From 6f2ea93cf4d39dc17b5fff4bc84a55d6562c8cd4 Mon Sep 17 00:00:00 2001 From: kris Date: Tue, 8 May 2001 06:19:06 +0000 Subject: Sync up with OpenBSD. Too many changes to note, but the major features are: * Implement cpio compatibility mode when pax is invoked as cpio * Extend tar compatibility mode to cover many of the GNU tar single-letter options (bzip2 mode, aka -y/-j is not present in OpenBSD). When invoked as tar, pax is now full-featured enough for use by the ports collection to extract distfiles and create packages. * Many bug fixes to the operation of pax and the tar compatibility modes * Code fixes for things like correct string buffer termination. I tried to preserve existing FreeBSD fixes to this utility; please let me know if I have inadvertently spammed something. --- bin/pax/Makefile | 9 +- bin/pax/ar_io.c | 37 +-- bin/pax/ar_subs.c | 72 ++++-- bin/pax/buf_subs.c | 6 + bin/pax/cache.c | 6 +- bin/pax/cpio.1 | 295 ++++++++++++++++++++++++ bin/pax/extern.h | 20 +- bin/pax/file_subs.c | 63 +++++- bin/pax/ftree.c | 26 ++- bin/pax/ftree.h | 1 + bin/pax/gen_subs.c | 72 ++---- bin/pax/getoldopt.c | 71 ++++++ bin/pax/options.c | 631 ++++++++++++++++++++++++++++++++++++++++++++++------ bin/pax/pat_rep.c | 48 +++- bin/pax/pax.1 | 8 +- bin/pax/pax.c | 16 +- bin/pax/pax.h | 4 +- bin/pax/tables.c | 13 +- bin/pax/tar.1 | 293 ++++++++++++++++++++++++ bin/pax/tar.c | 78 ++++--- bin/pax/tty_subs.c | 2 + 21 files changed, 1562 insertions(+), 209 deletions(-) create mode 100644 bin/pax/cpio.1 create mode 100644 bin/pax/getoldopt.c create mode 100644 bin/pax/tar.1 diff --git a/bin/pax/Makefile b/bin/pax/Makefile index b1a4dcf..f142bfc 100644 --- a/bin/pax/Makefile +++ b/bin/pax/Makefile @@ -26,8 +26,11 @@ # Pax may not compile if this not (un)defined properly. PROG= pax -SRCS= ar_io.c ar_subs.c buf_subs.c cache.c cpio.c file_subs.c ftree.c\ - gen_subs.c options.c pat_rep.c pax.c sel_subs.c tables.c tar.c\ - tty_subs.c +SRCS= ar_io.c ar_subs.c buf_subs.c cache.c cpio.c file_subs.c ftree.c \ + gen_subs.c getoldopt.c options.c pat_rep.c pax.c sel_subs.c \ + tables.c tar.c tty_subs.c +#XXX NOTYET +#MAN= pax.1 tar.1 cpio.1 +#LINKS= ${BINDIR}/pax ${BINDIR}/tar ${BINDIR}/pax ${BINDIR}/cpio .include diff --git a/bin/pax/ar_io.c b/bin/pax/ar_io.c index ee4681b..12fe522 100644 --- a/bin/pax/ar_io.c +++ b/bin/pax/ar_io.c @@ -57,6 +57,7 @@ static const char rcsid[] = #include #include #include "pax.h" +#include "options.h" #include "extern.h" /* @@ -159,6 +160,9 @@ ar_open(name) if (arfd < 0) return(-1); + if (chdname != NULL) + if (chdir(chdname) != 0) + syswarn(1, errno, "Failed chdir to %s", chdname); /* * set up is based on device type */ @@ -307,18 +311,12 @@ void ar_close() #endif { - FILE *outf; if (arfd < 0) { did_io = io_ok = flcnt = 0; return; } - if (act == LIST) - outf = stdout; - else - outf = stderr; - /* * Close archive file. This may take a LONG while on tapes (we may be * forced to wait for the rewind to complete) so tell the user what is @@ -327,11 +325,11 @@ ar_close() */ if (vflag && (artyp == ISTAPE)) { if (vfpart) - (void)putc('\n', outf); - (void)fprintf(outf, + (void)putc('\n', listf); + (void)fprintf(listf, "%s: Waiting for tape drive close to complete...", argv0); - (void)fflush(outf); + (void)fflush(listf); } /* @@ -357,9 +355,9 @@ ar_close() (void)close(arfd); if (vflag && (artyp == ISTAPE)) { - (void)fputs("done.\n", outf); + (void)fputs("done.\n", listf); vfpart = 0; - (void)fflush(outf); + (void)fflush(listf); } arfd = -1; @@ -385,7 +383,7 @@ ar_close() * Print out a summary of I/O for this archive volume. */ if (vfpart) { - (void)putc('\n', outf); + (void)putc('\n', listf); vfpart = 0; } @@ -396,24 +394,27 @@ ar_close() */ if (frmt == NULL) { # ifdef NET2_STAT - (void)fprintf(outf, "%s: unknown format, %lu bytes skipped.\n", + (void)fprintf(listf, "%s: unknown format, %lu bytes skipped.\n", # else - (void)fprintf(outf, "%s: unknown format, %qu bytes skipped.\n", + (void)fprintf(listf, "%s: unknown format, %qu bytes skipped.\n", # endif argv0, rdcnt); - (void)fflush(outf); + (void)fflush(listf); flcnt = 0; return; } - (void)fprintf(outf, + if (strcmp(NM_CPIO, argv0) == 0) + (void)fprintf(listf, "%qu blocks\n", (rdcnt ? rdcnt : wrcnt) / 5120); + else if (strcmp(NM_TAR, argv0) != 0) + (void)fprintf(listf, # ifdef NET2_STAT "%s: %s vol %d, %lu files, %lu bytes read, %lu bytes written.\n", # else "%s: %s vol %d, %lu files, %qu bytes read, %qu bytes written.\n", # endif argv0, frmt->name, arvol-1, flcnt, rdcnt, wrcnt); - (void)fflush(outf); + (void)fflush(listf); flcnt = 0; } @@ -1184,7 +1185,7 @@ ar_next() if (sigprocmask(SIG_SETMASK, &o_mask, NULL) < 0) syswarn(0, errno, "Unable to restore signal mask"); - if (done || !wr_trail) + if (done || !wr_trail || strcmp(NM_TAR, argv0) == 0) return(-1); tty_prnt("\nATTENTION! %s archive volume change required.\n", argv0); diff --git a/bin/pax/ar_subs.c b/bin/pax/ar_subs.c index 4f15ffd..f783489 100644 --- a/bin/pax/ar_subs.c +++ b/bin/pax/ar_subs.c @@ -130,7 +130,7 @@ list() if ((res = mod_name(arcn)) < 0) break; if (res == 0) - ls_list(arcn, now); + ls_list(arcn, now, stdout); } /* @@ -171,6 +171,7 @@ extract() ARCHD archd; struct stat sb; int fd; + time_t now; arcn = &archd; /* @@ -189,6 +190,8 @@ extract() if (iflag && (name_start() < 0)) return; + now = time(NULL); + /* * step through each entry on the archive until the format read routine * says it is done @@ -276,11 +279,23 @@ extract() } if (vflag) { - (void)fputs(arcn->name, stderr); - vfpart = 1; + if (vflag > 1) + ls_list(arcn, now, listf); + else { + (void)fputs(arcn->name, listf); + vfpart = 1; + } } /* + * if required, chdir around. + */ + if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL)) + if (chdir(arcn->pat->chdname) != 0) + syswarn(1, errno, "Cannot chdir to %s", + arcn->pat->chdname); + + /* * all ok, extract this member based on type */ if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) { @@ -299,7 +314,7 @@ extract() purg_lnk(arcn); if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } continue; @@ -320,11 +335,19 @@ extract() res = (*frmt->rd_data)(arcn, fd, &cnt); file_close(arcn, fd); if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } if (!res) (void)rd_skip(cnt + arcn->pad); + + /* + * if required, chdir around. + */ + if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL)) + if (fchdir(cwdfd) != 0) + syswarn(1, errno, + "Can't fchdir to starting directory"); } /* @@ -361,6 +384,7 @@ wr_archive(arcn, is_app) off_t cnt; int (*wrf)(); int fd = -1; + time_t now; /* * if this format supports hard link storage, start up the database @@ -388,6 +412,8 @@ wr_archive(arcn, is_app) */ wr_one = is_app; + now = time(NULL); + /* * while there are files to archive, process them one at at time */ @@ -457,8 +483,12 @@ wr_archive(arcn, is_app) } if (vflag) { - (void)fputs(arcn->name, stderr); - vfpart = 1; + if (vflag > 1) + ls_list(arcn, now, listf); + else { + (void)fputs(arcn->name, listf); + vfpart = 1; + } } ++flcnt; @@ -477,7 +507,7 @@ wr_archive(arcn, is_app) * so we are done messing with this file */ if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } rdfile_close(arcn, &fd); @@ -495,7 +525,7 @@ wr_archive(arcn, is_app) res = (*frmt->wr_data)(arcn, fd, &cnt); rdfile_close(arcn, &fd); if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } if (res < 0) @@ -612,7 +642,7 @@ append() * reading the archive may take a long time. If verbose tell the user */ if (vflag) { - (void)fprintf(stderr, + (void)fprintf(listf, "%s: Reading archive to position at the end...", argv0); vfpart = 1; } @@ -674,7 +704,7 @@ append() * tell the user we are done reading. */ if (vflag && vfpart) { - (void)fputs("done.\n", stderr); + (void)fputs("done.\n", listf); vfpart = 0; } @@ -872,7 +902,7 @@ copy() } if (vflag) { - (void)fputs(arcn->name, stderr); + (void)fputs(arcn->name, listf); vfpart = 1; } ++flcnt; @@ -887,7 +917,7 @@ copy() res = chk_same(arcn); if (res <= 0) { if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } continue; @@ -907,7 +937,7 @@ copy() if (res < 0) purg_lnk(arcn); if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } continue; @@ -937,7 +967,7 @@ copy() rdfile_close(arcn, &fdsrc); if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } } @@ -988,6 +1018,7 @@ next_head(arcn) register int hsz; register int in_resync = 0; /* set when we are in resync mode */ int cnt = 0; /* counter for trailer function */ + int first = 1; /* on 1st read, EOF isn't premature. */ /* * set up initial conditions, we want a whole frmt->hsz block as we @@ -1006,6 +1037,17 @@ next_head(arcn) break; /* + * If we read 0 bytes (EOF) from an archive when we + * expect to find a header, we have stepped upon + * an archive without the customary block of zeroes + * end marker. It's just stupid to error out on + * them, so exit gracefully. + */ + if (first && ret == 0) + return(-1); + first = 0; + + /* * some kind of archive read problem, try to resync the * storage device, better give the user the bad news. */ diff --git a/bin/pax/buf_subs.c b/bin/pax/buf_subs.c index 6e42e52..d6c4ae9 100644 --- a/bin/pax/buf_subs.c +++ b/bin/pax/buf_subs.c @@ -47,6 +47,7 @@ static const char rcsid[] = #include #include #include +#include #include #include #include "pax.h" @@ -111,6 +112,11 @@ wr_start() wrblksz, BLKMULT); return(-1); } + if (wrblksz > MAXBLK_POSIX) { + paxwarn(0, "Write block size of %d larger than POSIX max %d, archive may not be portable", + wrblksz, MAXBLK_POSIX); + return(-1); + } /* * we only allow wrblksz to be used with all archive operations diff --git a/bin/pax/cache.c b/bin/pax/cache.c index 040e18b..f593dce 100644 --- a/bin/pax/cache.c +++ b/bin/pax/cache.c @@ -388,7 +388,8 @@ uid_name(name, uid) } if (ptr == NULL) - ptr = (UIDC *)malloc(sizeof(UIDC)); + ptr = usrtb[st_hash(name, namelen, UNM_SZ)] = + (UIDC *)malloc(sizeof(UIDC)); /* * no match, look it up, if no match store it as an invalid entry, @@ -457,7 +458,8 @@ gid_name(name, gid) ++gropn; } if (ptr == NULL) - ptr = (GIDC *)malloc(sizeof(GIDC)); + ptr = grptb[st_hash(name, namelen, GID_SZ)] = + (GIDC *)malloc(sizeof(GIDC)); /* * no match, look it up, if no match store it as an invalid entry, diff --git a/bin/pax/cpio.1 b/bin/pax/cpio.1 new file mode 100644 index 0000000..9bec498 --- /dev/null +++ b/bin/pax/cpio.1 @@ -0,0 +1,295 @@ +.\" +.\" Copyright (c) 1997 SigmaSoft, Th. Lockert +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by SigmaSoft, Th. Lockert. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" $OpenBSD: cpio.1,v 1.16 2001/05/01 17:58:01 aaron Exp $ +.\" +.Dd February 16, 1997 +.Dt CPIO 1 +.Os +.Sh NAME +.Nm cpio +.Nd copy file archives in and out +.Sh SYNOPSIS +.Nm cpio +.Fl o +.Op Fl aABcLvzZ +.Op Fl C Ar bytes +.Op Fl F Ar archive +.Op Fl H Ar format +.Op Fl O Ar archive +.Ar "< name-list" +.Op Ar "> archive" +.Nm cpio +.Fl i +.Op Fl bBcdfmrsStuvzZ6 +.Op Fl C Ar bytes +.Op Fl E Ar file +.Op Fl F Ar archive +.Op Fl H Ar format +.Op Fl I Ar archive +.Op Ar "pattern ..." +.Op Ar "< archive" +.Nm cpio +.Fl p +.Op Fl adlLmuv +.Ar destination-directory +.Ar "< name-list" +.Sh DESCRIPTION +The +.Nm +command copies files to and from a +.Nm +archive. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl o +Create an archive. +Reads the list of files to store in the +archive from standard input, and writes the archive on standard +output. +.Bl -tag -width Ds +.It Fl a +Reset the access times on files that have been copied to the +archive. +.It Fl A +Append to the specified archive. +.It Fl B +Set block size of output to 5120 bytes. +.It Fl c +Use ASCII format for +.Nm +header for portability. +.It Fl C Ar bytes +Set the block size of output to +.Ar bytes . +.It Fl F Ar archive +.It Fl O Ar archive +Use the specified file name as the archive to write to. +.It Fl H Ar format +Write the archive in the specified format. +Recognized formats are: +.Pp +.Bl -tag -width sv4cpio -compact +.It Ar bcpio +Old binary +.Nm +format. +.It Ar cpio +Old octal character +.Nm +format. +.It Ar sv4cpio +SVR4 hex +.Nm +format. +.It Ar tar +Old tar format. +.It Ar ustar +POSIX ustar format. +.El +.It Fl L +Follow symbolic links. +.It Fl v +Be verbose about operations. +List filenames as they are written to the archive. +.It Fl z +Compress archive using +.Xr gzip 1 +format. +.It Fl Z +Compress archive using +.Xr compress 1 +format. +.El +.It Fl i +Restore files from an archive. +Reads the archive file from +standard input and extracts files matching the +.Ar patterns +that were specified on the command line. +.Bl -tag -width Ds +.It Fl b +Do byte and word swapping after reading in data from the +archive, for restoring archives created on systems with +a different byte order. +.It Fl B +Set the block size of the archive being read to 5120 bytes. +.It Fl c +Expect the archive headers to be in ASCII format. +.It Fl C Ar bytes +Read archive written with a block size of +.Ar bytes . +.It Fl d +Create any intermediate directories as needed during +restore. +.It Fl E Ar file +Read list of file name patterns to extract or list from +.Ar file . +.It Fl f +Restore all files except those matching the +.Ar patterns +given on the command line. +.It Fl F Ar archive +.It Fl I Ar archive +Use the specified file as the input for the archive. +.It Fl H Ar format +Read an archive of the specified format. +Recognized formats are: +.Pp +.Bl -tag -width sv4cpio -compact +.It Ar bcpio +Old binary +.Nm +format. +.It Ar cpio +Old octal character +.Nm +format. +.It Ar sv4cpio +SVR4 hex +.Nm +format. +.It Ar tar +Old tar format. +.It Ar ustar +POSIX ustar format. +.El +.It Fl m +Restore modification times on files. +.It Fl r +Rename restored files interactively. +.It Fl s +Swap bytes after reading data from the archive. +.It Fl S +Swap words after reading data from the archive. +.It Fl t +Only list the contents of the archive, no files or +directories will be created. +.It Fl u +Overwrite files even when the file in the archive is +older than the one that will be overwritten. +.It Fl v +Be verbose about operations. +List filenames as they are copied in from the archive. +.It Fl z +Uncompress archive using +.Xr gzip 1 +format. +.It Fl Z +Uncompress archive using +.Xr compress 1 +format. +.It Fl 6 +Process old-style +.Nm +format archives. +.El +.It Fl p +Copy files from one location to another in a single pass. +The list of files to copy are read from standard input and +written out to a directory relative to the specified +.Ar directory +argument. +.Bl -tag -width Ds +.It Fl a +Reset the access times on files that have been copied. +.It Fl d +Create any intermediate directories as needed to write +the files at the new location. +.It Fl l +When possible, link files rather than creating an +extra copy. +.It Fl L +Follow symbolic links. +.It Fl m +Restore modification times on files. +.It Fl u +Overwrite files even when the original file being copied is +older than the one that will be overwritten. +.It Fl v +Be verbose about operations. +List filenames as they are copied. +.El +.El +.Sh ERRORS +.Nm +will exit with one of the following values: +.Bl -tag -width 2n +.It 0 +All files were processed successfully. +.It 1 +An error occurred. +.El +.Pp +Whenever +.Nm +cannot create a file or a link when extracting an archive or cannot +find a file while writing an archive, or cannot preserve the user +ID, group ID, file mode, or access and modification times when the +.Fl p +option is specified, a diagnostic message is written to standard +error and a non-zero exit value will be returned, but processing +will continue. +In the case where +.Nm +cannot create a link to a file, +.Nm +will not create a second copy of the file. +.Pp +If the extraction of a file from an archive is prematurely terminated +by a signal or error, +.Nm +may have only partially extracted the file the user wanted. +Additionally, the file modes of extracted files and directories may +have incorrect file bits, and the modification and access times may +be wrong. +.Pp +If the creation of an archive is prematurely terminated by a signal +or error, +.Nm +may have only partially created the archive which may violate the +specific archive format specification. +.Sh ENVIRONMENT +.Bl -tag -width Fl +.It Ev TMPDIR +Path in which to store temporary files. +.El +.Sh SEE ALSO +.Xr pax 1 , +.Xr tar 1 +.Sh AUTHORS +Keith Muller at the University of California, San Diego. +.Sh BUGS +The +.Fl s +and +.Fl S +options are currently not implemented. diff --git a/bin/pax/extern.h b/bin/pax/extern.h index 9f4097c..dd1d6d5 100644 --- a/bin/pax/extern.h +++ b/bin/pax/extern.h @@ -146,6 +146,7 @@ int unlnk_exist __P((register char *, register int)); int chk_path __P((register char *, uid_t, gid_t)); void set_ftime __P((char *fnm, time_t mtime, time_t atime, int frc)); int set_ids __P((char *, uid_t, gid_t)); +int set_lids __P((char *, uid_t, gid_t)); void set_pmode __P((char *, mode_t)); int file_write __P((int, char *, register int, int *, int *, int, char *)); void file_flush __P((int, char *, int)); @@ -156,7 +157,7 @@ int set_crc __P((register ARCHD *, register int)); * ftree.c */ int ftree_start __P((void)); -int ftree_add __P((register char *)); +int ftree_add __P((register char *, int)); void ftree_sel __P((register ARCHD *)); void ftree_chk __P((void)); int next_file __P((register ARCHD *)); @@ -164,9 +165,8 @@ int next_file __P((register ARCHD *)); /* * gen_subs.c */ -void ls_list __P((register ARCHD *, time_t)); +void ls_list __P((register ARCHD *, time_t, FILE *)); void ls_tty __P((register ARCHD *)); -void zf_strncpy __P((register char *, register char *, int)); int l_strncpy __P((register char *, register char *, int)); u_long asc_ul __P((register char *, int, register int)); int ul_asc __P((u_long, register char *, register int, register int)); @@ -176,6 +176,11 @@ int uqd_asc __P((u_quad_t, register char *, register int, register int)); #endif /* + * getoldopt.c + */ +int getoldopt __P((int, char **, char *)); + +/* * options.c */ extern FSUB fsub[]; @@ -184,12 +189,13 @@ void options __P((register int, register char **)); OPLIST * opt_next __P((void)); int opt_add __P((register char *)); int bad_opt __P((void)); +char *chdname; /* * pat_rep.c */ int rep_add __P((register char *)); -int pat_add __P((char *)); +int pat_add __P((char *, char *)); void pat_chk __P((void)); int pat_sel __P((register ARCHD *)); int pat_match __P((register ARCHD *)); @@ -202,6 +208,7 @@ int set_dest __P((register ARCHD *, char *, int)); extern int act; extern FSUB *frmt; extern int cflag; +extern int cwdfd; extern int dflag; extern int iflag; extern int kflag; @@ -219,12 +226,15 @@ extern int Zflag; extern int vfpart; extern int patime; extern int pmtime; +extern int nodirs; extern int pmode; extern int pids; +extern int rmleadslash; extern int exit_val; extern int docrc; extern char *dirptr; extern char *argv0; +extern FILE *listf; extern char *tempfile; extern char *tempbase; @@ -250,7 +260,7 @@ int ftime_start __P((void)); int chk_ftime __P((register ARCHD *)); int name_start __P((void)); int add_name __P((register char *, int, char *)); -void sub_name __P((register char *, int *)); +void sub_name __P((register char *, int *, size_t)); int dev_start __P((void)); int add_dev __P((register ARCHD *)); int map_dev __P((register ARCHD *, u_long, u_long)); diff --git a/bin/pax/file_subs.c b/bin/pax/file_subs.c index b3126f5..a13238e 100644 --- a/bin/pax/file_subs.c +++ b/bin/pax/file_subs.c @@ -54,6 +54,7 @@ static const char rcsid[] = #include #include #include "pax.h" +#include "options.h" #include "extern.h" static int @@ -122,7 +123,7 @@ file_creat(arcn) file_mode)) >= 0) break; oerrno = errno; - if (chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) { + if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) { syswarn(1, oerrno, "Unable to create %s", arcn->name); return(-1); } @@ -356,7 +357,7 @@ mk_link(to, to_sb, from, ign) if (link(to, from) == 0) break; oerrno = errno; - if (chk_path(from, to_sb->st_uid, to_sb->st_gid) == 0) + if (!nodirs && chk_path(from, to_sb->st_uid, to_sb->st_gid) == 0) continue; if (!ign) { syswarn(1, oerrno, "Could not link to %s from %s", to, @@ -431,8 +432,7 @@ node_creat(arcn) arcn->name); return(-1); case PAX_SLK: - if ((res = symlink(arcn->ln_name, arcn->name)) == 0) - return(0); + res = symlink(arcn->ln_name, arcn->name); break; case PAX_CTG: case PAX_HLK: @@ -465,7 +465,7 @@ node_creat(arcn) if (++pass <= 1) continue; - if (chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) { + if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) { syswarn(1, oerrno, "Could not create: %s", arcn->name); return(-1); } @@ -475,11 +475,19 @@ node_creat(arcn) * we were able to create the node. set uid/gid, modes and times */ if (pids) - res = set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid); + res = ((arcn->type == PAX_SLK) ? + set_lids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid) : + set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid)); else res = 0; /* + * symlinks are done now. + */ + if (arcn->type == PAX_SLK) + return(0); + + /* * IMPORTANT SECURITY NOTE: * if not preserving mode or we cannot set uid/gid, then PROHIBIT any * set uid/gid bits @@ -489,7 +497,7 @@ node_creat(arcn) if (pmode) set_pmode(arcn->name, arcn->sb.st_mode); - if (arcn->type == PAX_DIR) { + if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) { /* * Dirs must be processed again at end of extract to set times * and modes to agree with those stored in the archive. However @@ -752,7 +760,46 @@ set_ids(fnm, uid, gid) #endif { if (chown(fnm, uid, gid) < 0) { - syswarn(1, errno, "Unable to set file uid/gid of %s", fnm); + /* + * ignore EPERM unless in verbose mode or being run by root. + * if running as pax, POSIX requires a warning. + */ + if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag || + geteuid() == 0) + syswarn(1, errno, "Unable to set file uid/gid of %s", + fnm); + return(-1); + } + return(0); +} + +/* + * set_lids() + * set the uid and gid of a file system node + * Return: + * 0 when set, -1 on failure + */ + +#ifdef __STDC__ +int +set_lids(char *fnm, uid_t uid, gid_t gid) +#else +int +set_lids(fnm, uid, gid) + char *fnm; + uid_t uid; + gid_t gid; +#endif +{ + if (lchown(fnm, uid, gid) < 0) { + /* + * ignore EPERM unless in verbose mode or being run by root. + * if running as pax, POSIX requires a warning. + */ + if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag || + geteuid() == 0) + syswarn(1, errno, "Unable to set file uid/gid of %s", + fnm); return(-1); } return(0); diff --git a/bin/pax/ftree.c b/bin/pax/ftree.c index 772404b..d7d6046 100644 --- a/bin/pax/ftree.c +++ b/bin/pax/ftree.c @@ -152,11 +152,12 @@ ftree_start() #ifdef __STDC__ int -ftree_add(register char *str) +ftree_add(register char *str, int chflg) #else int -ftree_add(str) +ftree_add(str, chflg) register char *str; + int chflg; #endif { register FTREE *ft; @@ -184,6 +185,7 @@ ftree_add(str) str[len] = '\0'; ft->fname = str; ft->refcnt = 0; + ft->chflg = chflg; ft->fow = NULL; if (fthead == NULL) { fttail = fthead = ft; @@ -261,7 +263,7 @@ ftree_chk() * that never had a match */ for (ft = fthead; ft != NULL; ft = ft->fow) { - if (ft->refcnt > 0) + if ((ft->refcnt > 0) || ft->chflg) continue; if (wban == 0) { paxwarn(1,"WARNING! These file names were not selected:"); @@ -321,7 +323,21 @@ ftree_arg() ftcur = fthead; else if ((ftcur = ftcur->fow) == NULL) return(-1); - farray[0] = ftcur->fname; + if (ftcur->chflg) { + /* First fchdir() back... */ + if (fchdir(cwdfd) < 0) { + syswarn(1, errno, + "Can't fchdir to starting directory"); + return(-1); + } + if (chdir(ftcur->fname) < 0) { + syswarn(1, errno, "Can't chdir to %s", + ftcur->fname); + return(-1); + } + continue; + } else + farray[0] = ftcur->fname; } /* @@ -538,7 +554,7 @@ next_file(arcn) /* * copy file name, set file name length */ - arcn->nlen = l_strncpy(arcn->name, ftent->fts_path, PAXPATHLEN+1); + arcn->nlen = l_strncpy(arcn->name, ftent->fts_path, sizeof(arcn->name) - 1); arcn->name[arcn->nlen] = '\0'; arcn->org_name = ftent->fts_path; return(0); diff --git a/bin/pax/ftree.h b/bin/pax/ftree.h index e5c9749..6ff282b 100644 --- a/bin/pax/ftree.h +++ b/bin/pax/ftree.h @@ -47,5 +47,6 @@ typedef struct ftree { char *fname; /* file tree name */ int refcnt; /* has tree had a selected file? */ + int chflg; /* change directory flag */ struct ftree *fow; /* pointer to next entry on list */ } FTREE; diff --git a/bin/pax/gen_subs.c b/bin/pax/gen_subs.c index a22bd96..3ddab8c 100644 --- a/bin/pax/gen_subs.c +++ b/bin/pax/gen_subs.c @@ -83,12 +83,13 @@ static int d_first = -1; #ifdef __STDC__ void -ls_list(register ARCHD *arcn, time_t now) +ls_list(register ARCHD *arcn, time_t now, FILE *fp) #else void -ls_list(arcn, now) +ls_list(arcn, now, fp) register ARCHD *arcn; time_t now; + FILE *fp; #endif { register struct stat *sbp; @@ -100,8 +101,8 @@ ls_list(arcn, now) * if not verbose, just print the file name */ if (!vflag) { - (void)printf("%s\n", arcn->name); - (void)fflush(stdout); + (void)fprintf(fp, "%s\n", arcn->name); + (void)fflush(fp); return; } @@ -126,8 +127,8 @@ ls_list(arcn, now) */ if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0) f_date[0] = '\0'; - (void)printf("%s%2u %-*s %-*s ", f_mode, sbp->st_nlink, UT_NAMESIZE, - name_uid(sbp->st_uid, 1), UT_GRPSIZE, + (void)fprintf(fp, "%s%2u %-*s %-*s ", f_mode, sbp->st_nlink, + UT_NAMESIZE, name_uid(sbp->st_uid, 1), UT_GRPSIZE, name_gid(sbp->st_gid, 1)); /* @@ -135,31 +136,31 @@ ls_list(arcn, now) */ if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK)) # ifdef NET2_STAT - (void)printf("%4u,%4u ", MAJOR(sbp->st_rdev), + (void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev), MINOR(sbp->st_rdev)); # else - (void)printf("%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev), + (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev), (unsigned long)MINOR(sbp->st_rdev)); # endif else { # ifdef NET2_STAT - (void)printf("%9lu ", sbp->st_size); + (void)fprintf(fp, "%9lu ", sbp->st_size); # else - (void)printf("%9qu ", sbp->st_size); + (void)fprintf(fp, "%9qu ", sbp->st_size); # endif } /* * print name and link info for hard and soft links */ - (void)printf("%s %s", f_date, arcn->name); + (void)fprintf(fp, "%s %s", f_date, arcn->name); if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) - (void)printf(" == %s\n", arcn->ln_name); + (void)fprintf(fp, " == %s\n", arcn->ln_name); else if (arcn->type == PAX_SLK) - (void)printf(" => %s\n", arcn->ln_name); + (void)fprintf(fp, " => %s\n", arcn->ln_name); else - (void)putchar('\n'); - (void)fflush(stdout); + (void)putc('\n', fp); + (void)fflush(fp); return; } @@ -201,40 +202,12 @@ ls_tty(arcn) } /* - * zf_strncpy() - * copy src to dest up to len chars (stopping at first '\0'), when src is - * shorter than len, pads to len with '\0'. big performance win (and - * a lot easier to code) over strncpy(), then a strlen() then a - * memset(). (or doing the memset() first). - */ - -#ifdef __STDC__ -void -zf_strncpy(register char *dest, register char *src, int len) -#else -void -zf_strncpy(dest, src, len) - register char *dest; - register char *src; - int len; -#endif -{ - register char *stop; - - stop = dest + len; - while ((dest < stop) && (*src != '\0')) - *dest++ = *src++; - while (dest < stop) - *dest++ = '\0'; - return; -} - -/* * l_strncpy() - * copy src to dest up to len chars (stopping at first '\0') + * copy src to dest up to len chars (stopping at first '\0'). + * when src is shorter than len, pads to len with '\0'. * Return: * number of chars copied. (Note this is a real performance win over - * doing a strncpy() then a strlen() + * doing a strncpy(), a strlen(), and then a possible memset()) */ #ifdef __STDC__ @@ -255,9 +228,10 @@ l_strncpy(dest, src, len) start = dest; while ((dest < stop) && (*src != '\0')) *dest++ = *src++; - if (dest < stop) - *dest = '\0'; - return(dest - start); + len = dest - start; + while (dest < stop) + *dest++ = '\0'; + return(len); } /* diff --git a/bin/pax/getoldopt.c b/bin/pax/getoldopt.c new file mode 100644 index 0000000..37c235b --- /dev/null +++ b/bin/pax/getoldopt.c @@ -0,0 +1,71 @@ +/* $OpenBSD: getoldopt.c,v 1.4 2000/01/22 20:24:51 deraadt Exp $ */ +/* $NetBSD: getoldopt.c,v 1.3 1995/03/21 09:07:28 cgd Exp $ */ + +/* + * Plug-compatible replacement for getopt() for parsing tar-like + * arguments. If the first argument begins with "-", it uses getopt; + * otherwise, it uses the old rules used by tar, dump, and ps. + * + * Written 25 August 1985 by John Gilmore (ihnp4!hoptoad!gnu) and placed + * in the Pubic Domain for your edification and enjoyment. + */ + +#ifndef lint +static const char rcsid[] = "$FreeBSD$"; +#endif /* not lint */ + +#include +#include +#include + +int +getoldopt(argc, argv, optstring) + int argc; + char **argv; + char *optstring; +{ + static char *key; /* Points to next keyletter */ + static char use_getopt; /* !=0 if argv[1][0] was '-' */ + char c; + char *place; + + optarg = NULL; + + if (key == NULL) { /* First time */ + if (argc < 2) return EOF; + key = argv[1]; + if (*key == '-') + use_getopt++; + else + optind = 2; + } + + if (use_getopt) + return getopt(argc, argv, optstring); + + c = *key++; + if (c == '\0') { + key--; + return EOF; + } + place = strchr(optstring, c); + + if (place == NULL || c == ':') { + fprintf(stderr, "%s: unknown option %c\n", argv[0], c); + return('?'); + } + + place++; + if (*place == ':') { + if (optind < argc) { + optarg = argv[optind]; + optind++; + } else { + fprintf(stderr, "%s: %c argument missing\n", + argv[0], c); + return('?'); + } + } + + return(c); +} diff --git a/bin/pax/options.c b/bin/pax/options.c index cbdcb11..5ce8eb2 100644 --- a/bin/pax/options.c +++ b/bin/pax/options.c @@ -1,4 +1,4 @@ -/*- +/* * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. @@ -48,9 +48,11 @@ static const char rcsid[] = #include #include #include +#include #include #include #include +#include #include "pax.h" #include "options.h" #include "cpio.h" @@ -69,17 +71,23 @@ static int no_op __P((void)); static void printflg __P((unsigned int)); static int c_frmt __P((const void *, const void *)); static off_t str_offt __P((char *)); +static char *getline __P((FILE *fp)); static void pax_options __P((register int, register char **)); static void pax_usage __P((void)); static void tar_options __P((register int, register char **)); static void tar_usage __P((void)); -#ifdef notdef static void cpio_options __P((register int, register char **)); static void cpio_usage __P((void)); -#endif + +/* errors from getline */ +#define GETLINE_FILE_CORRUPT 1 +#define GETLINE_OUT_OF_MEM 2 +static int getline_error; + #define GZIP_CMD "gzip" /* command to run as gzip */ #define COMPRESS_CMD "compress" /* command to run as compress */ +#define BZIP2_CMD "bzip2" /* command to run as gzip */ /* * Format specific routine table - MUST BE IN SORTED ORDER BY NAME @@ -121,7 +129,11 @@ FSUB fsub[] = { ustar_rd, tar_endrd, ustar_stwr, ustar_wr, tar_endwr, tar_trail, rd_wrfile, wr_rdfile, bad_opt}, }; -#define F_TAR 4 /* format when called as tar */ +#define F_OCPIO 0 /* format when called as cpio -6 */ +#define F_ACPIO 1 /* format when called as cpio -c */ +#define F_CPIO 3 /* format when called as cpio */ +#define F_OTAR 4 /* format when called as tar -o */ +#define F_TAR 5 /* format when called as tar */ #define DEFLT 5 /* default write format from list above */ /* @@ -158,10 +170,8 @@ options(argc, argv) if (strcmp(NM_TAR, argv0) == 0) return(tar_options(argc, argv)); -# ifdef notdef else if (strcmp(NM_CPIO, argv0) == 0) return(cpio_options(argc, argv)); -# endif /* * assume pax as the default */ @@ -368,7 +378,7 @@ pax_options(argc, argv) */ tmp.name = optarg; if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub, - sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt))) { + sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL) { flg |= XF; break; } @@ -500,7 +510,6 @@ pax_options(argc, argv) Zflag = 1; flg |= CZF; break; - case '?': default: pax_usage(); break; @@ -514,6 +523,7 @@ pax_options(argc, argv) */ if (ISLIST(flg)) { act = LIST; + listf = stdout; bflg = flg & BDLIST; } else if (ISEXTRACT(flg)) { act = EXTRACT; @@ -549,7 +559,7 @@ pax_options(argc, argv) case LIST: case EXTRACT: for (; optind < argc; optind++) - if (pat_add(argv[optind]) < 0) + if (pat_add(argv[optind], NULL) < 0) pax_usage(); break; case COPY: @@ -563,7 +573,7 @@ pax_options(argc, argv) case ARCHIVE: case APPND: for (; optind < argc; optind++) - if (ftree_add(argv[optind]) < 0) + if (ftree_add(argv[optind], 0) < 0) pax_usage(); /* * no read errors allowed on updates/append operation! @@ -590,35 +600,37 @@ tar_options(argc, argv) register char **argv; #endif { - register char *cp; + register int c; int fstdin = 0; + int Oflag = 0; + int nincfiles = 0; + int incfiles_max = 0; + struct incfile { + char *file; + char *dir; + }; + struct incfile *incfiles = NULL; + + /* + * Set default values. + */ + rmleadslash = 1; - if (argc < 2) - tar_usage(); /* * process option flags */ - ++argv; - for (cp = *argv++; *cp != '\0'; ++cp) { - switch (*cp) { - case '-': - /* - * skip over - - */ - break; + while ((c = getoldopt(argc, argv, + "b:cef:hjmopqruts:vwxyzBC:HI:LOPXZ014578")) != -1) { + switch(c) { case 'b': /* - * specify blocksize + * specify blocksize in 512-byte blocks */ - if (*argv == NULL) { - paxwarn(1,"blocksize must be specified with 'b'"); - tar_usage(); - } - if ((wrblksz = (int)str_offt(*argv)) <= 0) { - paxwarn(1, "Invalid block size %s", *argv); + if ((wrblksz = (int)str_offt(optarg)) <= 0) { + paxwarn(1, "Invalid block size %s", optarg); tar_usage(); } - ++argv; + wrblksz *= 512; /* XXX - check for int oflow */ break; case 'c': /* @@ -636,21 +648,29 @@ tar_options(argc, argv) /* * filename where the archive is stored */ - if (*argv == NULL) { - paxwarn(1, "filename must be specified with 'f'"); - tar_usage(); - } - if ((argv[0][0] == '-') && (argv[0][1]== '\0')) { + if ((optarg[0] == '-') && (optarg[1]== '\0')) { /* * treat a - as stdin */ - ++argv; - ++fstdin; - arcname = (char *)0; + fstdin = 1; + arcname = NULL; break; } fstdin = 0; - arcname = *argv++; + arcname = optarg; + break; + case 'h': + /* + * follow symlinks + */ + Lflag = 1; + break; + case 'j': + case 'y': + /* + * use bzip2. Non standard option. + */ + gzip_program = BZIP2_CMD; break; case 'm': /* @@ -661,16 +681,21 @@ tar_options(argc, argv) case 'o': if (opt_add("write_opt=nodir") < 0) tar_usage(); + case 'O': + Oflag = 1; break; case 'p': /* - * preserve user id, group id, file - * mode, access/modification times + * preserve uid/gid and file mode, regardless of umask */ - pids = 1; pmode = 1; - patime = 1; - pmtime = 1; + pids = 1; + break; + case 'q': + /* + * select first match for a pattern only + */ + nflag = 1; break; case 'r': case 'u': @@ -679,6 +704,15 @@ tar_options(argc, argv) */ act = APPND; break; + case 's': + /* + * file name substitution name pattern + */ + if (rep_add(optarg) < 0) { + tar_usage(); + break; + } + break; case 't': /* * list contents of the tape @@ -689,7 +723,7 @@ tar_options(argc, argv) /* * verbose operation mode */ - vflag = 1; + vflag++; break; case 'w': /* @@ -699,9 +733,11 @@ tar_options(argc, argv) break; case 'x': /* - * write an archive + * extract an archive, preserving mode, + * and mtime if possible. */ act = EXTRACT; + pmtime = 1; break; case 'z': /* @@ -714,12 +750,29 @@ tar_options(argc, argv) * Nothing to do here, this is pax default */ break; + case 'C': + chdname = optarg; + break; case 'H': /* * follow command line symlinks only */ Hflag = 1; break; + case 'I': + if (++nincfiles > incfiles_max) { + incfiles_max = nincfiles + 3; + incfiles = realloc(incfiles, + sizeof(*incfiles) * incfiles_max); + if (incfiles == NULL) { + paxwarn(0, "Unable to allocate space " + "for option list"); + exit(1); + } + } + incfiles[nincfiles - 1].file = optarg; + incfiles[nincfiles - 1].dir = chdname; + break; case 'L': /* * follow symlinks @@ -728,9 +781,9 @@ tar_options(argc, argv) break; case 'P': /* - * do not follow symlinks + * do not remove leading '/' from pathnames */ - Lflag = 0; + rmleadslash = 0; break; case 'X': /* @@ -767,12 +820,29 @@ tar_options(argc, argv) break; } } + argc -= optind; + argv += optind; + + /* Traditional tar behaviour (pax uses stderr unless in list mode) */ + if (fstdin == 1 && act == ARCHIVE) + listf = stderr; + else + listf = stdout; + + /* Traditional tar behaviour (pax wants to read file list from stdin) */ + if ((act == ARCHIVE || act == APPND) && argc == 0 && nincfiles == 0) + exit(0); /* * if we are writing (ARCHIVE) specify tar, otherwise run like pax + * (unless -o specified) */ - if (act == ARCHIVE) - frmt = &(fsub[F_TAR]); + if (act == ARCHIVE || act == APPND) + frmt = &(fsub[Oflag ? F_OTAR : F_TAR]); + else if (Oflag) { + paxwarn(1, "The -O/-o options are only valid when writing an archive"); + tar_usage(); /* only valid when writing */ + } /* * process the args as they are interpreted by the operation mode @@ -781,15 +851,132 @@ tar_options(argc, argv) case LIST: case EXTRACT: default: - while (*argv != NULL) - if (pat_add(*argv++) < 0) - tar_usage(); + { + int sawpat = 0; + char *file, *dir = NULL; + + while (nincfiles || *argv != NULL) { + /* + * If we queued up any include files, + * pull them in now. Otherwise, check + * for -I and -C positional flags. + * Anything else must be a file to + * extract. + */ + if (nincfiles) { + file = incfiles->file; + dir = incfiles->dir; + incfiles++; + nincfiles--; + } else if (strcmp(*argv, "-I") == 0) { + if (*++argv == NULL) + break; + file = *argv++; + dir = chdname; + } else + file = NULL; + if (file != NULL) { + FILE *fp; + char *str; + + if (strcmp(file, "-") == 0) + fp = stdin; + else if ((fp = fopen(file, "r")) == NULL) { + paxwarn(1, "Unable to open file '%s' for read", file); + tar_usage(); + } + while ((str = getline(fp)) != NULL) { + if (pat_add(str, dir) < 0) + tar_usage(); + sawpat = 1; + } + if (strcmp(file, "-") != 0) + fclose(fp); + if (getline_error) { + paxwarn(1, "Problem with file '%s'", file); + tar_usage(); + } + } else if (strcmp(*argv, "-C") == 0) { + if (*++argv == NULL) + break; + chdname = *argv++; + } else if (pat_add(*argv++, chdname) < 0) + tar_usage(); + else + sawpat = 1; + } + /* + * if patterns were added, we are doing chdir() + * on a file-by-file basis, else, just one + * global chdir (if any) after opening input. + */ + if (sawpat > 0) + chdname = NULL; + } break; case ARCHIVE: case APPND: - while (*argv != NULL) - if (ftree_add(*argv++) < 0) + if (chdname != NULL) { /* initial chdir() */ + if (ftree_add(chdname, 1) < 0) + tar_usage(); + } + + while (nincfiles || *argv != NULL) { + char *file, *dir = NULL; + + /* + * If we queued up any include files, pull them in + * now. Otherwise, check for -I and -C positional + * flags. Anything else must be a file to include + * in the archive. + */ + if (nincfiles) { + file = incfiles->file; + dir = incfiles->dir; + incfiles++; + nincfiles--; + } else if (strcmp(*argv, "-I") == 0) { + if (*++argv == NULL) + break; + file = *argv++; + dir = NULL; + } else + file = NULL; + if (file != NULL) { + FILE *fp; + char *str; + + /* Set directory if needed */ + if (dir) { + if (ftree_add(dir, 1) < 0) + tar_usage(); + } + + if (strcmp(file, "-") == 0) + fp = stdin; + else if ((fp = fopen(file, "r")) == NULL) { + paxwarn(1, "Unable to open file '%s' for read", file); + tar_usage(); + } + while ((str = getline(fp)) != NULL) { + if (ftree_add(str, 0) < 0) + tar_usage(); + } + if (strcmp(file, "-") != 0) + fclose(fp); + if (getline_error) { + paxwarn(1, "Problem with file '%s'", + file); + tar_usage(); + } + } else if (strcmp(*argv, "-C") == 0) { + if (*++argv == NULL) + break; + if (ftree_add(*argv++, 1) < 0) + tar_usage(); + } else if (ftree_add(*argv++, 0) < 0) tar_usage(); + } /* * no read errors allowed on updates/append operation! */ @@ -799,11 +986,43 @@ tar_options(argc, argv) if (!fstdin && ((arcname == NULL) || (*arcname == '\0'))) { arcname = getenv("TAPE"); if ((arcname == NULL) || (*arcname == '\0')) - arcname = DEV_8; + arcname = _PATH_DEFTAPE; } } -#ifdef notdef +int +mkpath(path) + char *path; +{ + struct stat sb; + register char *slash; + int done = 0; + + slash = path; + + while (!done) { + slash += strspn(slash, "/"); + slash += strcspn(slash, "/"); + + done = (*slash == '\0'); + *slash = '\0'; + + if (stat(path, &sb)) { + if (errno != ENOENT || mkdir(path, 0777)) { + paxwarn(1, "%s", path); + return (-1); + } + } else if (!S_ISDIR(sb.st_mode)) { + syswarn(1, ENOTDIR, "%s", path); + return (-1); + } + + if (!done) + *slash = '/'; + } + + return (0); +} /* * cpio_options() * look at the user specified flags. set globals as required and check if @@ -820,8 +1039,257 @@ cpio_options(argc, argv) register char **argv; #endif { + register int c, i; + char *str; + FSUB tmp; + FILE *fp; + + kflag = 1; + pids = 1; + pmode = 1; + pmtime = 0; + arcname = NULL; + dflag = 1; + act = -1; + nodirs = 1; + while ((c=getopt(argc,argv,"abcdfiklmoprstuvzABC:E:F:H:I:LO:SZ6")) != -1) + switch (c) { + case 'a': + /* + * preserve access time on files read + */ + tflag = 1; + break; + case 'b': + /* + * swap bytes and half-words when reading data + */ + break; + case 'c': + /* + * ASCII cpio header + */ + frmt = &(fsub[F_ACPIO]); + break; + case 'd': + /* + * create directories as needed + */ + nodirs = 0; + break; + case 'f': + /* + * invert meaning of pattern list + */ + cflag = 1; + break; + case 'i': + /* + * restore an archive + */ + act = EXTRACT; + break; + case 'k': + break; + case 'l': + /* + * use links instead of copies when possible + */ + lflag = 1; + break; + case 'm': + /* + * preserve modification time + */ + pmtime = 1; + break; + case 'o': + /* + * create an archive + */ + act = ARCHIVE; + frmt = &(fsub[F_CPIO]); + break; + case 'p': + /* + * copy-pass mode + */ + act = COPY; + break; + case 'r': + /* + * interactively rename files + */ + iflag = 1; + break; + case 's': + /* + * swap bytes after reading data + */ + break; + case 't': + /* + * list contents of archive + */ + act = LIST; + listf = stdout; + break; + case 'u': + /* + * replace newer files + */ + kflag = 0; + break; + case 'v': + /* + * verbose operation mode + */ + vflag = 1; + break; + case 'z': + /* + * use gzip. Non standard option. + */ + gzip_program = GZIP_CMD; + break; + case 'A': + /* + * append mode + */ + act = APPND; + break; + case 'B': + /* + * Use 5120 byte block size + */ + wrblksz = 5120; + break; + case 'C': + /* + * set block size in bytes + */ + wrblksz = atoi(optarg); + break; + case 'E': + /* + * file with patterns to extract or list + */ + if ((fp = fopen(optarg, "r")) == NULL) { + paxwarn(1, "Unable to open file '%s' for read", optarg); + cpio_usage(); + } + while ((str = getline(fp)) != NULL) { + pat_add(str, NULL); + } + fclose(fp); + if (getline_error) { + paxwarn(1, "Problem with file '%s'", optarg); + cpio_usage(); + } + break; + case 'F': + case 'I': + case 'O': + /* + * filename where the archive is stored + */ + if ((optarg[0] == '-') && (optarg[1]== '\0')) { + /* + * treat a - as stdin + */ + arcname = NULL; + break; + } + arcname = optarg; + break; + case 'H': + /* + * specify an archive format on write + */ + tmp.name = optarg; + if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub, + sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL) + break; + paxwarn(1, "Unknown -H format: %s", optarg); + (void)fputs("cpio: Known -H formats are:", stderr); + for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i) + (void)fprintf(stderr, " %s", fsub[i].name); + (void)fputs("\n\n", stderr); + cpio_usage(); + break; + case 'L': + /* + * follow symbolic links + */ + Lflag = 1; + break; + case 'S': + /* + * swap halfwords after reading data + */ + break; + case 'Z': + /* + * use compress. Non standard option. + */ + gzip_program = COMPRESS_CMD; + break; + case '6': + /* + * process Version 6 cpio format + */ + frmt = &(fsub[F_OCPIO]); + break; + case '?': + default: + cpio_usage(); + break; + } + argc -= optind; + argv += optind; + + /* + * process the args as they are interpreted by the operation mode + */ + switch (act) { + case LIST: + case EXTRACT: + while (*argv != NULL) + if (pat_add(*argv++, NULL) < 0) + cpio_usage(); + break; + case COPY: + if (*argv == NULL) { + paxwarn(0, "Destination directory was not supplied"); + cpio_usage(); + } + dirptr = *argv; + if (mkpath(dirptr) < 0) + cpio_usage(); + --argc; + ++argv; + /* FALL THROUGH */ + case ARCHIVE: + case APPND: + if (*argv != NULL) + cpio_usage(); + /* + * no read errors allowed on updates/append operation! + */ + maxflt = 0; + while ((str = getline(stdin)) != NULL) { + ftree_add(str, NULL); + } + if (getline_error) { + paxwarn(1, "Problem while reading stdin"); + cpio_usage(); + } + break; + default: + cpio_usage(); + break; + } } -#endif /* * printflg() @@ -841,7 +1309,7 @@ printflg(flg) int pos = 0; (void)fprintf(stderr,"%s: Invalid combination of options:", argv0); - while ((nxt = ffs(flg))) { + while ((nxt = ffs(flg)) != 0) { flg = flg >> nxt; pos += nxt; (void)fprintf(stderr, " -%c", flgch[pos-1]); @@ -946,6 +1414,10 @@ opt_add(str) paxwarn(0, "Invalid option name"); return(-1); } + if ((str = strdup(str)) == NULL) { + paxwarn(0, "Unable to allocate space for option list"); + return(-1); + } frpt = endpt = str; /* @@ -958,10 +1430,12 @@ opt_add(str) *endpt = '\0'; if ((pt = strchr(frpt, '=')) == NULL) { paxwarn(0, "Invalid options format"); + free(str); return(-1); } if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) { paxwarn(0, "Unable to allocate space for option list"); + free(str); return(-1); } *pt++ = '\0'; @@ -1065,6 +1539,35 @@ str_offt(val) return(num); } +#ifdef __STDC__ +char * +getline(FILE *f) +#else +char * +getline(f) + FILE *f; +#endif +{ + char *name, *temp; + size_t len; + + name = fgetln(f, &len); + if (!name) { + getline_error = ferror(f) ? GETLINE_FILE_CORRUPT : 0; + return(0); + } + if (name[len-1] != '\n') + len++; + temp = malloc(len); + if (!temp) { + getline_error = GETLINE_OUT_OF_MEM; + return(0); + } + memcpy(temp, name, len-1); + temp[len-1] = 0; + return(temp); +} + /* * no_op() * for those option functions where the archive format has nothing to do. @@ -1135,13 +1638,13 @@ void tar_usage() #endif { - (void)fputs("usage: tar -{txru}[cevfbmopwzBHLPXZ014578] [tapefile] ", + (void)fputs("usage: tar [-]{crtux}[-befhjmopqsvwyzHLOPXZ014578] [blocksize] ", stderr); - (void)fputs("[blocksize] file1 file2...\n", stderr); + (void)fputs("[archive] [replstr] [-C directory] [-I file] [file ...]\n", + stderr); exit(1); } -#ifdef notdef /* * cpio_usage() * print the usage summary to the user @@ -1155,6 +1658,10 @@ void cpio_usage() #endif { + (void)fputs("usage: cpio -o [-aABcLvVzZ] [-C bytes] [-H format] [-O archive]\n", stderr); + (void)fputs(" [-F archive] < name-list [> archive]\n", stderr); + (void)fputs(" cpio -i [-bBcdfmnrsStuvVzZ6] [-C bytes] [-E file] [-H format]\n", stderr); + (void)fputs(" [-I archive] [-F archive] [pattern...] [< archive]\n", stderr); + (void)fputs(" cpio -p [-adlLmuvV] destination-directory < name-list\n", stderr); exit(1); } -#endif diff --git a/bin/pax/pat_rep.c b/bin/pax/pat_rep.c index d6ecd53..769ac94 100644 --- a/bin/pax/pat_rep.c +++ b/bin/pax/pat_rep.c @@ -49,6 +49,7 @@ static const char rcsid[] = #include #include #include +#include #ifdef NET2_REGEX #include #else @@ -228,11 +229,12 @@ rep_add(str) #ifdef __STDC__ int -pat_add(char *str) +pat_add(char *str, char *chdname) #else int -pat_add(str) +pat_add(str, chdname) char *str; + char *chdname; #endif { register PATTERN *pt; @@ -260,6 +262,8 @@ pat_add(str) pt->plen = strlen(str); pt->fow = NULL; pt->flgs = 0; + pt->chdname = chdname; + if (pathead == NULL) { pattail = pathead = pt; return(0); @@ -616,7 +620,7 @@ range_match(pattern, test) int negate; int ok = 0; - if ((negate = (*pattern == '!'))) + if ((negate = (*pattern == '!')) != 0) ++pattern; while ((c = *pattern++) != ']') { @@ -663,6 +667,38 @@ mod_name(arcn) register int res = 0; /* + * Strip off leading '/' if appropriate. + * Currently, this option is only set for the tar format. + */ + if (rmleadslash && arcn->name[0] == '/') { + if (arcn->name[1] == '\0') { + arcn->name[0] = '.'; + } else { + (void)memmove(arcn->name, &arcn->name[1], + strlen(arcn->name)); + arcn->nlen--; + } + if (rmleadslash < 2) { + rmleadslash = 2; + paxwarn(0, "Removing leading / from absolute path names in the archive"); + } + } + if (rmleadslash && arcn->ln_name[0] == '/' && + (arcn->type == PAX_HLK || arcn->type == PAX_HRG)) { + if (arcn->ln_name[1] == '\0') { + arcn->ln_name[0] = '.'; + } else { + (void)memmove(arcn->ln_name, &arcn->ln_name[1], + strlen(arcn->ln_name)); + arcn->ln_nlen--; + } + if (rmleadslash < 2) { + rmleadslash = 2; + paxwarn(0, "Removing leading / from absolute path names in the archive"); + } + } + + /* * IMPORTANT: We have a problem. what do we do with symlinks? * Modifying a hard link name makes sense, as we know the file it * points at should have been seen already in the archive (and if it @@ -703,7 +739,7 @@ mod_name(arcn) return(res); if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) - sub_name(arcn->ln_name, &(arcn->ln_nlen)); + sub_name(arcn->ln_name, &(arcn->ln_nlen), sizeof(arcn->ln_name)); } return(res); } @@ -775,8 +811,8 @@ tty_rename(arcn) */ tty_prnt("Processing continues, name changed to: %s\n", tmpname); res = add_name(arcn->name, arcn->nlen, tmpname); - arcn->nlen = l_strncpy(arcn->name, tmpname, PAXPATHLEN+1); - arcn->name[PAXPATHLEN] = '\0'; + arcn->nlen = l_strncpy(arcn->name, tmpname, sizeof(arcn->name) - 1); + arcn->name[arcn->nlen] = '\0'; if (res < 0) return(-1); return(0); diff --git a/bin/pax/pax.1 b/bin/pax/pax.1 index 88a11eb..b51f534 100644 --- a/bin/pax/pax.1 +++ b/bin/pax/pax.1 @@ -403,7 +403,10 @@ block the output at a positive decimal integer number of bytes per write to the archive file. The .Ar blocksize -must be a multiple of 512 bytes with a maximum of 32256 bytes. +must be a multiple of 512 bytes with a maximum of 64512 bytes. +Archives larger than 32256 bytes violate the +.Tn POSIX +standard and will not be portable to all systems. A .Ar blocksize can end with @@ -1130,6 +1133,9 @@ and operations are extensions to the .Tn POSIX standard. +.Sh SEE ALSO +.Xr tar 1 , +.Xr cpio 1 .Sh AUTHORS .An Keith Muller at the University of California, San Diego diff --git a/bin/pax/pax.c b/bin/pax/pax.c index a53ba80..bc97d7d 100644 --- a/bin/pax/pax.c +++ b/bin/pax/pax.c @@ -55,6 +55,7 @@ static const char rcsid[] = #include #include #include +#include #include #include #include @@ -75,6 +76,7 @@ static int gen_init __P((void)); int act = DEFOP; /* read/write/append/copy */ FSUB *frmt = NULL; /* archive format type */ int cflag; /* match all EXCEPT pattern/file */ +int cwdfd; /* starting cwd */ int dflag; /* directory member match only */ int iflag; /* interactive file/archive rename */ int kflag; /* do not overwrite existing files */ @@ -92,15 +94,18 @@ int Zflag; /* same as uflg except after name mode */ int vfpart; /* is partial verbose output in progress */ int patime = 1; /* preserve file access time */ int pmtime = 1; /* preserve file modification times */ +int nodirs; /* do not create directories as needed */ int pmode; /* preserve file mode bits */ int pids; /* preserve file uid/gid */ +int rmleadslash = 0; /* remove leading '/' from pathnames */ int exit_val; /* exit value */ int docrc; /* check/create file crc */ char *dirptr; /* destination dir in a copy */ char *argv0; /* root of argv[0] */ +sigset_t s_mask; /* signal mask for cleanup critical sect */ +FILE *listf = stderr; /* file pointer to print file list to */ char *tempfile; /* tempfile to use for mkstemp(3) */ char *tempbase; /* basename of tempfile to use for mkstemp(3) */ -sigset_t s_mask; /* signal mask for cleanup critical sect */ /* * PAX - Portable Archive Interchange @@ -236,6 +241,14 @@ main(argc, argv) size_t tdlen; (void) setlocale(LC_ALL, ""); + /* + * Keep a reference to cwd, so we can always come back home. + */ + cwdfd = open(".", O_RDONLY); + if (cwdfd < 0) { + syswarn(0, errno, "Can't open current working directory."); + return(exit_val); + } /* * Where should we put temporary files? @@ -389,6 +402,7 @@ gen_init() paxwarn(1, "Unable to set up signal mask"); return(-1); } + memset(&n_hand, 0, sizeof n_hand); n_hand.sa_mask = s_mask; n_hand.sa_flags = 0; n_hand.sa_handler = sig_cleanup; diff --git a/bin/pax/pax.h b/bin/pax/pax.h index a515cdf..5c12210 100644 --- a/bin/pax/pax.h +++ b/bin/pax/pax.h @@ -42,9 +42,10 @@ * BSD PAX global data structures and constants. */ -#define MAXBLK 32256 /* MAX blocksize supported (posix SPEC) */ +#define MAXBLK 64512 /* MAX blocksize supported (posix SPEC) */ /* WARNING: increasing MAXBLK past 32256 */ /* will violate posix spec. */ +#define MAXBLK_POSIX 32256 /* MAX blocksize supported as per POSIX */ #define BLKMULT 512 /* blocksize must be even mult of 512 bytes */ /* Don't even think of changing this */ #define DEVBLK 8192 /* default read blksize for devices */ @@ -164,6 +165,7 @@ typedef struct { typedef struct pattern { char *pstr; /* pattern to match, user supplied */ char *pend; /* end of a prefix match */ + char *chdname; /* the dir to change to if not NULL. */ int plen; /* length of pstr */ int flgs; /* processing/state flags */ #define MTCH 0x1 /* pattern has been matched */ diff --git a/bin/pax/tables.c b/bin/pax/tables.c index 1a5b3fa..113b65a 100644 --- a/bin/pax/tables.c +++ b/bin/pax/tables.c @@ -180,8 +180,8 @@ chk_lnk(arcn) * other links. */ arcn->ln_nlen = l_strncpy(arcn->ln_name, pt->name, - PAXPATHLEN+1); - arcn->ln_name[PAXPATHLEN] = '\0'; + sizeof(arcn->ln_name) - 1); + arcn->ln_name[arcn->ln_nlen] = '\0'; if (arcn->type == PAX_REG) arcn->type = PAX_HRG; else @@ -624,12 +624,13 @@ add_name(oname, onamelen, nname) #ifdef __STDC__ void -sub_name(register char *oname, int *onamelen) +sub_name(register char *oname, int *onamelen, size_t onamesize) #else void -sub_name(oname, onamelen) +sub_name(oname, onamelen, onamesize) register char *oname; int *onamelen; + size_t onamesize; #endif { register NAMT *pt; @@ -653,8 +654,8 @@ sub_name(oname, onamelen) * found it, replace it with the new name * and return (we know that oname has enough space) */ - *onamelen = l_strncpy(oname, pt->nname, PAXPATHLEN+1); - oname[PAXPATHLEN] = '\0'; + *onamelen = l_strncpy(oname, pt->nname, onamesize - 1); + oname[*onamelen] = '\0'; return; } pt = pt->fow; diff --git a/bin/pax/tar.1 b/bin/pax/tar.1 new file mode 100644 index 0000000..9b2b569 --- /dev/null +++ b/bin/pax/tar.1 @@ -0,0 +1,293 @@ +.\" +.\" Copyright (c) 1996 SigmaSoft, Th. Lockert +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by SigmaSoft, Th. Lockert. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" $OpenBSD: tar.1,v 1.33 2001/05/01 17:58:01 aaron Exp $ +.\" +.Dd February 7, 2001 +.Dt TAR 1 +.Os +.Sh NAME +.Nm tar +.Nd tape archiver +.Sh SYNOPSIS +.Nm tar +.Sm off +.Oo \&- Oc {crtux} Op befhmopqsvwzHLOPXZ014578 +.Sm on +.Op Ar blocksize +.Op Ar archive +.Op Ar replstr +.\" XXX how to do this right? +.Op Fl C Ar directory +.Op Fl I Ar file +.Op Ar file ... +.Sh DESCRIPTION +The +.Nm +command creates, adds files to, or extracts files from an +archive file in +.Dq tar +format. +A tar archive is often stored on a magnetic tape, but can be +stored equally well on a floppy, CD-ROM, or in a regular disk file. +.Pp +One of the following flags must be present: +.Bl -tag -width Ar +.It Fl c +Create new archive, or overwrite an existing archive, +adding the specified files to it. +.It Fl r +Append the named new files to existing archive. +Note that this will only work on media on which an end-of-file mark +can be overwritten. +.It Fl t +List contents of archive. +If any files are named on the +command line, only those files will be listed. +.It Fl u +Alias for +.Fl r . +.It Fl x +Extract files from archive. +If any files are named on the +command line, only those files will be extracted from the +archive. +If more than one copy of a file exists in the +archive, later copies will overwrite earlier copies during +extraction. +The file mode and modification time are preserved +if possible. +The file mode is subject to modification by the +.Xr umask 2 . +.El +.Pp +In addition to the flags mentioned above, any of the following +flags may be used: +.Bl -tag -width Ar +.It Fl b Ar "blocking factor" +Set blocking factor to use for the archive. +.Nm +uses 512 byte blocks. +The default is 20, the maximum is 126. +Archives with a blocking factor larger 63 violate the +.Tn POSIX +standard and will not be portable to all systems. +.It Fl e +Stop after first error. +.It Fl f Ar archive +Filename where the archive is stored. +Defaults to +.Pa /dev/rst0 . +.It Fl h +Follow symbolic links as if they were normal files +or directories. +.It Fl j +Compress archives using bzip2. +.It Fl m +Do not preserve modification time. +.It Fl O +Write old-style (non-POSIX) archives. +.It Fl o +Don't write directory information that the older (V7) style +.Nm +is unable to decode. +This implies the +.Fl O +flag. +.It Fl p +Preserve user and group ID as well as file mode regardless of +the current +.Xr umask 2 . +The setuid and setgid bits are only preserved if the user is +the superuser. +Only meaningful in conjunction with the +.Fl x +flag. +.It Fl q +Select the first archive member that matches each +.Ar pattern +operand. +No more than one archive member is matched for each +.Ar pattern . +When members of type directory are matched, the file hierarchy rooted at that +directory is also matched. +.It Fl s Ar replstr +Modify the file or archive member names specified by the +.Ar pattern +or +.Ar file +operands according to the substitution expression +.Ar replstr , +using the syntax of the +.Xr ed 1 +utility regular expressions. +The format of these regular expressions are: +.Dl /old/new/[gp] +As in +.Xr ed 1 , +.Cm old +is a basic regular expression and +.Cm new +can contain an ampersand (&), \\n (where n is a digit) back-references, +or subexpression matching. +The +.Cm old +string may also contain +.Dv +characters. +Any non-null character can be used as a delimiter (/ is shown here). +Multiple +.Fl s +expressions can be specified. +The expressions are applied in the order they are specified on the +command line, terminating with the first successful substitution. +The optional trailing +.Cm g +continues to apply the substitution expression to the pathname substring +which starts with the first character following the end of the last successful +substitution. +The first unsuccessful substitution stops the operation of the +.Cm g +option. +The optional trailing +.Cm p +will cause the final result of a successful substitution to be written to +.Dv standard error +in the following format: +.Dl >> +File or archive member names that substitute to the empty string +are not selected and will be skipped. +.It Fl v +Verbose operation mode. +.It Fl w +Interactively rename files. +This option causes +.Nm +to prompt the user for the filename to use when storing or +extracting files in an archive. +.It Fl y +Compress archives using bzip2. +.It Fl z +Compress archive using gzip. +.It Fl C Ar directory +This is a positional argument which sets the working directory for the +following files. +When extracting, files will be extracted into +the specified directory; when creating, the specified files will be matched +from the directory. +.It Fl H +Follow symlinks given on command line only. +.It Fl L +Follow all symlinks. +.It Fl P +Do not strip leading slashes +.Pq Sq / +from pathnames. +The default is to strip leading slashes. +.It Fl I Ar file +This is a positional argument which reads the names of files to +archive or extract from the given file, one per line. +.It Fl X +Do not cross mount points in the file system. +.It Fl Z +Compress archive using compress. +.El +.Pp +The options +.Op Fl 014578 +can be used to select one of the compiled-in backup devices, +.Pa /dev/rstN . +.Sh DIAGNOSTICS +.Nm +will exit with one of the following values: +.Bl -tag -width 2n +.It 0 +All files were processed successfully. +.It 1 +An error occurred. +.El +.Pp +Whenever +.Nm +cannot create a file or a link when extracting an archive or cannot +find a file while writing an archive, or cannot preserve the user +ID, group ID, file mode, or access and modification times when the +.Fl p +option is specified, a diagnostic message is written to standard +error and a non-zero exit value will be returned, but processing +will continue. +In the case where +.Nm +cannot create a link to a file, +.Nm +will not create a second copy of the file. +.Pp +If the extraction of a file from an archive is prematurely terminated +by a signal or error, +.Nm +may have only partially extracted the file the user wanted. +Additionally, the file modes of extracted files and directories may +have incorrect file bits, and the modification and access times may +be wrong. +.Pp +If the creation of an archive is prematurely terminated by a signal +or error, +.Nm +may have only partially created the archive which may violate the +specific archive format specification. +.Sh FILES +.Bl -tag -width "/dev/rst0" +.It Pa /dev/rst0 +default archive name +.El +.Sh ENVIRONMENT +.Bl -tag -width Fl +.It Ev TMPDIR +Path in which to store temporary files. +.It Ev TAPE +Default tape device to use instead of +.Pa /dev/rst0 . +.El +.Sh SEE ALSO +.Xr cpio 1 , +.Xr pax 1 +.Sh AUTHORS +Keith Muller at the University of California, San Diego. +.Sh HISTORY +A +.Nm +command first appeared in +.At v7 . +.Sh CAVEATS +The +.Fl L +flag is not portable to other versions of +.Nm +where it may have a different meaning. diff --git a/bin/pax/tar.c b/bin/pax/tar.c index c6d5b89..541b450 100644 --- a/bin/pax/tar.c +++ b/bin/pax/tar.c @@ -162,7 +162,7 @@ tar_trail(buf, in_resync, cnt) * ul_oct() * convert an unsigned long to an octal string. many oddball field * termination characters are used by the various versions of tar in the - * different fields. term selects which kind to use. str is BLANK padded + * different fields. term selects which kind to use. str is '0' padded * at the front to len. we are unable to use only one format as many old * tar readers are very cranky about this. * Return: @@ -215,7 +215,7 @@ ul_oct(val, str, len, term) } while (pt >= str) - *pt-- = ' '; + *pt-- = '0'; if (val != (u_long)0) return(-1); return(0); @@ -226,7 +226,7 @@ ul_oct(val, str, len, term) * uqd_oct() * convert an u_quad_t to an octal string. one of many oddball field * termination characters are used by the various versions of tar in the - * different fields. term selects which kind to use. str is BLANK padded + * different fields. term selects which kind to use. str is '0' padded * at the front to len. we are unable to use only one format as many old * tar readers are very cranky about this. * Return: @@ -279,7 +279,7 @@ uqd_oct(val, str, len, term) } while (pt >= str) - *pt-- = ' '; + *pt-- = '0'; if (val != (u_quad_t)0) return(-1); return(0); @@ -453,13 +453,17 @@ tar_rd(arcn, buf) * copy out the name and values in the stat buffer */ hd = (HD_TAR *)buf; - arcn->nlen = l_strncpy(arcn->name, hd->name, sizeof(hd->name)); + arcn->nlen = l_strncpy(arcn->name, hd->name, sizeof(arcn->name) - 1); arcn->name[arcn->nlen] = '\0'; arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) & 0xfff); arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); - arcn->sb.st_size = (size_t)asc_ul(hd->size, sizeof(hd->size), OCT); +#ifdef NET2_STAT + arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); +#else + arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); +#endif arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; @@ -478,7 +482,7 @@ tar_rd(arcn, buf) */ arcn->type = PAX_SLK; arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, - sizeof(hd->linkname)); + sizeof(arcn->ln_name) - 1); arcn->ln_name[arcn->ln_nlen] = '\0'; arcn->sb.st_mode |= S_IFLNK; break; @@ -490,7 +494,7 @@ tar_rd(arcn, buf) arcn->type = PAX_HLK; arcn->sb.st_nlink = 2; arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, - sizeof(hd->linkname)); + sizeof(arcn->ln_name) - 1); arcn->ln_name[arcn->ln_nlen] = '\0'; /* @@ -499,6 +503,16 @@ tar_rd(arcn, buf) */ arcn->sb.st_mode |= S_IFREG; break; + case DIRTYPE: + /* + * It is a directory, set the mode for -v printing + */ + arcn->type = PAX_DIR; + arcn->sb.st_mode |= S_IFDIR; + arcn->sb.st_nlink = 2; + arcn->ln_name[0] = '\0'; + arcn->ln_nlen = 0; + break; case AREGTYPE: case REGTYPE: default: @@ -607,7 +621,7 @@ tar_wr(arcn) len = arcn->nlen; if (arcn->type == PAX_DIR) ++len; - if (len > sizeof(hd->name)) { + if (len >= sizeof(hd->name)) { paxwarn(1, "File name too long for tar %s", arcn->name); return(1); } @@ -621,7 +635,8 @@ tar_wr(arcn) * a header) */ hd = (HD_TAR *)hdblk; - zf_strncpy(hd->name, arcn->name, sizeof(hd->name)); + l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1); + hd->name[sizeof(hd->name) - 1] = '\0'; arcn->pad = 0; if (arcn->type == PAX_DIR) { @@ -640,7 +655,8 @@ tar_wr(arcn) * no data follows this file, so no pad */ hd->linkflag = SYMTYPE; - zf_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname)); + l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); + hd->linkname[sizeof(hd->linkname) - 1] = '\0'; if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) goto out; } else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) { @@ -648,7 +664,8 @@ tar_wr(arcn) * no data follows this file, so no pad */ hd->linkflag = LNKTYPE; - zf_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname)); + l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); + hd->linkname[sizeof(hd->linkname) - 1] = '\0'; if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) goto out; } else { @@ -685,7 +702,7 @@ tar_wr(arcn) * to be written */ if (ul_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum, - sizeof(hd->chksum), 2)) + sizeof(hd->chksum), 3)) goto out; if (wr_rdbuf(hdblk, sizeof(HD_TAR)) < 0) return(-1); @@ -818,6 +835,7 @@ ustar_rd(arcn, buf) arcn->org_name = arcn->name; arcn->sb.st_nlink = 1; arcn->pat = NULL; + arcn->nlen = 0; hd = (HD_USTAR *)buf; /* @@ -826,12 +844,12 @@ ustar_rd(arcn, buf) */ dest = arcn->name; if (*(hd->prefix) != '\0') { - cnt = l_strncpy(arcn->name, hd->prefix, sizeof(hd->prefix)); - dest = arcn->name + arcn->nlen; + cnt = l_strncpy(dest, hd->prefix, sizeof(arcn->name) - 2); + dest += cnt; *dest++ = '/'; + cnt++; } - arcn->nlen = l_strncpy(dest, hd->name, sizeof(hd->name)); - arcn->nlen += cnt; + arcn->nlen = cnt + l_strncpy(dest, hd->name, sizeof(arcn->name) - cnt); arcn->name[arcn->nlen] = '\0'; /* @@ -840,7 +858,11 @@ ustar_rd(arcn, buf) */ arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) & 0xfff); - arcn->sb.st_size = (size_t)asc_ul(hd->size, sizeof(hd->size), OCT); +#ifdef NET2_STAT + arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); +#else + arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); +#endif arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; @@ -920,7 +942,7 @@ ustar_rd(arcn, buf) * copy the link name */ arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, - sizeof(hd->linkname)); + sizeof(arcn->ln_name) - 1); arcn->ln_name[arcn->ln_nlen] = '\0'; break; case CONTTYPE: @@ -1002,7 +1024,7 @@ ustar_wr(arcn) * occur, we remove the / and copy the first part to the prefix */ *pt = '\0'; - zf_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix)); + l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix) - 1); *pt++ = '/'; } else memset(hd->prefix, 0, sizeof(hd->prefix)); @@ -1011,7 +1033,8 @@ ustar_wr(arcn) * copy the name part. this may be the whole path or the part after * the prefix */ - zf_strncpy(hd->name, pt, sizeof(hd->name)); + l_strncpy(hd->name, pt, sizeof(hd->name) - 1); + hd->name[sizeof(hd->name) - 1] = '\0'; /* * set the fields in the header that are type dependent @@ -1054,7 +1077,8 @@ ustar_wr(arcn) hd->typeflag = SYMTYPE; else hd->typeflag = LNKTYPE; - zf_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname)); + l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); + hd->linkname[sizeof(hd->linkname) - 1] = '\0'; memset(hd->devmajor, 0, sizeof(hd->devmajor)); memset(hd->devminor, 0, sizeof(hd->devminor)); if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) @@ -1087,8 +1111,8 @@ ustar_wr(arcn) break; } - zf_strncpy(hd->magic, TMAGIC, TMAGLEN); - zf_strncpy(hd->version, TVERSION, TVERSLEN); + l_strncpy(hd->magic, TMAGIC, TMAGLEN); + l_strncpy(hd->version, TVERSION, TVERSLEN); /* * set the remaining fields. Some versions want all 16 bits of mode @@ -1099,8 +1123,8 @@ ustar_wr(arcn) ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) || ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3)) goto out; - zf_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname)); - zf_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname)); + l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname)); + l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname)); /* * calculate and store the checksum write the header to the archive @@ -1154,7 +1178,7 @@ name_split(name, len) * check to see if the file name is small enough to fit in the name * field. if so just return a pointer to the name. */ - if (len <= TNMSZ) + if (len < TNMSZ) return(name); if (len > (TPFSZ + TNMSZ)) return(NULL); diff --git a/bin/pax/tty_subs.c b/bin/pax/tty_subs.c index 9d8763e..b04885f 100644 --- a/bin/pax/tty_subs.c +++ b/bin/pax/tty_subs.c @@ -189,6 +189,7 @@ paxwarn(set, fmt, va_alist) * line by itself */ if (vflag && vfpart) { + (void)fflush(listf); (void)fputc('\n', stderr); vfpart = 0; } @@ -229,6 +230,7 @@ syswarn(set, errnum, fmt, va_alist) * line by itself */ if (vflag && vfpart) { + (void)fflush(listf); (void)fputc('\n', stderr); vfpart = 0; } -- cgit v1.1