/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1992 Keith Muller.4* Copyright (c) 1992, 19935* The Regents of the University of California. All rights reserved.6*7* This code is derived from software contributed to Berkeley by8* Keith Muller of the University of California, San Diego.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions and the following disclaimer.15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18* 3. Neither the name of the University nor the names of its contributors19* may be used to endorse or promote products derived from this software20* without specific prior written permission.21*22* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND23* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE24* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE25* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE26* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL27* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS28* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)29* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT30* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY31* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF32* SUCH DAMAGE.33*/3435#include <sys/types.h>36#include <sys/stat.h>37#include <sys/time.h>38#include <sys/resource.h>39#include <err.h>40#include <errno.h>41#include <fcntl.h>42#include <locale.h>43#include <paths.h>44#include <signal.h>45#include <stdio.h>46#include <stdlib.h>47#include <string.h>48#include "pax.h"49#include "extern.h"50static int gen_init(void);5152/*53* PAX main routines, general globals and some simple start up routines54*/5556/*57* Variables that can be accessed by any routine within pax58*/59int act = DEFOP; /* read/write/append/copy */60FSUB *frmt = NULL; /* archive format type */61int cflag; /* match all EXCEPT pattern/file */62int cwdfd; /* starting cwd */63int dflag; /* directory member match only */64int iflag; /* interactive file/archive rename */65int kflag; /* do not overwrite existing files */66int lflag; /* use hard links when possible */67int nflag; /* select first archive member match */68int tflag; /* restore access time after read */69int uflag; /* ignore older modification time files */70int vflag; /* produce verbose output */71int Dflag; /* same as uflag except for inode change time */72int Hflag; /* follow command line symlinks (write only) */73int Lflag; /* follow symlinks when writing */74int Oflag; /* limit to single volume */75int Xflag; /* archive files with same device id only */76int Yflag; /* same as Dflg except after name mode */77int Zflag; /* same as uflg except after name mode */78int vfpart; /* is partial verbose output in progress */79int patime = 1; /* preserve file access time */80int pmtime = 1; /* preserve file modification times */81int nodirs; /* do not create directories as needed */82int pmode; /* preserve file mode bits */83int pids; /* preserve file uid/gid */84int rmleadslash = 0; /* remove leading '/' from pathnames */85int exit_val; /* exit value */86int docrc; /* check/create file crc */87char *dirptr; /* destination dir in a copy */88const char *argv0; /* root of argv[0] */89sigset_t s_mask; /* signal mask for cleanup critical sect */90FILE *listf; /* file pointer to print file list to */91char *tempfile; /* tempfile to use for mkstemp(3) */92char *tempbase; /* basename of tempfile to use for mkstemp(3) */9394/*95* PAX - Portable Archive Interchange96*97* A utility to read, write, and write lists of the members of archive98* files and copy directory hierarchies. A variety of archive formats99* are supported (some are described in POSIX 1003.1 10.1):100*101* ustar - 10.1.1 extended tar interchange format102* cpio - 10.1.2 extended cpio interchange format103* tar - old BSD 4.3 tar format104* binary cpio - old cpio with binary header format105* sysVR4 cpio - with and without CRC106*107* This version is a superset of IEEE Std 1003.2b-d3108*109* Summary of Extensions to the IEEE Standard:110*111* 1 READ ENHANCEMENTS112* 1.1 Operations which read archives will continue to operate even when113* processing archives which may be damaged, truncated, or fail to meet114* format specs in several different ways. Damaged sections of archives115* are detected and avoided if possible. Attempts will be made to resync116* archive read operations even with badly damaged media.117* 1.2 Blocksize requirements are not strictly enforced on archive read.118* Tapes which have variable sized records can be read without errors.119* 1.3 The user can specify via the non-standard option flag -E if error120* resync operation should stop on a media error, try a specified number121* of times to correct, or try to correct forever.122* 1.4 Sparse files (lseek holes) stored on the archive (but stored with blocks123* of all zeros will be restored with holes appropriate for the target124* file system125* 1.5 The user is notified whenever something is found during archive126* read operations which violates spec (but the read will continue).127* 1.6 Multiple archive volumes can be read and may span over different128* archive devices129* 1.7 Rigidly restores all file attributes exactly as they are stored on the130* archive.131* 1.8 Modification change time ranges can be specified via multiple -T132* options. These allow a user to select files whose modification time133* lies within a specific time range.134* 1.9 Files can be selected based on owner (user name or uid) via one or more135* -U options.136* 1.10 Files can be selected based on group (group name or gid) via one o137* more -G options.138* 1.11 File modification time can be checked against existing file after139* name modification (-Z)140*141* 2 WRITE ENHANCEMENTS142* 2.1 Write operation will stop instead of allowing a user to create a flawed143* flawed archive (due to any problem).144* 2.2 Archives written by pax are forced to strictly conform to both the145* archive and pax the specific format specifications.146* 2.3 Blocking size and format is rigidly enforced on writes.147* 2.4 Formats which may exhibit header overflow problems (they have fields148* too small for large file systems, such as inode number storage), use149* routines designed to repair this problem. These techniques still150* conform to both pax and format specifications, but no longer truncate151* these fields. This removes any restrictions on using these archive152* formats on large file systems.153* 2.5 Multiple archive volumes can be written and may span over different154* archive devices155* 2.6 A archive volume record limit allows the user to specify the number156* of bytes stored on an archive volume. When reached the user is157* prompted for the next archive volume. This is specified with the158* non-standard -B flag. The limit is rounded up to the next blocksize.159* 2.7 All archive padding during write use zero filled sections. This makes160* it much easier to pull data out of flawed archive during read161* operations.162* 2.8 Access time reset with the -t applies to all file nodes (including163* directories).164* 2.9 Symbolic links can be followed with -L (optional in the spec).165* 2.10 Modification or inode change time ranges can be specified via166* multiple -T options. These allow a user to select files whose167* modification or inode change time lies within a specific time range.168* 2.11 Files can be selected based on owner (user name or uid) via one or more169* -U options.170* 2.12 Files can be selected based on group (group name or gid) via one o171* more -G options.172* 2.13 Symlinks which appear on the command line can be followed (without173* following other symlinks; -H flag)174*175* 3 COPY ENHANCEMENTS176* 3.1 Sparse files (lseek holes) can be copied without expanding the holes177* into zero filled blocks. The file copy is created with holes which are178* appropriate for the target file system179* 3.2 Access time as well as modification time on copied file trees can be180* preserved with the appropriate -p options.181* 3.3 Access time reset with the -t applies to all file nodes (including182* directories).183* 3.4 Symbolic links can be followed with -L (optional in the spec).184* 3.5 Modification or inode change time ranges can be specified via185* multiple -T options. These allow a user to select files whose186* modification or inode change time lies within a specific time range.187* 3.6 Files can be selected based on owner (user name or uid) via one or more188* -U options.189* 3.7 Files can be selected based on group (group name or gid) via one o190* more -G options.191* 3.8 Symlinks which appear on the command line can be followed (without192* following other symlinks; -H flag)193* 3.9 File inode change time can be checked against existing file before194* name modification (-D)195* 3.10 File inode change time can be checked against existing file after196* name modification (-Y)197* 3.11 File modification time can be checked against existing file after198* name modification (-Z)199*200* 4 GENERAL ENHANCEMENTS201* 4.1 Internal structure is designed to isolate format dependent and202* independent functions. Formats are selected via a format driver table.203* This encourages the addition of new archive formats by only having to204* write those routines which id, read and write the archive header.205*/206207/*208* main()209* parse options, set up and operate as specified by the user.210* any operational flaw will set exit_val to non-zero211* Return: 0 if ok, 1 otherwise212*/213214int215main(int argc, char *argv[])216{217const char *tmpdir;218size_t tdlen;219220(void) setlocale(LC_ALL, "");221listf = stderr;222/*223* Keep a reference to cwd, so we can always come back home.224*/225cwdfd = open(".", O_RDONLY | O_CLOEXEC);226if (cwdfd < 0) {227syswarn(0, errno, "Can't open current working directory.");228return(exit_val);229}230231/*232* Where should we put temporary files?233*/234if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')235tmpdir = _PATH_TMP;236tdlen = strlen(tmpdir);237while (tdlen > 0 && tmpdir[tdlen - 1] == '/')238tdlen--;239tempfile = malloc(tdlen + 1 + sizeof(_TFILE_BASE));240if (tempfile == NULL) {241paxwarn(1, "Cannot allocate memory for temp file name.");242return(exit_val);243}244if (tdlen)245memcpy(tempfile, tmpdir, tdlen);246tempbase = tempfile + tdlen;247*tempbase++ = '/';248249/*250* parse options, determine operational mode, general init251*/252options(argc, argv);253if ((gen_init() < 0) || (tty_init() < 0))254return(exit_val);255256/*257* select a primary operation mode258*/259switch (act) {260case EXTRACT:261extract();262break;263case ARCHIVE:264archive();265break;266case APPND:267if (gzip_program != NULL)268err(1, "can not gzip while appending");269append();270break;271case COPY:272copy();273break;274default:275case LIST:276list();277break;278}279return(exit_val);280}281282/*283* sig_cleanup()284* when interrupted we try to do whatever delayed processing we can.285* This is not critical, but we really ought to limit our damage when we286* are aborted by the user.287* Return:288* never....289*/290291void292sig_cleanup(int which_sig)293{294/*295* restore modes and times for any dirs we may have created296* or any dirs we may have read. Set vflag and vfpart so the user297* will clearly see the message on a line by itself.298*/299vflag = vfpart = 1;300if (which_sig == SIGXCPU)301paxwarn(0, "Cpu time limit reached, cleaning up.");302else303paxwarn(0, "Signal caught, cleaning up.");304305ar_close();306proc_dir();307if (tflag)308atdir_end();309exit(1);310}311312/*313* setup_sig()314* set a signal to be caught, but only if it isn't being ignored already315*/316317static int318setup_sig(int sig, const struct sigaction *n_hand)319{320struct sigaction o_hand;321322if (sigaction(sig, NULL, &o_hand) < 0)323return (-1);324325if (o_hand.sa_handler == SIG_IGN)326return (0);327328return (sigaction(sig, n_hand, NULL));329}330331/*332* gen_init()333* general setup routines. Not all are required, but they really help334* when dealing with a medium to large sized archives.335*/336337static int338gen_init(void)339{340struct rlimit reslimit;341struct sigaction n_hand;342343/*344* Really needed to handle large archives. We can run out of memory for345* internal tables really fast when we have a whole lot of files...346*/347if (getrlimit(RLIMIT_DATA , &reslimit) == 0){348reslimit.rlim_cur = reslimit.rlim_max;349(void)setrlimit(RLIMIT_DATA , &reslimit);350}351352/*353* should file size limits be waived? if the os limits us, this is354* needed if we want to write a large archive355*/356if (getrlimit(RLIMIT_FSIZE , &reslimit) == 0){357reslimit.rlim_cur = reslimit.rlim_max;358(void)setrlimit(RLIMIT_FSIZE , &reslimit);359}360361/*362* increase the size the stack can grow to363*/364if (getrlimit(RLIMIT_STACK , &reslimit) == 0){365reslimit.rlim_cur = reslimit.rlim_max;366(void)setrlimit(RLIMIT_STACK , &reslimit);367}368369/*370* not really needed, but doesn't hurt371*/372if (getrlimit(RLIMIT_RSS , &reslimit) == 0){373reslimit.rlim_cur = reslimit.rlim_max;374(void)setrlimit(RLIMIT_RSS , &reslimit);375}376377/*378* signal handling to reset stored directory times and modes. Since379* we deal with broken pipes via failed writes we ignore it. We also380* deal with any file size limit through failed writes. Cpu time381* limits are caught and a cleanup is forced.382*/383if ((sigemptyset(&s_mask) < 0) || (sigaddset(&s_mask, SIGTERM) < 0) ||384(sigaddset(&s_mask,SIGINT) < 0)||(sigaddset(&s_mask,SIGHUP) < 0) ||385(sigaddset(&s_mask,SIGPIPE) < 0)||(sigaddset(&s_mask,SIGQUIT)<0) ||386(sigaddset(&s_mask,SIGXCPU) < 0)||(sigaddset(&s_mask,SIGXFSZ)<0)) {387paxwarn(1, "Unable to set up signal mask");388return(-1);389}390memset(&n_hand, 0, sizeof n_hand);391n_hand.sa_mask = s_mask;392n_hand.sa_flags = 0;393n_hand.sa_handler = sig_cleanup;394395if (setup_sig(SIGHUP, &n_hand) ||396setup_sig(SIGTERM, &n_hand) ||397setup_sig(SIGINT, &n_hand) ||398setup_sig(SIGQUIT, &n_hand) ||399setup_sig(SIGXCPU, &n_hand))400goto out;401402n_hand.sa_handler = SIG_IGN;403if ((sigaction(SIGPIPE, &n_hand, NULL) < 0) ||404(sigaction(SIGXFSZ, &n_hand, NULL) < 0))405goto out;406return(0);407408out:409syswarn(1, errno, "Unable to set up signal handler");410return(-1);411}412413414