From 85fee539f46ba8fb5b2f4cc95f1771ea1c379f15 Mon Sep 17 00:00:00 2001 From: Lionel Sambuc Date: Mon, 22 Oct 2012 16:10:38 +0200 Subject: [PATCH] Upgrading pax. This also means importing librmt. Change-Id: Ie5b314aeaad28dca46acb64f20f2d70746ea52d0 --- bin/Makefile | 2 +- bin/pax/Makefile | 61 + {commands => bin}/pax/ar_io.c | 833 ++++++++--- {commands => bin}/pax/ar_subs.c | 486 +++++-- {commands => bin}/pax/buf_subs.c | 235 ++-- {commands => bin}/pax/cpio.1 | 162 +-- {commands => bin}/pax/cpio.c | 440 +++--- {commands => bin}/pax/cpio.h | 5 +- bin/pax/dumptar.c | 122 ++ {commands => bin}/pax/extern.h | 115 +- {commands => bin}/pax/file_subs.c | 610 +++++--- {commands => bin}/pax/ftree.c | 418 ++++-- {commands => bin}/pax/ftree.h | 6 +- {commands => bin}/pax/gen_subs.c | 255 ++-- {commands => bin}/pax/getoldopt.c | 60 +- bin/pax/options.c | 2161 +++++++++++++++++++++++++++++ {commands => bin}/pax/options.h | 80 +- {commands => bin}/pax/pat_rep.c | 457 +++--- {commands => bin}/pax/pat_rep.h | 12 +- {commands => bin}/pax/pax.1 | 452 +++--- {commands => bin}/pax/pax.c | 193 ++- {commands => bin}/pax/pax.h | 244 ++-- {commands => bin}/pax/sel_subs.c | 234 ++-- {commands => bin}/pax/sel_subs.h | 7 +- {commands => bin}/pax/tables.c | 317 +++-- {commands => bin}/pax/tables.h | 13 +- {commands => bin}/pax/tar.1 | 250 ++-- {commands => bin}/pax/tar.c | 859 ++++++++---- {commands => bin}/pax/tar.h | 35 +- {commands => bin}/pax/tty_subs.c | 49 +- commands/Makefile | 2 +- commands/pax/Makefile | 40 - commands/pax/cache.c | 430 ------ commands/pax/cache.h | 71 - commands/pax/err.h | 0 commands/pax/fgetln.c | 38 - commands/pax/options.c | 1606 --------------------- lib/Makefile | 2 +- lib/librmt/Makefile | 16 + lib/librmt/README | 20 + lib/librmt/pathnames.h | 30 + lib/librmt/rmtlib.c | 896 ++++++++++++ lib/librmt/rmtops.3 | 182 +++ releasetools/nbsd_ports | 2 + tools/Makefile | 1 + tools/pax/Makefile | 6 + 46 files changed, 7789 insertions(+), 4726 deletions(-) create mode 100644 bin/pax/Makefile rename {commands => bin}/pax/ar_io.c (64%) rename {commands => bin}/pax/ar_subs.c (77%) rename {commands => bin}/pax/buf_subs.c (85%) rename {commands => bin}/pax/cpio.1 (76%) rename {commands => bin}/pax/cpio.c (69%) rename {commands => bin}/pax/cpio.h (97%) create mode 100644 bin/pax/dumptar.c rename {commands => bin}/pax/extern.h (73%) rename {commands => bin}/pax/file_subs.c (61%) rename {commands => bin}/pax/ftree.c (55%) rename {commands => bin}/pax/ftree.h (92%) rename {commands => bin}/pax/gen_subs.c (66%) rename {commands => bin}/pax/getoldopt.c (52%) create mode 100644 bin/pax/options.c rename {commands => bin}/pax/options.h (63%) rename {commands => bin}/pax/pat_rep.c (82%) rename {commands => bin}/pax/pat_rep.h (90%) rename {commands => bin}/pax/pax.1 (82%) rename {commands => bin}/pax/pax.c (81%) rename {commands => bin}/pax/pax.h (72%) rename {commands => bin}/pax/sel_subs.c (78%) rename {commands => bin}/pax/sel_subs.h (93%) rename {commands => bin}/pax/tables.c (84%) rename {commands => bin}/pax/tables.h (96%) rename {commands => bin}/pax/tar.1 (56%) rename {commands => bin}/pax/tar.c (54%) rename {commands => bin}/pax/tar.h (88%) rename {commands => bin}/pax/tty_subs.c (83%) delete mode 100644 commands/pax/Makefile delete mode 100644 commands/pax/cache.c delete mode 100644 commands/pax/cache.h delete mode 100644 commands/pax/err.h delete mode 100644 commands/pax/fgetln.c delete mode 100644 commands/pax/options.c create mode 100644 lib/librmt/Makefile create mode 100644 lib/librmt/README create mode 100644 lib/librmt/pathnames.h create mode 100644 lib/librmt/rmtlib.c create mode 100644 lib/librmt/rmtops.3 create mode 100644 tools/pax/Makefile diff --git a/bin/Makefile b/bin/Makefile index a8739e32f..e7f753820 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -2,6 +2,6 @@ .include -SUBDIR= cat date ed mkdir rm rmdir +SUBDIR= cat date ed mkdir pax rm rmdir .include diff --git a/bin/pax/Makefile b/bin/pax/Makefile new file mode 100644 index 000000000..84f820163 --- /dev/null +++ b/bin/pax/Makefile @@ -0,0 +1,61 @@ +# $NetBSD: Makefile,v 1.39 2010/04/23 19:41:02 joerg Exp $ +# @(#)Makefile 8.1 (Berkeley) 5/31/93 + +.include + +PROG= pax +SRCS= ar_io.c ar_subs.c buf_subs.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 + +.if defined(SMALLPROG) +CPPFLAGS+= -DSMALL -DNO_CPIO +.else +SRCS+= getid.c spec.c misc.c pack_dev.c cpio.c +CPPFLAGS+= -I${NETBSDSRCDIR}/usr.sbin/mtree \ + -I${NETBSDSRCDIR}/sbin/mknod +.PATH: ${NETBSDSRCDIR}/usr.sbin/mtree \ + ${NETBSDSRCDIR}/sbin/mknod + +.if (${HOSTPROG:U} == "") +DPADD+= ${LIBUTIL} +LDADD+= -lutil +.endif +.endif + +MAN= pax.1 tar.1 cpio.1 + +.if defined(HOSTPROG) +CPPFLAGS+= -DHOSTPROG +.else # { ! HOSTPROG + +# XXX: Interix does not have it; we need a conditional for it. +CPPFLAGS+= -DHAVE_SYS_MTIO_H + +.if ${MKBSDTAR} == "no" +LINKS+= ${BINDIR}/pax ${BINDIR}/tar +SYMLINKS+=${BINDIR}/tar /usr/bin/tar +.if defined(__MINIX) +SYMLINKS+=${BINDIR}/tar /usr/bin/bsdtar +.endif + +LINKS+= ${BINDIR}/pax ${BINDIR}/cpio +SYMLINKS+=${BINDIR}/cpio /usr/bin/cpio +.endif +.endif # } ! HOSTPROG + +.if !defined(HOSTPROG) && !defined(SMALLPROG) +CPPFLAGS+= -DSUPPORT_RMT + +LDADD+= -lrmt +DPADD+= ${LIBRMT} +.endif + +.if defined(__MINIX) +CPPFLAGS+= -DHOSTPROG +CPPFLAGS+= -Dlchown=chown -Dlchmod=chmod +DPADD+= ${LIBUTIL} +LDADD+= -lutil +.endif + +.include diff --git a/commands/pax/ar_io.c b/bin/pax/ar_io.c similarity index 64% rename from commands/pax/ar_io.c rename to bin/pax/ar_io.c index 10d480cfc..164740a26 100644 --- a/commands/pax/ar_io.c +++ b/bin/pax/ar_io.c @@ -1,3 +1,5 @@ +/* $netbsd: ar_io.c,v 1.48 2007/04/23 18:40:22 christos Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,25 +33,40 @@ * SUCH DAMAGE. */ -#ifndef lint +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) #if 0 static char sccsid[] = "@(#)ar_io.c 8.2 (Berkeley) 4/18/94"; +#else +__RCSID("$NetBSD: ar_io.c,v 1.54 2012/03/20 18:42:28 matt Exp $"); #endif #endif /* not lint */ #include +#include +#include +#include #include +#ifdef HAVE_SYS_MTIO_H #include -#include +#endif #include -#include -#include #include -#include -#include #include -#include +#include #include +#include +#include +#include +#include +#ifdef SUPPORT_RMT +#define __RMTLIB_PRIVATE +#include +#endif /* SUPPORT_RMT */ #include "pax.h" #include "options.h" #include "extern.h" @@ -62,10 +79,9 @@ static char sccsid[] = "@(#)ar_io.c 8.2 (Berkeley) 4/18/94"; #define EXT_MODE O_RDONLY /* open mode for list/extract */ #define AR_MODE (O_WRONLY | O_CREAT | O_TRUNC) /* mode for archive */ #define APP_MODE O_RDWR /* mode for append */ - -static char none[] = ""; /* pseudo name for no file */ -static char stdo[] = ""; /* pseudo name for stdout */ -static char stdn[] = ""; /* pseudo name for stdin */ +static char STDO[] = ""; /* pseudo name for stdout */ +static char STDN[] = ""; /* pseudo name for stdin */ +static char NONE[] = ""; /* pseudo name for none */ static int arfd = -1; /* archive file descriptor */ static int artyp = ISREG; /* archive type: file/FIFO/tape */ static int arvol = 1; /* archive volume number */ @@ -77,13 +93,29 @@ static struct stat arsb; /* stat of archive device at open */ static int invld_rec; /* tape has out of spec record size */ static int wr_trail = 1; /* trailer was rewritten in append */ static int can_unlnk = 0; /* do we unlink null archives? */ -const char *arcname; /* printable name of archive */ +const char *arcname; /* printable name of archive */ const char *gzip_program; /* name of gzip program */ static pid_t zpid = -1; /* pid of child process */ +time_t starttime; /* time the run started */ +int force_one_volume; /* 1 if we ignore volume changes */ +#ifdef HAVE_SYS_MTIO_H static int get_phys(void); +#endif extern sigset_t s_mask; static void ar_start_gzip(int, const char *, int); +static const char *timefmt(char *, size_t, off_t, time_t, const char *); +static const char *sizefmt(char *, size_t, off_t); + +#ifdef SUPPORT_RMT +#ifdef SYS_NO_RESTART +static int rmtread_with_restart(int, void *, int); +static int rmtwrite_with_restart(int, void *, int); +#else +#define rmtread_with_restart(a, b, c) rmtread((a), (b), (c)) +#define rmtwrite_with_restart(a, b, c) rmtwrite((a), (b), (c)) +#endif +#endif /* SUPPORT_RMT */ /* * ar_open() @@ -97,7 +129,9 @@ static void ar_start_gzip(int, const char *, int); int ar_open(const char *name) { +#ifdef HAVE_SYS_MTIO_H struct mtget mb; +#endif if (arfd != -1) (void)close(arfd); @@ -106,6 +140,24 @@ ar_open(const char *name) artyp = ISREG; flcnt = 0; +#ifdef SUPPORT_RMT + if (name && strchr(name, ':') != NULL && !forcelocal) { + artyp = ISRMT; + if ((arfd = rmtopen(name, O_RDWR, DMOD)) == -1) { + syswarn(0, errno, "Failed open on %s", name); + return -1; + } + if (!isrmt(arfd)) { + rmtclose(arfd); + tty_warn(0, "Not a remote file: %s", name); + return -1; + } + blksz = rdblksz = 8192; + lstrval = 1; + return 0; + } +#endif /* SUPPORT_RMT */ + /* * open based on overall operation mode */ @@ -114,7 +166,7 @@ ar_open(const char *name) case EXTRACT: if (name == NULL) { arfd = STDIN_FILENO; - arcname = stdn; + arcname = STDN; } else if ((arfd = open(name, EXT_MODE, DMOD)) < 0) syswarn(0, errno, "Failed open to read on %s", name); if (arfd != -1 && gzip_program != NULL) @@ -123,7 +175,7 @@ ar_open(const char *name) case ARCHIVE: if (name == NULL) { arfd = STDOUT_FILENO; - arcname = stdo; + arcname = STDO; } else if ((arfd = open(name, AR_MODE, DMOD)) < 0) syswarn(0, errno, "Failed open to write on %s", name); else @@ -134,7 +186,7 @@ ar_open(const char *name) case APPND: if (name == NULL) { arfd = STDOUT_FILENO; - arcname = stdo; + arcname = STDO; } else if ((arfd = open(name, APP_MODE, DMOD)) < 0) syswarn(0, errno, "Failed open to read/write on %s", name); @@ -143,18 +195,16 @@ ar_open(const char *name) /* * arfd not used in COPY mode */ - arcname = none; + arcname = NONE; lstrval = 1; - return(0); + return 0; } if (arfd < 0) - return(-1); + return -1; if (chdname != NULL) - if (chdir(chdname) != 0) { - syswarn(1, errno, "Failed chdir to %s", chdname); - return(-1); - } + if (dochdir(chdname) == -1) + return -1; /* * set up is based on device type */ @@ -163,46 +213,68 @@ ar_open(const char *name) (void)close(arfd); arfd = -1; can_unlnk = 0; - return(-1); + return -1; } if (S_ISDIR(arsb.st_mode)) { - paxwarn(0, "Cannot write an archive on top of a directory %s", + tty_warn(0, "Cannot write an archive on top of a directory %s", arcname); (void)close(arfd); arfd = -1; can_unlnk = 0; - return(-1); + return -1; } - if (S_ISCHR(arsb.st_mode)) + if (S_ISCHR(arsb.st_mode)) { +#ifdef HAVE_SYS_MTIO_H artyp = ioctl(arfd, MTIOCGET, &mb) ? ISCHR : ISTAPE; - else if (S_ISBLK(arsb.st_mode)) +#else + tty_warn(1, "System does not have tape support"); + artyp = ISREG; +#endif + } else if (S_ISBLK(arsb.st_mode)) artyp = ISBLK; else if ((lseek(arfd, (off_t)0L, SEEK_CUR) == -1) && (errno == ESPIPE)) artyp = ISPIPE; else artyp = ISREG; + /* + * Special handling for empty files. + */ + if (artyp == ISREG && arsb.st_size == 0) { + switch (act) { + case LIST: + case EXTRACT: + return -1; + case APPND: + act = -ARCHIVE; + return -1; + case ARCHIVE: + break; + } + } + /* * make sure we beyond any doubt that we only can unlink regular files * we created */ if (artyp != ISREG) can_unlnk = 0; + /* * if we are writing, we are done */ if (act == ARCHIVE) { blksz = rdblksz = wrblksz; lstrval = 1; - return(0); + return 0; } /* * set default blksz on read. APPNDs writes rdblksz on the last volume * On all new archive volumes, we shift to wrblksz (if the user * specified one, otherwize we will continue to use rdblksz). We - * must to set blocksize based on what kind of device the archive is + * must set blocksize based on what kind of device the archive is * stored. */ switch(artyp) { @@ -239,12 +311,10 @@ ar_open(const char *name) break; } -#if 0 /* Not on minix */ if ((arsb.st_blksize > 0) && (arsb.st_blksize < MAXBLK) && ((arsb.st_blksize % BLKMULT) == 0)) rdblksz = arsb.st_blksize; else -#endif rdblksz = DEVBLK; /* * For performance go for large reads when we can without harm @@ -284,13 +354,13 @@ ar_open(const char *name) break; default: /* - * should never happen, worse case, slow... + * should never happen, worst case, slow... */ blksz = rdblksz = BLKMULT; break; } lstrval = 1; - return(0); + return 0; } /* @@ -307,13 +377,14 @@ ar_close(void) return; } + /* * 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 * going on (this avoids the user hitting control-c thinking pax is * broken). */ - if (vflag && (artyp == ISTAPE)) { + if ((vflag || Vflag) && (artyp == ISTAPE)) { if (vfpart) (void)putc('\n', listf); (void)fprintf(listf, @@ -339,13 +410,18 @@ ar_close(void) if ((act == LIST || act == EXTRACT) && nflag && zpid > 0) kill(zpid, SIGINT); - (void)close(arfd); +#ifdef SUPPORT_RMT + if (artyp == ISRMT) + (void)rmtclose(arfd); + else +#endif /* SUPPORT_RMT */ + (void)close(arfd); /* Do not exit before child to ensure data integrity */ if (zpid > 0) waitpid(zpid, &status, 0); - if (vflag && (artyp == ISTAPE)) { + if ((vflag || Vflag) && (artyp == ISTAPE)) { (void)fputs("done.\n", listf); vfpart = 0; (void)fflush(listf); @@ -365,7 +441,7 @@ ar_close(void) if (frmt != NULL) ++arvol; - if (!vflag) { + if (!vflag && !Vflag) { flcnt = 0; return; } @@ -378,37 +454,14 @@ ar_close(void) vfpart = 0; } - /* - * If we have not determined the format yet, we just say how many bytes - * we have skipped over looking for a header to id. there is no way we - * could have written anything yet. - */ - if (frmt == NULL) { -# ifdef NET2_STAT - (void)fprintf(listf, "%s: unknown format, %lu bytes skipped.\n", - argv0, rdcnt); -# else - (void)fprintf(listf, "%s: unknown format, %ju bytes skipped.\n", - argv0, (uintmax_t)rdcnt); -# endif - (void)fflush(listf); - flcnt = 0; - return; + /* mimic cpio's block count first */ + if (frmt && strcmp(NM_CPIO, argv0) == 0) { + (void)fprintf(listf, OFFT_F " blocks\n", + (rdcnt ? rdcnt : wrcnt) / 5120); } - if (strcmp(NM_CPIO, argv0) == 0) - (void)fprintf(listf, "%llu blocks\n", - (unsigned long)((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", - argv0, frmt->name, arvol-1, flcnt, rdcnt, wrcnt); -# else - "%s: %s vol %d, %ju files, %ju bytes read, %ju bytes written.\n", - argv0, frmt->name, arvol-1, (uintmax_t)flcnt, - (uintmax_t)rdcnt, (uintmax_t)wrcnt); -# endif + ar_summary(0); + (void)fflush(listf); flcnt = 0; } @@ -437,8 +490,19 @@ ar_drain(void) /* * keep reading until pipe is drained */ - while ((res = read(arfd, drbuf, sizeof(drbuf))) > 0) - ; +#ifdef SUPPORT_RMT + if (artyp == ISRMT) { + while ((res = rmtread_with_restart(arfd, + drbuf, sizeof(drbuf))) > 0) + continue; + } else { +#endif /* SUPPORT_RMT */ + while ((res = read_with_restart(arfd, + drbuf, sizeof(drbuf))) > 0) + continue; +#ifdef SUPPORT_RMT + } +#endif /* SUPPORT_RMT */ lstrval = res; } @@ -467,7 +531,7 @@ ar_set_wr(void) * Add any device dependent code as required here */ if (artyp != ISREG) - return(0); + return 0; /* * Ok we have an archive in a regular file. If we were rewriting a * file, we must get rid of all the stuff after the current offset @@ -476,9 +540,9 @@ ar_set_wr(void) if (((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0) || (ftruncate(arfd, cpos) < 0)) { syswarn(1, errno, "Unable to truncate archive file"); - return(-1); + return -1; } - return(0); + return 0; } /* @@ -494,15 +558,158 @@ int ar_app_ok(void) { if (artyp == ISPIPE) { - paxwarn(1, "Cannot append to an archive obtained from a pipe."); - return(-1); + tty_warn(1, + "Cannot append to an archive obtained from a pipe."); + return -1; } if (!invld_rec) - return(0); - paxwarn(1,"Cannot append, device record size %d does not support %s spec", - rdblksz, argv0); - return(-1); + return 0; + tty_warn(1, + "Cannot append, device record size %d does not support %s spec", + rdblksz, argv0); + return -1; +} + +#ifdef SYS_NO_RESTART +/* + * read_with_restart() + * Equivalent to read() but does retry on signals. + * This function is not needed on 4.2BSD and later. + * Return: + * Number of bytes written. -1 indicates an error. + */ + +int +read_with_restart(int fd, void *buf, int bsz) +{ + int r; + + while (((r = read(fd, buf, bsz)) < 0) && errno == EINTR) + continue; + + return r; +} + +/* + * rmtread_with_restart() + * Equivalent to rmtread() but does retry on signals. + * This function is not needed on 4.2BSD and later. + * Return: + * Number of bytes written. -1 indicates an error. + */ +static int +rmtread_with_restart(int fd, void *buf, int bsz) +{ + int r; + + while (((r = rmtread(fd, buf, bsz)) < 0) && errno == EINTR) + continue; + + return r; +} +#endif + +/* + * xread() + * Equivalent to read() but does retry on partial read, which may occur + * on signals. + * Return: + * Number of bytes read. 0 for end of file, -1 for an error. + */ + +int +xread(int fd, void *buf, int bsz) +{ + char *b = buf; + int nread = 0; + int r; + + do { +#ifdef SUPPORT_RMT + if ((r = rmtread_with_restart(fd, b, bsz)) <= 0) + break; +#else + if ((r = read_with_restart(fd, b, bsz)) <= 0) + break; +#endif /* SUPPORT_RMT */ + b += r; + bsz -= r; + nread += r; + } while (bsz > 0); + + return nread ? nread : r; +} + +#ifdef SYS_NO_RESTART +/* + * write_with_restart() + * Equivalent to write() but does retry on signals. + * This function is not needed on 4.2BSD and later. + * Return: + * Number of bytes written. -1 indicates an error. + */ + +int +write_with_restart(int fd, void *buf, int bsz) +{ + int r; + + while (((r = write(fd, buf, bsz)) < 0) && errno == EINTR) + ; + + return r; +} + +/* + * rmtwrite_with_restart() + * Equivalent to write() but does retry on signals. + * This function is not needed on 4.2BSD and later. + * Return: + * Number of bytes written. -1 indicates an error. + */ + +static int +rmtwrite_with_restart(int fd, void *buf, int bsz) +{ + int r; + + while (((r = rmtwrite(fd, buf, bsz)) < 0) && errno == EINTR) + ; + + return r; +} +#endif + +/* + * xwrite() + * Equivalent to write() but does retry on partial write, which may occur + * on signals. + * Return: + * Number of bytes written. -1 indicates an error. + */ + +int +xwrite(int fd, void *buf, int bsz) +{ + char *b = buf; + int written = 0; + int r; + + do { +#ifdef SUPPORT_RMT + if ((r = rmtwrite_with_restart(fd, b, bsz)) <= 0) + break; +#else + if ((r = write_with_restart(fd, b, bsz)) <= 0) + break; +#endif /* SUPPORT_RMT */ + b += r; + bsz -= r; + written += r; + } while (bsz > 0); + + return written ? written : r; } /* @@ -523,14 +730,22 @@ ar_read(char *buf, int cnt) * if last i/o was in error, no more reads until reset or new volume */ if (lstrval <= 0) - return(lstrval); + return lstrval; /* * how we read must be based on device type */ switch (artyp) { +#ifdef SUPPORT_RMT + case ISRMT: + if ((res = rmtread_with_restart(arfd, buf, cnt)) > 0) { + io_ok = 1; + return res; + } + break; +#endif /* SUPPORT_RMT */ case ISTAPE: - if ((res = read(arfd, buf, cnt)) > 0) { + if ((res = read_with_restart(arfd, buf, cnt)) > 0) { /* * CAUTION: tape systems may not always return the same * sized records so we leave blksz == MAXBLK. The @@ -541,10 +756,10 @@ ar_read(char *buf, int cnt) io_ok = 1; if (res != rdblksz) { /* - * Record size changed. If this is happens on + * Record size changed. If this happens on * any record after the first, we probably have * a tape drive which has a fixed record size - * we are getting multiple records in a single + * (we are getting multiple records in a single * read). Watch out for record blocking that * violates pax spec (must be a multiple of * BLKMULT). @@ -553,7 +768,7 @@ ar_read(char *buf, int cnt) if (rdblksz % BLKMULT) invld_rec = 1; } - return(res); + return res; } break; case ISREG: @@ -568,9 +783,9 @@ ar_read(char *buf, int cnt) * and return. Trying to do anything else with them runs the * risk of failure. */ - if ((res = read(arfd, buf, cnt)) > 0) { + if ((res = read_with_restart(arfd, buf, cnt)) > 0) { io_ok = 1; - return(res); + return res; } break; } @@ -582,8 +797,8 @@ ar_read(char *buf, int cnt) if (res < 0) syswarn(1, errno, "Failed read on archive volume %d", arvol); else - paxwarn(0, "End of archive volume %d reached", arvol); - return(res); + tty_warn(0, "End of archive volume %d reached", arvol); + return res; } /* @@ -594,7 +809,7 @@ ar_read(char *buf, int cnt) * Return: * Number of bytes written. 0 indicates end of volume reached and with no * flaws (as best that can be detected). A -1 indicates an unrecoverable - * error in the archive occured. + * error in the archive occurred. */ int @@ -608,12 +823,12 @@ ar_write(char *buf, int bsz) * an archive volume prevent further writes to it. */ if (lstrval <= 0) - return(lstrval); + return lstrval; - if ((res = write(arfd, buf, bsz)) == bsz) { + if ((res = xwrite(arfd, buf, bsz)) == bsz) { wr_trail = 1; io_ok = 1; - return(bsz); + return bsz; } /* * write broke, see what we can do with it. We try to send any partial @@ -628,10 +843,10 @@ ar_write(char *buf, int bsz) case ISREG: if ((res > 0) && (res % BLKMULT)) { /* - * try to fix up partial writes which are not BLKMULT + * try to fix up partial writes which are not BLKMULT * in size by forcing the runt record to next archive * volume - */ + */ if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0) break; cpos -= (off_t)res; @@ -645,22 +860,26 @@ ar_write(char *buf, int bsz) /* * if file is out of space, handle it like a return of 0 */ - if ((errno == ENOSPC) || (errno == EFBIG) + if ((errno == ENOSPC) || (errno == EFBIG)) + res = lstrval = 0; #ifdef EDQUOT - || (errno == EDQUOT) -#endif - ) + if (errno == EDQUOT) res = lstrval = 0; +#endif break; case ISTAPE: case ISCHR: case ISBLK: +#ifdef SUPPORT_RMT + case ISRMT: +#endif /* SUPPORT_RMT */ if (res >= 0) break; if (errno == EACCES) { - paxwarn(0, "Write failed, archive is write protected."); + tty_warn(0, + "Write failed, archive is write protected."); res = lstrval = 0; - return(0); + return 0; } /* * see if we reached the end of media, if so force a change to @@ -696,19 +915,21 @@ ar_write(char *buf, int bsz) * must quit right away. */ if (!wr_trail && (res <= 0)) { - paxwarn(1,"Unable to append, trailer re-write failed. Quitting."); - return(res); + tty_warn(1, + "Unable to append, trailer re-write failed. Quitting."); + return res; } if (res == 0) - paxwarn(0, "End of archive volume %d reached", arvol); + tty_warn(0, "End of archive volume %d reached", arvol); else if (res < 0) syswarn(1, errno, "Failed write to archive volume: %d", arvol); else if (!frmt->blkalgn || ((res % frmt->blkalgn) == 0)) - paxwarn(0,"WARNING: partial archive write. Archive MAY BE FLAWED"); + tty_warn(0, + "WARNING: partial archive write. Archive MAY BE FLAWED"); else - paxwarn(1,"WARNING: partial archive write. Archive IS FLAWED"); - return(res); + tty_warn(1,"WARNING: partial archive write. Archive IS FLAWED"); + return res; } /* @@ -725,25 +946,31 @@ ar_rdsync(void) long fsbz; off_t cpos; off_t mpos; +#ifdef HAVE_SYS_MTIO_H struct mtop mb; +#endif /* - * Fail resync attempts at user request (done) or this is going to be - * an update/append to an existing archive. If last i/o hit media end, - * we need to go to the next volume not try a resync. + * Fail resync attempts at user request (done) or if this is going to be + * an update/append to a existing archive. if last i/o hit media end, + * we need to go to the next volume not try a resync */ if ((done > 0) || (lstrval == 0)) - return(-1); + return -1; if ((act == APPND) || (act == ARCHIVE)) { - paxwarn(1, "Cannot allow updates to an archive with flaws."); - return(-1); + tty_warn(1, "Cannot allow updates to an archive with flaws."); + return -1; } if (io_ok) did_io = 1; switch(artyp) { +#ifdef SUPPORT_RMT + case ISRMT: +#endif /* SUPPORT_RMT */ case ISTAPE: +#ifdef HAVE_SYS_MTIO_H /* * if the last i/o was a successful data transfer, we assume * the fault is just a bad record on the tape that we are now @@ -759,9 +986,21 @@ ar_rdsync(void) } mb.mt_op = MTFSR; mb.mt_count = 1; - if (ioctl(arfd, MTIOCTOP, &mb) < 0) - break; +#ifdef SUPPORT_RMT + if (artyp == ISRMT) { + if (rmtioctl(arfd, MTIOCTOP, &mb) < 0) + break; + } else { +#endif /* SUPPORT_RMT */ + if (ioctl(arfd, MTIOCTOP, &mb) < 0) + break; +#ifdef SUPPORT_RMT + } +#endif /* SUPPORT_RMT */ lstrval = 1; +#else + tty_warn(1, "System does not have tape support"); +#endif break; case ISREG: case ISCHR: @@ -770,10 +1009,7 @@ ar_rdsync(void) * try to step over the bad part of the device. */ io_ok = 0; -#if 0 - /* no blksize on minix */ if (((fsbz = arsb.st_blksize) <= 0) || (artyp != ISREG)) -#endif fsbz = BLKMULT; if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0) break; @@ -791,16 +1027,16 @@ ar_rdsync(void) break; } if (lstrval <= 0) { - paxwarn(1, "Unable to recover from an archive read failure."); - return(-1); + tty_warn(1, "Unable to recover from an archive read failure."); + return -1; } - paxwarn(0, "Attempting to recover from an archive read failure."); - return(0); + tty_warn(0, "Attempting to recover from an archive read failure."); + return 0; } /* * ar_fow() - * Move the I/O position within the archive foward the specified number of + * Move the I/O position within the archive forward the specified number of * bytes as supported by the device. If we cannot move the requested * number of bytes, return the actual number of bytes moved in skipped. * Return: @@ -816,44 +1052,51 @@ ar_fow(off_t sksz, off_t *skipped) *skipped = 0; if (sksz <= 0) - return(0); + return 0; /* - * we cannot move foward at EOF or error + * we cannot move forward at EOF or error */ if (lstrval <= 0) - return(lstrval); + return lstrval; /* * Safer to read forward on devices where it is hard to find the end of * the media without reading to it. With tapes we cannot be sure of the * number of physical blocks to skip (we do not know physical block - * size at this point), so we must only read foward on tapes! + * size at this point), so we must only read forward on tapes! */ - if (artyp != ISREG) - return(0); + if (artyp == ISTAPE || artyp == ISPIPE +#ifdef SUPPORT_RMT + || artyp == ISRMT +#endif /* SUPPORT_RMT */ + ) + return 0; /* * figure out where we are in the archive */ if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) >= 0) { /* - * we can be asked to move farther than there are bytes in this + * we can be asked to move farther than there are bytes in this * volume, if so, just go to file end and let normal buf_fill() * deal with the end of file (it will go to next volume by * itself) - */ - if ((mpos = cpos + sksz) > arsb.st_size) { - *skipped = arsb.st_size - cpos; + */ + mpos = cpos + sksz; + if (artyp == ISREG && mpos > arsb.st_size) mpos = arsb.st_size; - } else - *skipped = sksz; - if (lseek(arfd, mpos, SEEK_SET) >= 0) - return(0); + if ((mpos = lseek(arfd, mpos, SEEK_SET)) >= 0) { + *skipped = mpos - cpos; + return 0; + } + } else { + if (artyp != ISREG) + return 0; /* non-seekable device */ } syswarn(1, errno, "Forward positioning operation on archive failed"); lstrval = -1; - return(-1); + return -1; } /* @@ -871,14 +1114,16 @@ int ar_rev(off_t sksz) { off_t cpos; - struct mtop mb; +#ifdef HAVE_SYS_MTIO_H int phyblk; + struct mtop mb; +#endif /* * make sure we do not have try to reverse on a flawed archive */ if (lstrval < 0) - return(lstrval); + return lstrval; switch(artyp) { case ISPIPE: @@ -887,9 +1132,9 @@ ar_rev(off_t sksz) /* * cannot go backwards on these critters */ - paxwarn(1, "Reverse positioning on pipes is not supported."); + tty_warn(1, "Reverse positioning on pipes is not supported."); lstrval = -1; - return(-1); + return -1; case ISREG: case ISBLK: case ISCHR: @@ -908,13 +1153,13 @@ ar_rev(off_t sksz) syswarn(1, errno, "Unable to obtain current archive byte offset"); lstrval = -1; - return(-1); + return -1; } /* * we may try to go backwards past the start when the archive - * is only a single record. If this hapens and we are on a - * multi volume archive, we need to go to the end of the + * is only a single record. If this happens and we are on a + * multi-volume archive, we need to go to the end of the * previous volume and continue our movement backwards from * there. */ @@ -923,29 +1168,34 @@ ar_rev(off_t sksz) /* * this should never happen */ - paxwarn(1,"Reverse position on previous volume."); + tty_warn(1, + "Reverse position on previous volume."); lstrval = -1; - return(-1); + return -1; } cpos = (off_t)0L; } if (lseek(arfd, cpos, SEEK_SET) < 0) { syswarn(1, errno, "Unable to seek archive backwards"); lstrval = -1; - return(-1); + return -1; } break; case ISTAPE: +#ifdef SUPPORT_RMT + case ISRMT: +#endif /* SUPPORT_RMT */ +#ifdef HAVE_SYS_MTIO_H /* - * Calculate and move the proper number of PHYSICAL tape + * Calculate and move the proper number of PHYSICAL tape * blocks. If the sksz is not an even multiple of the physical * tape size, we cannot do the move (this should never happen). - * (We also cannot handler trailers spread over two vols). + * (We also cannot handle trailers spread over two vols). * get_phys() also makes sure we are in front of the filemark. - */ + */ if ((phyblk = get_phys()) <= 0) { lstrval = -1; - return(-1); + return -1; } /* @@ -965,10 +1215,10 @@ ar_rev(off_t sksz) * ok we have to move. Make sure the tape drive can do it. */ if (sksz % phyblk) { - paxwarn(1, + tty_warn(1, "Tape drive unable to backspace requested amount"); lstrval = -1; - return(-1); + return -1; } /* @@ -976,18 +1226,28 @@ ar_rev(off_t sksz) */ mb.mt_op = MTBSR; mb.mt_count = sksz/phyblk; - if (ioctl(arfd, MTIOCTOP, &mb) < 0) { - syswarn(1,errno, "Unable to backspace tape %d blocks.", - mb.mt_count); + if ( +#ifdef SUPPORT_RMT + rmtioctl(arfd, MTIOCTOP, &mb) +#else + ioctl(arfd, MTIOCTOP, &mb) +#endif /* SUPPORT_RMT */ + < 0) { + syswarn(1, errno, "Unable to backspace tape %ld blocks.", + (long) mb.mt_count); lstrval = -1; - return(-1); + return -1; } +#else + tty_warn(1, "System does not have tape support"); +#endif break; } lstrval = 1; - return(0); + return 0; } +#ifdef HAVE_SYS_MTIO_H /* * get_phys() * Determine the physical block size on a tape drive. We need the physical @@ -1017,11 +1277,17 @@ get_phys(void) * we know we are at file mark when we get back a 0 from * read() */ - while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0) +#ifdef SUPPORT_RMT + while ((res = rmtread_with_restart(arfd, + scbuf, sizeof(scbuf))) > 0) +#else + while ((res = read_with_restart(arfd, + scbuf, sizeof(scbuf))) > 0) +#endif /* SUPPORT_RMT */ padsz += res; if (res < 0) { syswarn(1, errno, "Unable to locate tape filemark."); - return(-1); + return -1; } } @@ -1031,9 +1297,15 @@ get_phys(void) */ mb.mt_op = MTBSF; mb.mt_count = 1; - if (ioctl(arfd, MTIOCTOP, &mb) < 0) { + if ( +#ifdef SUPPORT_RMT + rmtioctl(arfd, MTIOCTOP, &mb) +#else + ioctl(arfd, MTIOCTOP, &mb) +#endif /* SUPPORT_RMT */ + < 0) { syswarn(1, errno, "Unable to backspace over tape filemark."); - return(-1); + return -1; } /* @@ -1042,30 +1314,54 @@ get_phys(void) */ mb.mt_op = MTBSR; mb.mt_count = 1; - if (ioctl(arfd, MTIOCTOP, &mb) < 0) { + if ( +#ifdef SUPPORT_RMT + rmtioctl(arfd, MTIOCTOP, &mb) +#else + ioctl(arfd, MTIOCTOP, &mb) +#endif /* SUPPORT_RMT */ + < 0) { syswarn(1, errno, "Unable to backspace over last tape block."); - return(-1); + return -1; } - if ((phyblk = read(arfd, scbuf, sizeof(scbuf))) <= 0) { + if ((phyblk = +#ifdef SUPPORT_RMT + rmtread_with_restart(arfd, scbuf, sizeof(scbuf)) +#else + read_with_restart(arfd, scbuf, sizeof(scbuf)) +#endif /* SUPPORT_RMT */ + ) <= 0) { syswarn(1, errno, "Cannot determine archive tape blocksize."); - return(-1); + return -1; } /* - * read foward to the file mark, then back up in front of the filemark + * read forward to the file mark, then back up in front of the filemark * (this is a bit paranoid, but should be safe to do). */ - while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0) + while ((res = +#ifdef SUPPORT_RMT + rmtread_with_restart(arfd, scbuf, sizeof(scbuf)) +#else + read_with_restart(arfd, scbuf, sizeof(scbuf)) +#endif /* SUPPORT_RMT */ + ) > 0) ; if (res < 0) { syswarn(1, errno, "Unable to locate tape filemark."); - return(-1); + return -1; } mb.mt_op = MTBSF; mb.mt_count = 1; - if (ioctl(arfd, MTIOCTOP, &mb) < 0) { + if ( +#ifdef SUPPORT_RMT + rmtioctl(arfd, MTIOCTOP, &mb) +#else + ioctl(arfd, MTIOCTOP, &mb) +#endif /* SUPPORT_RMT */ + < 0) { syswarn(1, errno, "Unable to backspace over tape filemark."); - return(-1); + return -1; } /* @@ -1077,15 +1373,15 @@ get_phys(void) * return if there was no padding */ if (padsz == 0) - return(phyblk); + return phyblk; /* * make sure we can move backwards over the padding. (this should * never fail). */ if (padsz % phyblk) { - paxwarn(1, "Tape drive unable to backspace requested amount"); - return(-1); + tty_warn(1, "Tape drive unable to backspace requested amount"); + return -1; } /* @@ -1094,13 +1390,21 @@ get_phys(void) */ mb.mt_op = MTBSR; mb.mt_count = padsz/phyblk; - if (ioctl(arfd, MTIOCTOP, &mb) < 0) { - syswarn(1,errno,"Unable to backspace tape over %d pad blocks", - mb.mt_count); - return(-1); + if ( +#ifdef SUPPORT_RMT + rmtioctl(arfd, MTIOCTOP, &mb) +#else + ioctl(arfd, MTIOCTOP, &mb) +#endif /* SUPPORT_RMT */ + < 0) { + syswarn(1, errno, + "Unable to backspace tape over %ld pad blocks", + (long)mb.mt_count); + return -1; } - return(phyblk); + return phyblk; } +#endif /* * ar_next() @@ -1116,7 +1420,7 @@ int ar_next(void) { char buf[PAXPATHLEN+2]; - static int freeit = 0; + static char *arcfree = NULL; sigset_t o_mask; /* @@ -1130,18 +1434,24 @@ ar_next(void) if (sigprocmask(SIG_SETMASK, &o_mask, NULL) < 0) syswarn(0, errno, "Unable to restore signal mask"); - if (done || !wr_trail || strcmp(NM_TAR, argv0) == 0) - return(-1); + if (done || !wr_trail || force_one_volume) + return -1; - tty_prnt("\nATTENTION! %s archive volume change required.\n", argv0); + if (!is_gnutar) + tty_prnt("\nATTENTION! %s archive volume change required.\n", + argv0); /* * if i/o is on stdin or stdout, we cannot reopen it (we do not know * the name), the user will be forced to type it in. */ - if (strcmp(arcname, stdo) && strcmp(arcname, stdn) && (artyp != ISREG) + if (strcmp(arcname, STDO) && strcmp(arcname, STDN) && (artyp != ISREG) && (artyp != ISPIPE)) { - if (artyp == ISTAPE) { + if (artyp == ISTAPE +#ifdef SUPPORT_RMT + || artyp == ISRMT +#endif /* SUPPORT_RMT */ + ) { tty_prnt("%s ready for archive tape volume: %d\n", arcname, arvol); tty_prnt("Load the NEXT TAPE on the tape drive"); @@ -1168,7 +1478,7 @@ ar_next(void) lstrval = -1; tty_prnt("Quitting %s!\n", argv0); vfpart = 0; - return(-1); + return -1; } if ((buf[0] == '\0') || (buf[1] != '\0')) { @@ -1183,7 +1493,7 @@ ar_next(void) * we are to continue with the same device */ if (ar_open(arcname) >= 0) - return(0); + return 0; tty_prnt("Cannot re-open %s, try again\n", arcname); continue; @@ -1200,8 +1510,13 @@ ar_next(void) } break; } - } else + } else { + if (is_gnutar) { + tty_warn(1, "Unexpected EOF on archive file"); + return -1; + } tty_prnt("Ready for archive volume: %d\n", arvol); + } /* * have to go to a different archive @@ -1215,7 +1530,7 @@ ar_next(void) lstrval = -1; tty_prnt("Quitting %s!\n", argv0); vfpart = 0; - return(-1); + return -1; } if (buf[0] == '\0') { tty_prnt("Empty file name, try again\n"); @@ -1234,32 +1549,33 @@ ar_next(void) * try to open new archive */ if (ar_open(buf) >= 0) { - if (freeit) { - (void)free((char *)(uintptr_t)arcname); - freeit = 0; + if (arcfree) { + (void)free(arcfree); + arcfree = NULL; } - if ((arcname = strdup(buf)) == NULL) { + if ((arcfree = strdup(buf)) == NULL) { done = 1; lstrval = -1; - paxwarn(0, "Cannot save archive name."); - return(-1); + tty_warn(0, "Cannot save archive name."); + return -1; } - freeit = 1; + arcname = arcfree; break; } tty_prnt("Cannot open %s, try again\n", buf); continue; } - return(0); + return 0; } /* * ar_start_gzip() - * starts the gzip compression/decompression process as a child, using magic - * to keep the fd the same in the calling function (parent). + * starts the compression/decompression process as a child, using magic + * to keep the fd the same in the calling function (parent). possible + * programs are GZIP_CMD, BZIP2_CMD, and COMPRESS_CMD. */ -static void -ar_start_gzip(int fd, const char *gzip_prog, int wr) +void +ar_start_gzip(int fd, const char *gzp, int wr) { int fds[2]; const char *gzip_flags; @@ -1290,9 +1606,122 @@ ar_start_gzip(int fd, const char *gzip_prog, int wr) } close(fds[0]); close(fds[1]); - if (execlp(gzip_prog, gzip_prog, gzip_flags, - (char *)NULL) < 0) + if (execlp(gzp, gzp, gzip_flags, NULL) < 0) err(1, "could not exec"); /* NOTREACHED */ } } + +static const char * +timefmt(char *buf, size_t size, off_t sz, time_t tm, const char *unitstr) +{ + (void)snprintf(buf, size, "%lu secs (" OFFT_F " %s/sec)", + (unsigned long)tm, (OFFT_T)(sz / tm), unitstr); + return buf; +} + +static const char * +sizefmt(char *buf, size_t size, off_t sz) +{ + (void)snprintf(buf, size, OFFT_F " bytes", (OFFT_T)sz); + return buf; +} + +void +ar_summary(int n) +{ + time_t secs; + int len; + char buf[BUFSIZ]; + char tbuf[MAXPATHLEN/4]; /* XXX silly size! */ + char s1buf[MAXPATHLEN/8]; /* XXX very silly size! */ + char s2buf[MAXPATHLEN/8]; /* XXX very silly size! */ + FILE *outf; + + if (act == LIST) + outf = stdout; + else + outf = stderr; + + /* + * If we are called from a signal (n != 0), use snprintf(3) so that we + * don't reenter stdio(3). + */ + (void)time(&secs); + if ((secs -= starttime) == 0) + secs = 1; + + /* + * If we have not determined the format yet, we just say how many bytes + * we have skipped over looking for a header to id. there is no way we + * could have written anything yet. + */ + if (frmt == NULL && act != COPY) { + len = snprintf(buf, sizeof(buf), + "unknown format, %s skipped in %s\n", + sizefmt(s1buf, sizeof(s1buf), rdcnt), + timefmt(tbuf, sizeof(tbuf), rdcnt, secs, "bytes")); + if (n == 0) + (void)fprintf(outf, "%s: %s", argv0, buf); + else + (void)write(STDERR_FILENO, buf, len); + return; + } + + + if (n != 0 && *archd.name) { + len = snprintf(buf, sizeof(buf), "Working on `%s' (%s)\n", + archd.name, sizefmt(s1buf, sizeof(s1buf), archd.sb.st_size)); + (void)write(STDERR_FILENO, buf, len); + len = 0; + } + + + if (act == COPY) { + len = snprintf(buf, sizeof(buf), + "%lu files in %s\n", + (unsigned long)flcnt, + timefmt(tbuf, sizeof(tbuf), flcnt, secs, "files")); + } else { + len = snprintf(buf, sizeof(buf), + "%s vol %d, %lu files, %s read, %s written in %s\n", + frmt->name, arvol-1, (unsigned long)flcnt, + sizefmt(s1buf, sizeof(s1buf), rdcnt), + sizefmt(s2buf, sizeof(s2buf), wrcnt), + timefmt(tbuf, sizeof(tbuf), rdcnt + wrcnt, secs, "bytes")); + } + if (n == 0) + (void)fprintf(outf, "%s: %s", argv0, buf); + else + (void)write(STDERR_FILENO, buf, strlen(buf)); +} + +/* + * ar_dochdir(name) + * change directory to name, and remember where we came from and + * where we change to (for ar_open). + * + * Maybe we could try to be smart and only do the actual chdir + * when necessary to write a file read from the archive, but this + * is not easy to get right given the pax code structure. + * + * Be sure to not leak descriptors! + * + * We are called N * M times when extracting, and N times when + * writing archives, where + * N: number of -C options + * M: number of files in archive + * + * Returns 0 if all went well, else -1. + */ + +int +ar_dochdir(const char *name) +{ + /* First fdochdir() back... */ + if (fdochdir(cwdfd) == -1) + return -1; + if (dochdir(name) == -1) + return -1; + return 0; +} diff --git a/commands/pax/ar_subs.c b/bin/pax/ar_subs.c similarity index 77% rename from commands/pax/ar_subs.c rename to bin/pax/ar_subs.c index c78b2173b..f77cc815b 100644 --- a/commands/pax/ar_subs.c +++ b/bin/pax/ar_subs.c @@ -1,3 +1,5 @@ +/* $NetBSD: ar_subs.c,v 1.56 2011/08/31 16:24:54 plunky Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,29 +33,43 @@ * SUCH DAMAGE. */ -#ifndef lint +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) #if 0 static char sccsid[] = "@(#)ar_subs.c 8.2 (Berkeley) 4/18/94"; +#else +__RCSID("$NetBSD: ar_subs.c,v 1.56 2011/08/31 16:24:54 plunky Exp $"); #endif #endif /* not lint */ #include #include #include +#include #include #include -#include #include +#include #include #include +#include #include #include #include "pax.h" +#include "pat_rep.h" #include "extern.h" -static void wr_archive(ARCHD *, int is_app); +static int path_check(ARCHD *, int); +static int wr_archive(ARCHD *, int is_app); static int get_arc(void); static int next_head(ARCHD *); +#if !HAVE_NBTOOL_CONFIG_H && !defined(__minix) +static int fdochroot(int); +#endif extern sigset_t s_mask; /* @@ -63,19 +79,124 @@ extern sigset_t s_mask; static char hdbuf[BLKMULT]; /* space for archive header on read */ u_long flcnt; /* number of files processed */ +ARCHD archd; + +static char cwdpath[MAXPATHLEN]; /* current working directory path */ +static size_t cwdpathlen; /* current working directory path len */ + +int +updatepath(void) +{ + if (getcwd(cwdpath, sizeof(cwdpath)) == NULL) { + syswarn(1, errno, "Cannot get working directory"); + return -1; + } + cwdpathlen = strlen(cwdpath); + return 0; +} + +int +fdochdir(int fcwd) +{ + if (fchdir(fcwd) == -1) { + syswarn(1, errno, "Cannot chdir to `.'"); + return -1; + } + return updatepath(); +} + +int +dochdir(const char *name) +{ + if (chdir(name) == -1) + syswarn(1, errno, "Cannot chdir to `%s'", name); + return updatepath(); +} + +#if !HAVE_NBTOOL_CONFIG_H && !defined(__minix) +static int +fdochroot(int fcwd) +{ + if (fchroot(fcwd) != 0) { + syswarn(1, errno, "Can't fchroot to \".\""); + return -1; + } + return updatepath(); +} +#endif + +/* + * mkdir(), but if we failed, check if someone else made it for us + * already and don't error out. + */ +int +domkdir(const char *fname, mode_t mode) +{ + int error; + struct stat sb; + + if ((error = mkdir(fname, mode)) != -1) + return error; + + switch (errno) { + case EISDIR: + return 0; + case EEXIST: + case EACCES: + case ENOSYS: /* Grr Solaris */ + case EROFS: + error = errno; + if (stat(fname, &sb) != -1 && S_ISDIR(sb.st_mode)) + return 0; + errno = error; + /*FALLTHROUGH*/ + default: + return -1; + } +} + +static int +path_check(ARCHD *arcn, int level) +{ + char buf[MAXPATHLEN]; + char *p; + + if ((p = strrchr(arcn->name, '/')) == NULL) + return 0; + *p = '\0'; + + if (realpath(arcn->name, buf) == NULL) { + int error; + error = path_check(arcn, level + 1); + *p = '/'; + if (error == 0) + return 0; + if (level == 0) + syswarn(1, 0, "Cannot resolve `%s'", arcn->name); + return -1; + } + if (strncmp(buf, cwdpath, cwdpathlen) != 0) { + *p = '/'; + syswarn(1, 0, "Attempt to write file `%s' that resolves into " + "`%s/%s' outside current working directory `%s' ignored", + arcn->name, buf, p + 1, cwdpath); + return -1; + } + *p = '/'; + return 0; +} /* * list() * list the contents of an archive which match user supplied pattern(s) - * (no pattern matches all). + * (if no pattern is supplied, list entire contents). */ -void +int list(void) { ARCHD *arcn; int res; - ARCHD archd; time_t now; arcn = &archd; @@ -88,10 +209,7 @@ list(void) */ if ((get_arc() < 0) || ((*frmt->options)() < 0) || ((*frmt->st_rd)() < 0)) - return; - - if (vflag && ((uidtb_start() < 0) || (gidtb_start() < 0))) - return; + return 1; now = time(NULL); @@ -99,6 +217,16 @@ list(void) * step through the archive until the format says it is done */ while (next_head(arcn) == 0) { + if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) { + /* + * we need to read, to get the real filename + */ + off_t cnt; + if (!(*frmt->rd_data)(arcn, -arcn->type, &cnt)) + (void)rd_skip(cnt + arcn->pad); + continue; + } + /* * check for pattern, and user specified options match. * When all patterns are matched we are done. @@ -117,12 +245,25 @@ list(void) * modify the name as requested by the user if name * survives modification, do a listing of the file */ - if ((res = mod_name(arcn)) < 0) + if ((res = mod_name(arcn, RENM)) < 0) break; - if (res == 0) + if (res == 0) { + if (arcn->name[0] == '/' && !check_Aflag()) { + memmove(arcn->name, arcn->name + 1, + strlen(arcn->name)); + } ls_list(arcn, now, stdout); + } + /* + * if there's an error writing to stdout then we must + * stop now -- we're probably writing to a pipe that + * has been closed by the reader. + */ + if (ferror(stdout)) { + syswarn(1, errno, "Listing incomplete."); + break; + } } - /* * skip to next archive format header using values calculated * by the format header read routine @@ -139,6 +280,8 @@ list(void) (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); ar_close(); pat_chk(); + + return 0; } /* @@ -147,13 +290,12 @@ list(void) * pattern(s) (no patterns extracts all members) */ -void +int extract(void) { ARCHD *arcn; int res; off_t cnt; - ARCHD archd; struct stat sb; int fd; time_t now; @@ -166,22 +308,36 @@ extract(void) */ if ((get_arc() < 0) || ((*frmt->options)() < 0) || ((*frmt->st_rd)() < 0) || (dir_start() < 0)) - return; + return 1; + + now = time(NULL); +#if !HAVE_NBTOOL_CONFIG_H && !defined(__minix) + if (do_chroot) + (void)fdochroot(cwdfd); +#endif /* * When we are doing interactive rename, we store the mapping of names * so we can fix up hard links files later in the archive. */ if (iflag && (name_start() < 0)) - return; - - now = time(NULL); + return 1; /* * step through each entry on the archive until the format read routine * says it is done */ while (next_head(arcn) == 0) { + int write_to_hard_link = 0; + + if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) { + /* + * we need to read, to get the real filename + */ + if (!(*frmt->rd_data)(arcn, -arcn->type, &cnt)) + (void)rd_skip(cnt + arcn->pad); + continue; + } /* * check for pattern, and user specified options match. When @@ -192,22 +348,28 @@ extract(void) if ((res > 0) || (sel_chk(arcn) != 0)) { /* - * file is not selected. skip past any file data and - * padding and go back for the next archive member + * file is not selected. skip past any file + * data and padding and go back for the next + * archive member */ (void)rd_skip(arcn->skip + arcn->pad); continue; } + if (kflag && (lstat(arcn->name, &sb) == 0)) { + (void)rd_skip(arcn->skip + arcn->pad); + continue; + } + /* * with -u or -D only extract when the archive member is newer - * than the file with the same name in the file system (nos + * than the file with the same name in the file system (no * test of being the same type is required). * NOTE: this test is done BEFORE name modifications as * specified by pax. this operation can be confusing to the * user who might expect the test to be done on an existing * file AFTER the name mod. In honesty the pax spec is probably - * flawed in this respect. + * flawed in this respect. ignore this for GNU long links. */ if ((uflag || Dflag) && ((lstat(arcn->name, &sb) == 0))) { if (uflag && Dflag) { @@ -230,7 +392,7 @@ extract(void) /* * this archive member is now been selected. modify the name. */ - if ((pat_sel(arcn) < 0) || ((res = mod_name(arcn)) < 0)) + if ((pat_sel(arcn) < 0) || ((res = mod_name(arcn, RENM)) < 0)) break; if (res > 0) { /* @@ -241,9 +403,12 @@ extract(void) continue; } + if (arcn->name[0] == '/' && !check_Aflag()) { + memmove(arcn->name, arcn->name + 1, strlen(arcn->name)); + } /* * Non standard -Y and -Z flag. When the existing file is - * same age or newer skip + * same age or newer skip; ignore this for GNU long links. */ if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) { if (Yflag && Zflag) { @@ -267,7 +432,7 @@ extract(void) if (vflag > 1) ls_list(arcn, now, listf); else { - (void)fputs(arcn->name, listf); + (void)safe_print(arcn->name, listf); vfpart = 1; } } @@ -275,11 +440,16 @@ extract(void) /* * 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); + if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL) && + !to_stdout) + dochdir(arcn->pat->chdname); + if (secure && path_check(arcn, 0) != 0) { + (void)rd_skip(arcn->skip + arcn->pad); + continue; + } + + /* * all ok, extract this member based on type */ @@ -289,36 +459,46 @@ extract(void) * throw out padding and any data that might follow the * header (as determined by the format). */ - if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) - res = lnk_creat(arcn); + if ((arcn->type == PAX_HLK) || + (arcn->type == PAX_HRG)) + res = lnk_creat(arcn, &write_to_hard_link); else res = node_creat(arcn); - (void)rd_skip(arcn->skip + arcn->pad); - if (res < 0) - purg_lnk(arcn); + if (!write_to_hard_link) { + (void)rd_skip(arcn->skip + arcn->pad); + if (res < 0) + purg_lnk(arcn); - if (vflag && vfpart) { - (void)putc('\n', listf); - vfpart = 0; + if (vflag && vfpart) { + (void)putc('\n', listf); + vfpart = 0; + } + continue; } - continue; } - /* - * we have a file with data here. If we can not create it, skip - * over the data and purge the name from hard link table - */ - if ((fd = file_creat(arcn)) < 0) { - (void)rd_skip(arcn->skip + arcn->pad); - purg_lnk(arcn); - continue; + if (to_stdout) + fd = STDOUT_FILENO; + else { + /* + * We have a file with data here. If we cannot create + * it, skip over the data and purge the name from hard + * link table. + */ + if ((fd = file_creat(arcn, write_to_hard_link)) < 0) { + (void)fflush(listf); + (void)rd_skip(arcn->skip + arcn->pad); + purg_lnk(arcn); + continue; + } } /* * extract the file from the archive and skip over padding and * any unprocessed data */ res = (*frmt->rd_data)(arcn, fd, &cnt); - file_close(arcn, fd); + if (!to_stdout) + file_close(arcn, fd); if (vflag && vfpart) { (void)putc('\n', listf); vfpart = 0; @@ -330,9 +510,7 @@ extract(void) * 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"); + fdochdir(cwdfd); } /* @@ -345,6 +523,8 @@ extract(void) ar_close(); proc_dir(); pat_chk(); + + return 0; } /* @@ -353,7 +533,7 @@ extract(void) * previously written archive. */ -static void +static int wr_archive(ARCHD *arcn, int is_app) { int res; @@ -369,29 +549,29 @@ wr_archive(ARCHD *arcn, int is_app) * that detects them. */ if (((hlk = frmt->hlk) == 1) && (lnk_start() < 0)) - return; + return 1; /* * start up the file traversal code and format specific write */ if ((ftree_start() < 0) || ((*frmt->st_wr)() < 0)) - return; + return 1; wrf = frmt->wr; + now = time(NULL); + /* * When we are doing interactive rename, we store the mapping of names * so we can fix up hard links files later in the archive. */ if (iflag && (name_start() < 0)) - return; + return 1; /* - * if this not append, and there are no files, we do no write a trailer + * if this is not append, and there are no files, we do no write a trailer */ wr_one = is_app; - now = time(NULL); - /* * while there are files to archive, process them one at at time */ @@ -399,10 +579,18 @@ wr_archive(ARCHD *arcn, int is_app) /* * check if this file meets user specified options match. */ - if (sel_chk(arcn) != 0) { - ftree_notsel(); + if (sel_chk(arcn) != 0) + continue; + /* + * Here we handle the exclusion -X gnu style patterns which + * are implemented like a pattern list. We don't modify the + * name as this will be done below again, and we don't want + * to double modify it. + */ + if ((res = mod_name(arcn, 0)) < 0) + break; + if (res == 1) continue; - } fd = -1; if (uflag) { /* @@ -432,7 +620,7 @@ wr_archive(ARCHD *arcn, int is_app) * the link table). */ if ((fd = open(arcn->org_name, O_RDONLY, 0)) < 0) { - syswarn(1,errno, "Unable to open %s to read", + syswarn(1, errno, "Unable to open %s to read", arcn->org_name); purg_lnk(arcn); continue; @@ -442,7 +630,7 @@ wr_archive(ARCHD *arcn, int is_app) /* * Now modify the name as requested by the user */ - if ((res = mod_name(arcn)) < 0) { + if ((res = mod_name(arcn, RENM)) < 0) { /* * name modification says to skip this file, close the * file and purge link table entry @@ -452,6 +640,10 @@ wr_archive(ARCHD *arcn, int is_app) break; } + if (arcn->name[0] == '/' && !check_Aflag()) { + memmove(arcn->name, arcn->name + 1, strlen(arcn->name)); + } + if ((res > 0) || (docrc && (set_crc(arcn, fd) < 0))) { /* * unable to obtain the crc we need, close the file, @@ -466,7 +658,7 @@ wr_archive(ARCHD *arcn, int is_app) if (vflag > 1) ls_list(arcn, now, listf); else { - (void)fputs(arcn->name, listf); + (void)safe_print(arcn->name, listf); vfpart = 1; } } @@ -534,6 +726,8 @@ wr_archive(ARCHD *arcn, int is_app) if (tflag) proc_dir(); ftree_chk(); + + return 0; } /* @@ -553,17 +747,16 @@ wr_archive(ARCHD *arcn, int is_app) * It is really difficult to splice in members without either re-writing * the entire archive (from the point were the old version was), or having * assistance of the format specification in terms of a special update - * header that invalidates a previous archive record. The POSIX spec left + * header that invalidates a previous archive record. The posix spec left * the method used to implement -u unspecified. This pax is able to * over write existing files that it creates. */ -void +int append(void) { ARCHD *arcn; int res; - ARCHD archd; FSUB *orgfrmt; int udev; off_t tlen; @@ -576,25 +769,25 @@ append(void) * different format than the user specified format. */ if (get_arc() < 0) - return; + return 1; if ((orgfrmt != NULL) && (orgfrmt != frmt)) { - paxwarn(1, "Cannot mix current archive format %s with %s", + tty_warn(1, "Cannot mix current archive format %s with %s", frmt->name, orgfrmt->name); - return; + return 1; } /* * pass the format any options and start up format */ if (((*frmt->options)() < 0) || ((*frmt->st_rd)() < 0)) - return; + return 1; /* * if we only are adding members that are newer, we need to save the * mod times for all files we see. */ if (uflag && (ftime_start() < 0)) - return; + return 1; /* * some archive formats encode hard links by recording the device and @@ -611,12 +804,12 @@ append(void) * header. See the remap routines for more details. */ if ((udev = frmt->udev) && (dev_start() < 0)) - return; + return 1; /* * reading the archive may take a long time. If verbose tell the user */ - if (vflag) { + if (vflag || Vflag) { (void)fprintf(listf, "%s: Reading archive to position at the end...", argv0); vfpart = 1; @@ -673,20 +866,31 @@ append(void) * we will refuse to write */ if (appnd_start(tlen) < 0) - return; + return 1; /* * tell the user we are done reading. */ - if (vflag && vfpart) { - (void)fputs("done.\n", listf); + if ((vflag || Vflag) && vfpart) { + (void)safe_print("done.\n", listf); vfpart = 0; } /* * go to the writing phase to add the new members */ - wr_archive(arcn, 1); + res = wr_archive(arcn, 1); + if (res == 1) { + /* + * wr_archive failed in some way, but before any files were + * added. These are the only steps needed to cleanup (and + * not truncate the archive). + */ + wr_fin(); + (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); + ar_close(); + } + return res; } /* @@ -694,10 +898,9 @@ append(void) * write a new archive */ -void +int archive(void) { - ARCHD archd; /* * if we only are adding members that are newer, we need to save the @@ -705,11 +908,11 @@ archive(void) * options write the archive */ if ((uflag && (ftime_start() < 0)) || (wr_start() < 0)) - return; + return 1; if ((*frmt->options)() < 0) - return; + return 1; - wr_archive(&archd, 0); + return wr_archive(&archd, 0); } /* @@ -720,18 +923,17 @@ archive(void) * (except the files are forced to be under the destination directory). */ -void +int copy(void) { ARCHD *arcn; int res; int fddest; char *dest_pt; - int dlen; - int drem; + size_t dlen; + size_t drem; int fdsrc = -1; struct stat sb; - ARCHD archd; char dirbuf[PAXPATHLEN+1]; arcn = &archd; @@ -739,7 +941,12 @@ copy(void) * set up the destination dir path and make sure it is a directory. We * make sure we have a trailing / on the destination */ - dlen = l_strncpy(dirbuf, dirptr, sizeof(dirbuf) - 1); + dlen = strlcpy(dirbuf, dirptr, sizeof(dirbuf)); + if (dlen >= sizeof(dirbuf) || + (dlen == sizeof(dirbuf) - 1 && dirbuf[dlen - 1] != '/')) { + tty_warn(1, "directory name is too long %s", dirptr); + return 1; + } dest_pt = dirbuf + dlen; if (*(dest_pt-1) != '/') { *dest_pt++ = '/'; @@ -751,11 +958,11 @@ copy(void) if (stat(dirptr, &sb) < 0) { syswarn(1, errno, "Cannot access destination directory %s", dirptr); - return; + return 1; } if (!S_ISDIR(sb.st_mode)) { - paxwarn(1, "Destination is not a directory %s", dirptr); - return; + tty_warn(1, "Destination is not a directory %s", dirptr); + return 1; } /* @@ -763,14 +970,14 @@ copy(void) * modification time and access mode database */ if ((lnk_start() < 0) || (ftree_start() < 0) || (dir_start() < 0)) - return; + return 1; /* * When we are doing interactive rename, we store the mapping of names * so we can fix up hard links files later in the archive. */ if (iflag && (name_start() < 0)) - return; + return 1; /* * set up to cp file trees @@ -786,10 +993,8 @@ copy(void) /* * check if this file meets user specified options */ - if (sel_chk(arcn) != 0) { - ftree_notsel(); + if (sel_chk(arcn) != 0) continue; - } /* * if there is already a file in the destination directory with @@ -805,17 +1010,12 @@ copy(void) /* * create the destination name */ - if (*(arcn->name) == '/') - res = 1; - else - res = 0; - if ((arcn->nlen - res) > drem) { - paxwarn(1, "Destination pathname too long %s", + if (strlcpy(dest_pt, arcn->name + (*arcn->name == '/'), + drem + 1) > drem) { + tty_warn(1, "Destination pathname too long %s", arcn->name); continue; } - (void)strncpy(dest_pt, arcn->name + res, drem); - dirbuf[PAXPATHLEN] = '\0'; /* * if existing file is same age or newer skip @@ -823,10 +1023,10 @@ copy(void) res = lstat(dirbuf, &sb); *dest_pt = '\0'; - if (res == 0) { + if (res == 0) { if (uflag && Dflag) { if ((arcn->sb.st_mtime<=sb.st_mtime) && - (arcn->sb.st_ctime<=sb.st_ctime)) + (arcn->sb.st_ctime<=sb.st_ctime)) continue; } else if (Dflag) { if (arcn->sb.st_ctime <= sb.st_ctime) @@ -842,7 +1042,7 @@ copy(void) * user; set the final destination. */ ftree_sel(arcn); - if ((chk_lnk(arcn) < 0) || ((res = mod_name(arcn)) < 0)) + if ((chk_lnk(arcn) < 0) || ((res = mod_name(arcn, RENM)) < 0)) break; if ((res > 0) || (set_dest(arcn, dirbuf, dlen) < 0)) { /* @@ -869,7 +1069,7 @@ copy(void) } if (vflag) { - (void)fputs(arcn->name, listf); + (void)safe_print(arcn->name, listf); vfpart = 1; } ++flcnt; @@ -897,10 +1097,14 @@ copy(void) /* * create a link or special file */ - if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) - res = lnk_creat(arcn); - else + if ((arcn->type == PAX_HLK) || + (arcn->type == PAX_HRG)) { + int payload; + + res = lnk_creat(arcn, &payload); + } else { res = node_creat(arcn); + } if (res < 0) purg_lnk(arcn); if (vflag && vfpart) { @@ -920,7 +1124,7 @@ copy(void) purg_lnk(arcn); continue; } - if ((fddest = file_creat(arcn)) < 0) { + if ((fddest = file_creat(arcn, 0)) < 0) { rdfile_close(arcn, &fdsrc); purg_lnk(arcn); continue; @@ -948,6 +1152,8 @@ copy(void) ar_close(); proc_dir(); ftree_chk(); + + return 0; } /* @@ -977,7 +1183,7 @@ next_head(ARCHD *arcn) int res; int shftsz; int hsz; - int in_resync = 0; /* set when we are in resync mode */ + 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. */ @@ -1005,7 +1211,7 @@ next_head(ARCHD *arcn) * them, so exit gracefully. */ if (first && ret == 0) - return(-1); + return -1; first = 0; /* @@ -1013,16 +1219,18 @@ next_head(ARCHD *arcn) * storage device, better give the user the bad news. */ if ((ret == 0) || (rd_sync() < 0)) { - paxwarn(1,"Premature end of file on archive read"); - return(-1); + tty_warn(1, + "Premature end of file on archive read"); + return -1; } if (!in_resync) { if (act == APPND) { - paxwarn(1, + tty_warn(1, "Archive I/O error, cannot continue"); - return(-1); + return -1; } - paxwarn(1,"Archive I/O error. Trying to recover."); + tty_warn(1, + "Archive I/O error. Trying to recover."); ++in_resync; } @@ -1052,12 +1260,12 @@ next_head(ARCHD *arcn) /* * this format has trailers outside of valid headers */ - if ((ret = (*frmt->trail_tar)(hdbuf,in_resync,&cnt)) == 0){ + if ((ret = (*frmt->trail)(hdbuf,in_resync,&cnt)) == 0){ /* * valid trailer found, drain input as required */ ar_drain(); - return(-1); + return -1; } if (ret == 1) { @@ -1083,10 +1291,12 @@ next_head(ARCHD *arcn) */ if (!in_resync) { if (act == APPND) { - paxwarn(1,"Unable to append, archive header flaw"); - return(-1); + tty_warn(1, + "Unable to append, archive header flaw"); + return -1; } - paxwarn(1,"Invalid header, starting valid header search."); + tty_warn(1, + "Invalid header, starting valid header search."); ++in_resync; } memmove(hdbuf, hdbuf+1, shftsz); @@ -1096,18 +1306,19 @@ next_head(ARCHD *arcn) /* * ok got a valid header, check for trailer if format encodes it in the - * the header. + * the header. NOTE: the parameters are different than trailer routines + * which encode trailers outside of the header! */ - if (frmt->inhead && ((*frmt->trail_cpio)(arcn) == 0)) { + if (frmt->inhead && ((*frmt->subtrail)(arcn) == 0)) { /* * valid trailer found, drain input as required */ ar_drain(); - return(-1); + return -1; } ++flcnt; - return(0); + return 0; } /* @@ -1139,7 +1350,7 @@ get_arc(void) minhd = fsub[ford[i]].hsz; } if (rd_start() < 0) - return(-1); + return -1; res = BLKMULT; hdsz = 0; hdend = hdbuf; @@ -1171,8 +1382,9 @@ get_arc(void) hdend = hdbuf; if (!notice) { if (act == APPND) - return(-1); - paxwarn(1,"Cannot identify format. Searching..."); + return -1; + tty_warn(1, + "Cannot identify format. Searching..."); ++notice; } } @@ -1197,7 +1409,7 @@ get_arc(void) * adding all the special case code is far worse. */ pback(hdbuf, hdsz); - return(0); + return 0; } /* @@ -1206,8 +1418,8 @@ get_arc(void) */ if (!notice) { if (act == APPND) - return(-1); - paxwarn(1, "Cannot identify format. Searching..."); + return -1; + tty_warn(1, "Cannot identify format. Searching..."); ++notice; } @@ -1232,6 +1444,6 @@ get_arc(void) /* * we cannot find a header, bow, apologize and quit */ - paxwarn(1, "Sorry, unable to determine archive format."); - return(-1); + tty_warn(1, "Sorry, unable to determine archive format."); + return -1; } diff --git a/commands/pax/buf_subs.c b/bin/pax/buf_subs.c similarity index 85% rename from commands/pax/buf_subs.c rename to bin/pax/buf_subs.c index 0eb53727d..d4c27514d 100644 --- a/commands/pax/buf_subs.c +++ b/bin/pax/buf_subs.c @@ -1,3 +1,5 @@ +/* $NetBSD: buf_subs.c,v 1.28 2007/04/29 20:23:34 msaitoh Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,17 +33,27 @@ * SUCH DAMAGE. */ -#ifndef lint +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) #if 0 static char sccsid[] = "@(#)buf_subs.c 8.2 (Berkeley) 4/18/94"; +#else +__RCSID("$NetBSD: buf_subs.c,v 1.28 2007/04/29 20:23:34 msaitoh Exp $"); #endif #endif /* not lint */ #include +#include #include +#include +#include +#include #include #include -#include #include #include #include "pax.h" @@ -92,19 +104,14 @@ wr_start(void) if (!wrblksz) wrblksz = frmt->bsz; if (wrblksz > MAXBLK) { - paxwarn(1, "Write block size of %d too large, maximum is: %d", + tty_warn(1, "Write block size of %d too large, maximum is: %d", wrblksz, MAXBLK); - return(-1); + return -1; } if (wrblksz % BLKMULT) { - paxwarn(1, "Write block size of %d is not a %d byte multiple", + tty_warn(1, "Write block size of %d is not a %d byte multiple", 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); + return -1; } /* @@ -112,11 +119,11 @@ wr_start(void) */ blksz = rdblksz = wrblksz; if ((ar_open(arcname) < 0) && (ar_next() < 0)) - return(-1); + return -1; wrcnt = 0; bufend = buf + wrblksz; bufpt = buf; - return(0); + return 0; } /* @@ -137,14 +144,16 @@ rd_start(void) buf = &(bufmem[BLKMULT]); if ((act == APPND) && wrblksz) { if (wrblksz > MAXBLK) { - paxwarn(1,"Write block size %d too large, maximum is: %d", - wrblksz, MAXBLK); - return(-1); + tty_warn(1, + "Write block size %d too large, maximum is: %d", + wrblksz, MAXBLK); + return -1; } if (wrblksz % BLKMULT) { - paxwarn(1, "Write block size %d is not a %d byte multiple", - wrblksz, BLKMULT); - return(-1); + tty_warn(1, + "Write block size %d is not a %d byte multiple", + wrblksz, BLKMULT); + return -1; } } @@ -152,11 +161,11 @@ rd_start(void) * open the archive */ if ((ar_open(arcname) < 0) && (ar_next() < 0)) - return(-1); + return -1; bufend = buf + rdblksz; bufpt = bufend; rdcnt = 0; - return(0); + return 0; } /* @@ -180,13 +189,13 @@ cp_start(void) * the start of the header of the first file added to the archive. The * format specific end read function tells us how many bytes to move * backwards in the archive to be positioned BEFORE the trailer. Two - * different postions have to be adjusted, the O.S. file offset (e.g. the + * different positions have to be adjusted, the O.S. file offset (e.g. the * position of the tape head) and the write point within the data we have * stored in the read (soon to become write) buffer. We may have to move * back several records (the number depends on the size of the archive * record and the size of the format trailer) to read up the record where * the first byte of the trailer is recorded. Trailers may span (and - * overlap) record boundries. + * overlap) record boundaries. * We first calculate which record has the first byte of the trailer. We * move the OS file offset back to the start of this record and read it * up. We set the buffer write pointer to be at this byte (the byte where @@ -194,9 +203,9 @@ cp_start(void) * start of this record so a flush of this buffer will replace the record * in the archive. * A major problem is rewriting this last record. For archives stored - * on disk files, this is trival. However, many devices are really picky + * on disk files, this is trivial. However, many devices are really picky * about the conditions under which they will allow a write to occur. - * Often devices restrict the conditions where writes can be made writes, + * Often devices restrict the conditions where writes can be made, * so it may not be feasable to append archives stored on all types of * devices. * Return: @@ -210,8 +219,8 @@ appnd_start(off_t skcnt) off_t cnt; if (exit_val != 0) { - paxwarn(0, "Cannot append to an archive that may have flaws."); - return(-1); + tty_warn(0, "Cannot append to an archive that may have flaws."); + return -1; } /* * if the user did not specify a write blocksize, inherit the size used @@ -227,7 +236,7 @@ appnd_start(off_t skcnt) * make sure that this volume allows appends */ if (ar_app_ok() < 0) - return(-1); + return -1; /* * Calculate bytes to move back and move in front of record where we @@ -282,15 +291,15 @@ appnd_start(off_t skcnt) * ARCHIVE mode (write) conditions */ if (ar_set_wr() < 0) - return(-1); + return -1; act = ARCHIVE; - return(0); + return 0; out: - paxwarn(1, "Unable to rewrite archive trailer, cannot append."); - return(-1); + tty_warn(1, "Unable to rewrite archive trailer, cannot append."); + return -1; } - + /* * rd_sync() * A read error occurred on this archive volume. Resync the buffer and @@ -312,10 +321,11 @@ rd_sync(void) * if the user says bail out on first fault, we are out of here... */ if (maxflt == 0) - return(-1); + return -1; if (act == APPND) { - paxwarn(1, "Unable to append when there are archive read errors."); - return(-1); + tty_warn(1, + "Unable to append when there are archive read errors."); + return -1; } /* @@ -323,7 +333,7 @@ rd_sync(void) */ if (ar_rdsync() < 0) { if (ar_next() < 0) - return(-1); + return -1; else rdcnt = 0; } @@ -336,19 +346,20 @@ rd_sync(void) bufpt = buf; bufend = buf + res; rdcnt += res; - return(0); + return 0; } /* * Oh well, yet another failed read... - * if error limit reached, ditch. o.w. poke device to move past + * if error limit reached, ditch. otherwise poke device to move past * bad media and try again. if media is badly damaged, we ask * the poor (and upset user at this point) for the next archive * volume. remember the goal on reads is to get the most we * can extract out of the archive. */ if ((maxflt > 0) && (++errcnt > maxflt)) - paxwarn(0,"Archive read error limit (%d) reached",maxflt); + tty_warn(0, + "Archive read error limit (%d) reached",maxflt); else if (ar_rdsync() == 0) continue; if (ar_next() < 0) @@ -356,14 +367,14 @@ rd_sync(void) rdcnt = 0; errcnt = 0; } - return(-1); + return -1; } /* * pback() * push the data used during the archive id phase back into the I/O * buffer. This is required as we cannot be sure that the header does NOT - * overlap a block boundry (as in the case we are trying to recover a + * overlap a block boundary (as in the case we are trying to recover a * flawed archived). This was not designed to be used for any other * purpose. (What software engineering, HA!) * WARNING: do not even THINK of pback greater than BLKMULT, unless the @@ -380,7 +391,7 @@ pback(char *pt, int cnt) /* * rd_skip() - * skip foward in the archive during an archive read. Used to get quickly + * skip forward in the archive during an archive read. Used to get quickly * past file data and padding for files the user did NOT select. * Return: * 0 if ok, -1 failure, and 1 when EOF on the archive volume was detected. @@ -394,13 +405,13 @@ rd_skip(off_t skcnt) off_t skipped = 0; /* - * consume what data we have in the buffer. If we have to move foward + * consume what data we have in the buffer. If we have to move forward * whole records, we call the low level skip function to see if we can * move within the archive without doing the expensive reads on data we * do not want. */ if (skcnt == 0) - return(0); + return 0; res = MIN((bufend - bufpt), skcnt); bufpt += res; skcnt -= res; @@ -409,7 +420,7 @@ rd_skip(off_t skcnt) * if skcnt is now 0, then no additional i/o is needed */ if (skcnt == 0) - return(0); + return 0; /* * We have to read more, calculate complete and partial record reads @@ -423,7 +434,7 @@ rd_skip(off_t skcnt) * how much it can skip over. We will have to read the rest. */ if (ar_fow(cnt, &skipped) < 0) - return(-1); + return -1; res += cnt - skipped; rdcnt += skipped; @@ -437,14 +448,14 @@ rd_skip(off_t skcnt) * if the read fails, we will have to resync */ if ((cnt <= 0) && ((cnt = buf_fill()) < 0)) - return(-1); + return -1; if (cnt == 0) - return(1); + return 1; cnt = MIN(cnt, res); bufpt += cnt; res -= cnt; } - return(0); + return 0; } /* @@ -488,7 +499,7 @@ wr_rdbuf(char *out, int outcnt) while (outcnt > 0) { cnt = bufend - bufpt; if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) - return(-1); + return -1; /* * only move what we have space for */ @@ -498,7 +509,7 @@ wr_rdbuf(char *out, int outcnt) out += cnt; outcnt -= cnt; } - return(0); + return 0; } /* @@ -528,12 +539,12 @@ rd_wrbuf(char *in, int cpcnt) /* * read error, return what we got (or the error if * no data was copied). The caller must know that an - * error occured and has the best knowledge what to + * error occurred and has the best knowledge what to * do with it */ if ((res = cpcnt - incnt) > 0) - return(res); - return(cnt); + return res; + return cnt; } /* @@ -546,7 +557,7 @@ rd_wrbuf(char *in, int cpcnt) incnt -= cnt; in += cnt; } - return(cpcnt); + return cpcnt; } /* @@ -571,19 +582,19 @@ wr_skip(off_t skcnt) while (skcnt > 0L) { cnt = bufend - bufpt; if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) - return(-1); + return -1; cnt = MIN(cnt, skcnt); memset(bufpt, 0, cnt); bufpt += cnt; skcnt -= cnt; } - return(0); + return 0; } /* * wr_rdfile() * fill write buffer with the contents of a file. We are passed an open - * file descriptor to the file and the archive structure that describes the + * file descriptor to the file an the archive structure that describes the * file we are storing. The variable "left" is modified to contain the * number of bytes of the file we were NOT able to write to the archive. * it is important that we always write EXACTLY the number of bytes that @@ -604,7 +615,16 @@ wr_rdfile(ARCHD *arcn, int ifd, off_t *left) int cnt; int res = 0; off_t size = arcn->sb.st_size; - struct stat sb; + struct stat origsb, sb; + + /* + * by default, remember the previously obtained stat information + * (in arcn->sb) for comparing the mtime after reading. + * if Mflag is set, use the actual mtime instead. + */ + origsb = arcn->sb; + if (Mflag && (fstat(ifd, &origsb) < 0)) + syswarn(1, errno, "Failed stat on %s", arcn->org_name); /* * while there are more bytes to write @@ -613,10 +633,10 @@ wr_rdfile(ARCHD *arcn, int ifd, off_t *left) cnt = bufend - bufpt; if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) { *left = size; - return(-1); + return -1; } cnt = MIN(cnt, size); - if ((res = read(ifd, bufpt, cnt)) <= 0) + if ((res = read_with_restart(ifd, bufpt, cnt)) <= 0) break; size -= res; bufpt += res; @@ -629,14 +649,14 @@ wr_rdfile(ARCHD *arcn, int ifd, off_t *left) if (res < 0) syswarn(1, errno, "Read fault on %s", arcn->org_name); else if (size != 0L) - paxwarn(1, "File changed size during read %s", arcn->org_name); + tty_warn(1, "File changed size during read %s", arcn->org_name); else if (fstat(ifd, &sb) < 0) syswarn(1, errno, "Failed stat on %s", arcn->org_name); - else if (arcn->sb.st_mtime != sb.st_mtime) - paxwarn(1, "File %s was modified during copy to archive", + else if (origsb.st_mtime != sb.st_mtime) + tty_warn(1, "File %s was modified during copy to archive", arcn->org_name); *left = size; - return(0); + return 0; } /* @@ -669,21 +689,21 @@ rd_wrfile(ARCHD *arcn, int ofd, off_t *left) int isem = 1; int rem; int sz = MINFBSZ; - struct stat sb; + struct stat sb; u_long crc = 0L; /* * pass the blocksize of the file being written to the write routine, * if the size is zero, use the default MINFBSZ */ - if (fstat(ofd, &sb) == 0) { -#if 0 - /* not under minix */ + if (ofd < 0) + sz = PAXPATHLEN+1; + else if (fstat(ofd, &sb) == 0) { if (sb.st_blksize > 0) sz = (int)sb.st_blksize; -#endif } else - syswarn(0,errno,"Unable to obtain block size for file %s",fnm); + syswarn(0, errno, + "Unable to obtain block size for file %s", fnm); rem = sz; *left = 0L; @@ -725,22 +745,23 @@ rd_wrfile(ARCHD *arcn, int ofd, off_t *left) * written. just closing with the file offset moved forward may not put * a hole at the end of the file. */ - if (isem && (arcn->sb.st_size > 0L)) + if (ofd >= 0 && isem && (arcn->sb.st_size > 0L)) file_flush(ofd, fnm, isem); /* * if we failed from archive read, we do not want to skip */ if ((size > 0L) && (*left == 0L)) - return(-1); + return -1; /* * some formats record a crc on file data. If so, then we compare the * calculated crc to the crc stored in the archive */ if (docrc && (size == 0L) && (arcn->crc != crc)) - paxwarn(1,"Actual crc does not match expected crc %s",arcn->name); - return(0); + tty_warn(1,"Actual crc does not match expected crc %s", + arcn->name); + return 0; } /* @@ -761,40 +782,44 @@ cp_file(ARCHD *arcn, int fd1, int fd2) int isem = 1; int rem; int sz = MINFBSZ; - struct stat sb; + struct stat sb, origsb; /* * check for holes in the source file. If none, we will use regular * write instead of file write. */ -#if 0 - /* not under minix */ if (((off_t)(arcn->sb.st_blocks * BLKMULT)) >= arcn->sb.st_size) -#endif ++no_hole; + /* + * by default, remember the previously obtained stat information + * (in arcn->sb) for comparing the mtime after reading. + * if Mflag is set, use the actual mtime instead. + */ + origsb = arcn->sb; + if (Mflag && (fstat(fd1, &origsb) < 0)) + syswarn(1, errno, "Failed stat on %s", arcn->org_name); + /* * pass the blocksize of the file being written to the write routine, * if the size is zero, use the default MINFBSZ */ if (fstat(fd2, &sb) == 0) { -#if 0 - /* not under minix */ if (sb.st_blksize > 0) sz = sb.st_blksize; -#endif } else - syswarn(0,errno,"Unable to obtain block size for file %s",fnm); + syswarn(0, errno, + "Unable to obtain block size for file %s", fnm); rem = sz; /* * read the source file and copy to destination file until EOF */ for(;;) { - if ((cnt = read(fd1, buf, blksz)) <= 0) + if ((cnt = read_with_restart(fd1, buf, blksz)) <= 0) break; if (no_hole) - res = write(fd2, buf, cnt); + res = xwrite(fd2, buf, cnt); else res = file_write(fd2, buf, cnt, &rem, &isem, sz, fnm); if (res != cnt) @@ -809,12 +834,12 @@ cp_file(ARCHD *arcn, int fd1, int fd2) syswarn(1, errno, "Failed write during copy of %s to %s", arcn->org_name, arcn->name); else if (cpcnt != arcn->sb.st_size) - paxwarn(1, "File %s changed size during copy to %s", + tty_warn(1, "File %s changed size during copy to %s", arcn->org_name, arcn->name); else if (fstat(fd1, &sb) < 0) syswarn(1, errno, "Failed stat of %s", arcn->org_name); - else if (arcn->sb.st_mtime != sb.st_mtime) - paxwarn(1, "File %s was modified during copy to %s", + else if (origsb.st_mtime != sb.st_mtime) + tty_warn(1, "File %s was modified during copy to %s", arcn->org_name, arcn->name); /* @@ -844,7 +869,7 @@ buf_fill(void) static int fini = 0; if (fini) - return(0); + return 0; for(;;) { /* @@ -855,22 +880,25 @@ buf_fill(void) bufpt = buf; bufend = buf + cnt; rdcnt += cnt; - return(cnt); + return cnt; } /* * errors require resync, EOF goes to next archive + * but in case we have not determined yet the format, + * this means that we have a very short file, so we + * are done again. */ if (cnt < 0) break; - if (ar_next() < 0) { + if (frmt == NULL || ar_next() < 0) { fini = 1; - return(0); + return 0; } rdcnt = 0; } exit_val = 1; - return(-1); + return -1; } /* @@ -891,16 +919,17 @@ buf_flush(int bufcnt) /* * if we have reached the user specified byte count for each archive - * volume, prompt for the next volume. (The non-standrad -R flag). + * volume, prompt for the next volume. (The non-standard -R flag). * NOTE: If the wrlimit is smaller than wrcnt, we will always write * at least one record. We always round limit UP to next blocksize. */ if ((wrlimit > 0) && (wrcnt > wrlimit)) { - paxwarn(0, "User specified archive volume byte limit reached."); + tty_warn(0, + "User specified archive volume byte limit reached."); if (ar_next() < 0) { wrcnt = 0; exit_val = 1; - return(-1); + return -1; } wrcnt = 0; @@ -915,7 +944,7 @@ buf_flush(int bufcnt) */ bufend = buf + blksz; if (blksz > bufcnt) - return(0); + return 0; if (blksz < bufcnt) push = bufcnt - blksz; } @@ -947,7 +976,7 @@ buf_flush(int bufcnt) } } else bufpt = buf; - return(totcnt); + return totcnt; } else if (cnt > 0) { /* * Oh drat we got a partial write! @@ -962,7 +991,7 @@ buf_flush(int bufcnt) memcpy(buf, bufpt, cnt); bufpt = buf + cnt; if (!frmt->blkalgn || ((cnt % frmt->blkalgn) == 0)) - return(totcnt); + return totcnt; break; } @@ -980,7 +1009,7 @@ buf_flush(int bufcnt) */ bufend = buf + blksz; if (blksz > bufcnt) - return(0); + return 0; if (blksz < bufcnt) push = bufcnt - blksz; } @@ -989,5 +1018,5 @@ buf_flush(int bufcnt) * write failed, stop pax. we must not create a bad archive! */ exit_val = 1; - return(-1); + return -1; } diff --git a/commands/pax/cpio.1 b/bin/pax/cpio.1 similarity index 76% rename from commands/pax/cpio.1 rename to bin/pax/cpio.1 index 7ff188122..9589e3d64 100644 --- a/commands/pax/cpio.1 +++ b/bin/pax/cpio.1 @@ -1,4 +1,5 @@ -.\"- +.\" $NetBSD: cpio.1,v 1.13 2011/06/19 07:34:24 wiz Exp $ +.\" .\" Copyright (c) 1997 SigmaSoft, Th. Lockert .\" All rights reserved. .\" @@ -10,11 +11,6 @@ .\" 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 @@ -27,66 +23,67 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: cpio.1,v 1.16 2001/05/01 17:58:01 aaron Exp $ -.\" $FreeBSD$ +.\" OpenBSD: cpio.1,v 1.14 2000/11/10 17:52:02 aaron Exp .\" -.Dd February 16, 1997 +.Dd June 18, 2011 .Dt CPIO 1 .Os .Sh NAME .Nm cpio .Nd copy file archives in and out .Sh SYNOPSIS -.Nm +.Nm cpio .Fl o -.Op Fl aABcLvzZ +.Op Fl AaBcLvZz .Op Fl C Ar bytes .Op Fl F Ar archive .Op Fl H Ar format .Op Fl O Ar archive -.No < Ar name-list -.Op No > Ar archive -.Nm +.Ar "\*[Lt] name-list" +.Op Ar "\*[Gt] archive" +.Nm cpio .Fl i -.Op Fl bBcdfmrsStuvzZ6 +.Op Fl 6BbcdfmrSstuvZz .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 No < Ar archive -.Nm +.Op Ar "pattern ..." +.Op Ar "\*[Lt] archive" +.Nm cpio .Fl p -.Op Fl adlLmuv +.Op Fl adLlmuv .Ar destination-directory -.No < Ar name-list +.Ar "\*[Lt] name-list" .Sh DESCRIPTION The .Nm command copies files to and from a .Nm archive. +If the archive is of the form: +.Ar [[user@]host:]file +then the archive will be processed using +.Xr rmt 8 . .Pp The options are as follows: -.Bl -tag -width indent -.It Fl o +.Bl -tag -width Ds +.It Fl o , Fl Fl create 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 indent -.It Fl a +.Bl -tag -width Ds +.It Fl a , Fl Fl reset-access-time Reset the access times on files that have been copied to the archive. -.It Fl A +.It Fl A , Fl Fl append Append to the specified archive. .It Fl B Set block size of output to 5120 bytes. .It Fl c -Use -.Tn ASCII -format for +Use ASCII format for .Nm header for portability. .It Fl C Ar bytes @@ -100,46 +97,48 @@ Write the archive in the specified format. Recognized formats are: .Pp .Bl -tag -width sv4cpio -compact -.It Cm bcpio +.It Ar bcpio Old binary .Nm format. -.It Cm cpio +.It Ar cpio Old octal character .Nm format. -.It Cm sv4cpio -.Tn SVR4 -hex +.It Ar sv4cpio +SVR4 hex .Nm format. -.It Cm tar +.It Ar tar Old tar format. -.It Cm ustar -.Tn POSIX -ustar 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 +.It Fl Fl xz +Compress/decompress archive using +.Xr xz 1 format. .It Fl Z Compress archive using .Xr compress 1 format. +.It Fl z +Compress/decompress archive using +.Xr gzip 1 +format. .El -.It Fl i +.It Fl i , Fl Fl extract 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 indent +.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 @@ -147,63 +146,60 @@ 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 -.Tn ASCII -format. +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 +.It Fl d , Fl Fl make-directories Create any intermediate directories as needed during restore. -.It Fl E Ar file +.It Fl E Ar file , Fl Fl pattern-file Ar file Read list of file name patterns to extract or list from .Ar file . -.It Fl f +.It Fl f , Fl Fl nonmatching Restore all files except those matching the .Ar patterns given on the command line. -.It Fl F Ar archive , Fl I Ar archive +.It Fl F Ar archive , Fl Fl file Ar archive +.It Fl I Ar archive Use the specified file as the input for the archive. -.It Fl H Ar format +.It Fl H Ar format , Fl Fl format Ar format Read an archive of the specified format. Recognized formats are: .Pp .Bl -tag -width sv4cpio -compact -.It Cm bcpio +.It Ar bcpio Old binary .Nm format. -.It Cm cpio +.It Ar cpio Old octal character .Nm format. -.It Cm sv4cpio -.Tn SVR4 -hex +.It Ar sv4cpio +SVR4 hex .Nm format. -.It Cm tar +.It Ar tar Old tar format. -.It Cm ustar -.Tn POSIX -ustar format. +.It Ar ustar +POSIX ustar format. .El .It Fl m Restore modification times on files. -.It Fl r +.It Fl r , Fl Fl rename Rename restored files interactively. .It Fl s Swap bytes after reading data from the archive. -.It Fl S +.It Fl S , Fl Fl swap-halfwords Swap words after reading data from the archive. -.It Fl t +.It Fl t , Fl Fl list Only list the contents of the archive, no files or directories will be created. -.It Fl u +.It Fl u , Fl Fl unconditional Overwrite files even when the file in the archive is older than the one that will be overwritten. -.It Fl v +.It Fl v , Fl Fl verbose Be verbose about operations. List filenames as they are copied in from the archive. .It Fl z @@ -219,42 +215,49 @@ Process old-style .Nm format archives. .El -.It Fl p +.It Fl p , Fl Fl pass-through 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 indent +.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 +.It Fl l , Fl Fl link When possible, link files rather than creating an extra copy. -.It Fl L +.It Fl L , Fl Fl dereference Follow symbolic links. -.It Fl m +.It Fl m , Fl Fl preserve-modification-time Restore modification times on files. -.It Fl u +.It Fl u , Fl Fl unconditional Overwrite files even when the original file being copied is older than the one that will be overwritten. -.It Fl v +.It Fl v , Fl Fl verbose Be verbose about operations. List filenames as they are copied. +.It Fl Fl force-local +Do not interpret filenames that contain a +.Sq \&: +as remote files. +.It Fl Fl insecure +Normally +.Nm +ignores filenames that contain +.Dq .. +as a path component. +With this option, files that contain +.Dq .. +can be processed. .El .El -.Sh ENVIRONMENT -.Bl -tag -width TMPDIR -.It Ev TMPDIR -Path in which to store temporary files. -.El .Sh EXIT STATUS -The .Nm -utility will exit with one of the following values: +will exit with one of the following values: .Bl -tag -width 2n .It 0 All files were processed successfully. @@ -294,8 +297,7 @@ specific archive format specification. .Xr pax 1 , .Xr tar 1 .Sh AUTHORS -.An Keith Muller -at the University of California, San Diego. +Keith Muller at the University of California, San Diego. .Sh BUGS The .Fl s diff --git a/commands/pax/cpio.c b/bin/pax/cpio.c similarity index 69% rename from commands/pax/cpio.c rename to bin/pax/cpio.c index 0a86a1f9f..1a38ba26a 100644 --- a/commands/pax/cpio.c +++ b/bin/pax/cpio.c @@ -1,3 +1,5 @@ +/* $NetBSD: cpio.c,v 1.22 2012/08/09 08:09:21 christos Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,17 +33,25 @@ * SUCH DAMAGE. */ -#ifndef lint +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) #if 0 static char sccsid[] = "@(#)cpio.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: cpio.c,v 1.22 2012/08/09 08:09:21 christos Exp $"); #endif #endif /* not lint */ #include #include #include +#include #include -#include +#include #include #include #include @@ -57,7 +67,7 @@ static int com_rd(ARCHD *); * Routines which support the different cpio versions */ -static int swp_head; /* binary cpio header byte swap */ +int cpio_swp_head; /* binary cpio header byte swap */ /* * Routines common to all versions of cpio @@ -67,17 +77,17 @@ static int swp_head; /* binary cpio header byte swap */ * cpio_strd() * Fire up the hard link detection code * Return: - * 0 if ok -1 otherwise (the return values of lnk_start()) + * 0 if ok -1 otherwise (the return values of lnk_start()) */ int cpio_strd(void) { - return(lnk_start()); + return lnk_start(); } /* - * cpio_trail() + * cpio_subtrail() * Called to determine if a header block is a valid trailer. We are * passed the block, the in_sync flag (which tells us we are in resync * mode; looking for a valid header), and cnt (which starts at zero) @@ -87,14 +97,14 @@ cpio_strd(void) */ int -cpio_trail(ARCHD *arcn) +cpio_subtrail(ARCHD *arcn) { /* * look for trailer id in file we are about to process */ if ((strcmp(arcn->name, TRAILER) == 0) && (arcn->sb.st_size == 0)) - return(0); - return(-1); + return 0; + return -1; } /* @@ -142,8 +152,8 @@ com_rd(ARCHD *arcn) break; } if (chk_lnk(arcn) < 0) - return(-1); - return(0); + return -1; + return 0; } /* @@ -166,7 +176,7 @@ cpio_endwr(void) last.type = PAX_REG; last.sb.st_nlink = 1; (void)strcpy(last.name, TRAILER); - return((*frmt->wr)(&last)); + return (*frmt->wr)(&last); } /* @@ -182,9 +192,9 @@ rd_nm(ARCHD *arcn, int nsz) /* * do not even try bogus values */ - if ((nsz == 0) || (nsz > (int)sizeof(arcn->name))) { - paxwarn(1, "Cpio file name length %d is out of range", nsz); - return(-1); + if ((nsz <= 0) || (nsz > (int)sizeof(arcn->name))) { + tty_warn(1, "Cpio file name length %d is out of range", nsz); + return -1; } /* @@ -192,10 +202,10 @@ rd_nm(ARCHD *arcn, int nsz) */ if ((rd_wrbuf(arcn->name,nsz) != nsz) || (arcn->name[nsz-1] != '\0') || (arcn->name[0] == '\0')) { - paxwarn(1, "Cpio file name in header is corrupted"); - return(-1); + tty_warn(1, "Cpio file name in header is corrupted"); + return -1; } - return(0); + return 0; } /* @@ -213,15 +223,10 @@ rd_ln_nm(ARCHD *arcn) * check the length specified for bogus values */ if ((arcn->sb.st_size == 0) || - ((size_t)arcn->sb.st_size >= sizeof(arcn->ln_name))) { -# ifdef NET2_STAT - paxwarn(1, "Cpio link name length is invalid: %lu", - arcn->sb.st_size); -# else - paxwarn(1, "Cpio link name length is invalid: %ju", - (uintmax_t)arcn->sb.st_size); -# endif - return(-1); + (arcn->sb.st_size >= (off_t)sizeof(arcn->ln_name))) { + tty_warn(1, "Cpio link name length is invalid: " OFFT_F, + (OFFT_T) arcn->sb.st_size); + return -1; } /* @@ -229,8 +234,8 @@ rd_ln_nm(ARCHD *arcn) */ if (rd_wrbuf(arcn->ln_name, (int)arcn->sb.st_size) != (int)arcn->sb.st_size) { - paxwarn(1, "Cpio link name read error"); - return(-1); + tty_warn(1, "Cpio link name read error"); + return -1; } arcn->ln_nlen = arcn->sb.st_size; arcn->ln_name[arcn->ln_nlen] = '\0'; @@ -239,10 +244,10 @@ rd_ln_nm(ARCHD *arcn) * watch out for those empty link names */ if (arcn->ln_name[0] == '\0') { - paxwarn(1, "Cpio link name is corrupt"); - return(-1); + tty_warn(1, "Cpio link name is corrupt"); + return -1; } - return(0); + return 0; } /* @@ -251,10 +256,10 @@ rd_ln_nm(ARCHD *arcn) /* * cpio_id() - * determine if a block given to us is a valid extended byte oriented + * determine if a block given to us is a valid extended byte oriented * cpio header * Return: - * 0 if a valid header, -1 otherwise + * 0 if a valid header, -1 otherwise */ int @@ -262,8 +267,8 @@ cpio_id(char *blk, int size) { if ((size < (int)sizeof(HD_CPIO)) || (strncmp(blk, AMAGIC, sizeof(AMAGIC) - 1) != 0)) - return(-1); - return(0); + return -1; + return 0; } /* @@ -284,7 +289,7 @@ cpio_rd(ARCHD *arcn, char *buf) * check that this is a valid header, if not return -1 */ if (cpio_id(buf, sizeof(HD_CPIO)) < 0) - return(-1); + return -1; hd = (HD_CPIO *)buf; /* @@ -292,47 +297,37 @@ cpio_rd(ARCHD *arcn, char *buf) * ascii fields from the header */ arcn->pad = 0L; - arcn->sb.st_dev = (dev_t)asc_ul(hd->c_dev, sizeof(hd->c_dev), OCT); - arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), OCT); - arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), OCT); - arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), OCT); - arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), OCT); - arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink), + arcn->sb.st_dev = (dev_t)asc_u32(hd->c_dev, sizeof(hd->c_dev), OCT); + arcn->sb.st_ino = (ino_t)asc_u32(hd->c_ino, sizeof(hd->c_ino), OCT); + arcn->sb.st_mode = (mode_t)asc_u32(hd->c_mode, sizeof(hd->c_mode), OCT); + arcn->sb.st_uid = (uid_t)asc_u32(hd->c_uid, sizeof(hd->c_uid), OCT); + arcn->sb.st_gid = (gid_t)asc_u32(hd->c_gid, sizeof(hd->c_gid), OCT); + arcn->sb.st_nlink = (nlink_t)asc_u32(hd->c_nlink, sizeof(hd->c_nlink), OCT); - arcn->sb.st_rdev = (dev_t)asc_ul(hd->c_rdev, sizeof(hd->c_rdev), OCT); -#ifdef NET2_STAT - arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime, sizeof(hd->c_mtime), + arcn->sb.st_rdev = (dev_t)asc_u32(hd->c_rdev, sizeof(hd->c_rdev), OCT); + arcn->sb.st_mtime = (time_t)(int32_t)asc_u32(hd->c_mtime, sizeof(hd->c_mtime), OCT); -#else - arcn->sb.st_mtime = (time_t)asc_uqd(hd->c_mtime, sizeof(hd->c_mtime), - OCT); -#endif arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; -#ifdef NET2_STAT - arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,sizeof(hd->c_filesize), - OCT); -#else - arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,sizeof(hd->c_filesize), - OCT); -#endif + arcn->sb.st_size = (off_t)ASC_OFFT(hd->c_filesize, + sizeof(hd->c_filesize), OCT); /* * check name size and if valid, read in the name of this entry (name * follows header in the archive) */ - if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),OCT)) < 2) - return(-1); + if ((nsz = (int)asc_u32(hd->c_namesize,sizeof(hd->c_namesize),OCT)) < 2) + return -1; arcn->nlen = nsz - 1; if (rd_nm(arcn, nsz) < 0) - return(-1); + return -1; if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) { /* - * no link name to read for this file - */ + * no link name to read for this file + */ arcn->ln_nlen = 0; arcn->ln_name[0] = '\0'; - return(com_rd(arcn)); + return com_rd(arcn); } /* @@ -340,25 +335,25 @@ cpio_rd(ARCHD *arcn, char *buf) * stored like file data. */ if (rd_ln_nm(arcn) < 0) - return(-1); + return -1; /* * we have a valid header (with a link) */ - return(com_rd(arcn)); + return com_rd(arcn); } /* * cpio_endrd() - * no cleanup needed here, just return size of the trailer (for append) + * no cleanup needed here, just return size of the trailer (for append) * Return: - * size of trailer header in this format + * size of trailer header in this format */ off_t cpio_endrd(void) { - return((off_t)(sizeof(HD_CPIO) + sizeof(TRAILER))); + return (off_t)(sizeof(HD_CPIO) + sizeof(TRAILER)); } /* @@ -371,7 +366,7 @@ cpio_endrd(void) int cpio_stwr(void) { - return(dev_start()); + return dev_start(); } /* @@ -379,7 +374,7 @@ cpio_stwr(void) * copy the data in the ARCHD to buffer in extended byte oriented cpio * format. * Return - * 0 if file has data to be written after the header, 1 if file has NO + * 0 if file has data to be written after the header, 1 if file has NO * data to write after the header, -1 if archive write failed */ @@ -394,7 +389,7 @@ cpio_wr(ARCHD *arcn) * check and repair truncated device and inode fields in the header */ if (map_dev(arcn, (u_long)CPIO_MASK, (u_long)CPIO_MASK) < 0) - return(-1); + return -1; arcn->pad = 0L; nsz = arcn->nlen + 1; @@ -409,23 +404,18 @@ cpio_wr(ARCHD *arcn) /* * set data size for file data */ -# ifdef NET2_STAT - if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize, + if (OFFT_ASC(arcn->sb.st_size, hd->c_filesize, sizeof(hd->c_filesize), OCT)) { -# else - if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize, - sizeof(hd->c_filesize), OCT)) { -# endif - paxwarn(1,"File is too large for cpio format %s", + tty_warn(1,"File is too large for cpio format %s", arcn->org_name); - return(1); + return 1; } break; case PAX_SLK: /* * set data size to hold link name */ - if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize, + if (u32_asc((uintmax_t)arcn->ln_nlen, hd->c_filesize, sizeof(hd->c_filesize), OCT)) goto out; break; @@ -433,7 +423,7 @@ cpio_wr(ARCHD *arcn) /* * all other file types have no file data */ - if (ul_asc((u_long)0, hd->c_filesize, sizeof(hd->c_filesize), + if (u32_asc((uintmax_t)0, hd->c_filesize, sizeof(hd->c_filesize), OCT)) goto out; break; @@ -442,24 +432,24 @@ cpio_wr(ARCHD *arcn) /* * copy the values to the header using octal ascii */ - if (ul_asc((u_long)MAGIC, hd->c_magic, sizeof(hd->c_magic), OCT) || - ul_asc((u_long)arcn->sb.st_dev, hd->c_dev, sizeof(hd->c_dev), + if (u32_asc((uintmax_t)MAGIC, hd->c_magic, sizeof(hd->c_magic), OCT) || + u32_asc((uintmax_t)arcn->sb.st_dev, hd->c_dev, sizeof(hd->c_dev), OCT) || - ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino), + u32_asc((uintmax_t)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino), OCT) || - ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode), + u32_asc((uintmax_t)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode), OCT) || - ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid), + u32_asc((uintmax_t)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid), OCT) || - ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid), + u32_asc((uintmax_t)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid), OCT) || - ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink), + u32_asc((uintmax_t)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink), OCT) || - ul_asc((u_long)arcn->sb.st_rdev, hd->c_rdev, sizeof(hd->c_rdev), + u32_asc((uintmax_t)arcn->sb.st_rdev, hd->c_rdev, sizeof(hd->c_rdev), OCT) || - ul_asc((u_long)arcn->sb.st_mtime,hd->c_mtime,sizeof(hd->c_mtime), + u32_asc((uintmax_t)arcn->sb.st_mtime,hd->c_mtime,sizeof(hd->c_mtime), OCT) || - ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), OCT)) + u32_asc((uintmax_t)nsz, hd->c_namesize, sizeof(hd->c_namesize), OCT)) goto out; /* @@ -467,37 +457,38 @@ cpio_wr(ARCHD *arcn) */ if ((wr_rdbuf(hdblk, (int)sizeof(HD_CPIO)) < 0) || (wr_rdbuf(arcn->name, nsz) < 0)) { - paxwarn(1, "Unable to write cpio header for %s", arcn->org_name); - return(-1); + tty_warn(1, "Unable to write cpio header for %s", + arcn->org_name); + return -1; } /* * if this file has data, we are done. The caller will write the file * data, if we are link tell caller we are done, go to next file */ - if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) || - (arcn->type == PAX_HRG)) - return(0); + if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) + return 0; if (arcn->type != PAX_SLK) - return(1); + return 1; /* * write the link name to the archive, tell the caller to go to the * next file as we are done. */ if (wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) { - paxwarn(1,"Unable to write cpio link name for %s",arcn->org_name); - return(-1); + tty_warn(1,"Unable to write cpio link name for %s", + arcn->org_name); + return -1; } - return(1); + return 1; out: /* * header field is out of range */ - paxwarn(1, "Cpio header field is too small to store file %s", + tty_warn(1, "Cpio header field is too small to store file %s", arcn->org_name); - return(1); + return 1; } /* @@ -506,11 +497,11 @@ cpio_wr(ARCHD *arcn) /* * vcpio_id() - * determine if a block given to us is a valid system VR4 cpio header + * determine if a block given to us is a valid system VR4 cpio header * WITHOUT crc. WATCH it the magic cookies are in OCTAL, the header * uses HEX * Return: - * 0 if a valid header, -1 otherwise + * 0 if a valid header, -1 otherwise */ int @@ -518,39 +509,39 @@ vcpio_id(char *blk, int size) { if ((size < (int)sizeof(HD_VCPIO)) || (strncmp(blk, AVMAGIC, sizeof(AVMAGIC) - 1) != 0)) - return(-1); - return(0); + return -1; + return 0; } /* * crc_id() - * determine if a block given to us is a valid system VR4 cpio header + * determine if a block given to us is a valid system VR4 cpio header * WITH crc. WATCH it the magic cookies are in OCTAL the header uses HEX * Return: - * 0 if a valid header, -1 otherwise + * 0 if a valid header, -1 otherwise */ int crc_id(char *blk, int size) { if ((size < (int)sizeof(HD_VCPIO)) || - (strncmp(blk, AVCMAGIC, (int)sizeof(AVCMAGIC) - 1) != 0)) - return(-1); - return(0); + (strncmp(blk, AVCMAGIC, sizeof(AVCMAGIC) - 1) != 0)) + return -1; + return 0; } /* * crc_strd() - w set file data CRC calculations. Fire up the hard link detection code + * set file data CRC calculations. Fire up the hard link detection code * Return: - * 0 if ok -1 otherwise (the return values of lnk_start()) + * 0 if ok -1 otherwise (the return values of lnk_start()) */ int crc_strd(void) { docrc = 1; - return(lnk_start()); + return lnk_start(); } /* @@ -575,10 +566,10 @@ vcpio_rd(ARCHD *arcn, char *buf) */ if (docrc) { if (crc_id(buf, sizeof(HD_VCPIO)) < 0) - return(-1); + return -1; } else { if (vcpio_id(buf, sizeof(HD_VCPIO)) < 0) - return(-1); + return -1; } hd = (HD_VCPIO *)buf; @@ -587,48 +578,39 @@ vcpio_rd(ARCHD *arcn, char *buf) /* * extract the hex ascii fields from the header */ - arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), HEX); - arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), HEX); - arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), HEX); - arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), HEX); -#ifdef NET2_STAT - arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime,sizeof(hd->c_mtime),HEX); -#else - arcn->sb.st_mtime = (time_t)asc_uqd(hd->c_mtime,sizeof(hd->c_mtime),HEX); -#endif + arcn->sb.st_ino = (ino_t)asc_u32(hd->c_ino, sizeof(hd->c_ino), HEX); + arcn->sb.st_mode = (mode_t)asc_u32(hd->c_mode, sizeof(hd->c_mode), HEX); + arcn->sb.st_uid = (uid_t)asc_u32(hd->c_uid, sizeof(hd->c_uid), HEX); + arcn->sb.st_gid = (gid_t)asc_u32(hd->c_gid, sizeof(hd->c_gid), HEX); + arcn->sb.st_mtime = (time_t)(int32_t)asc_u32(hd->c_mtime,sizeof(hd->c_mtime),HEX); arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; -#ifdef NET2_STAT - arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize, - sizeof(hd->c_filesize), HEX); -#else - arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize, + arcn->sb.st_size = (off_t)ASC_OFFT(hd->c_filesize, sizeof(hd->c_filesize), HEX); -#endif - arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink), + arcn->sb.st_nlink = (nlink_t)asc_u32(hd->c_nlink, sizeof(hd->c_nlink), HEX); - devmajor = (dev_t)asc_ul(hd->c_maj, sizeof(hd->c_maj), HEX); - devminor = (dev_t)asc_ul(hd->c_min, sizeof(hd->c_min), HEX); + devmajor = (dev_t)asc_u32(hd->c_maj, sizeof(hd->c_maj), HEX); + devminor = (dev_t)asc_u32(hd->c_min, sizeof(hd->c_min), HEX); arcn->sb.st_dev = TODEV(devmajor, devminor); - devmajor = (dev_t)asc_ul(hd->c_rmaj, sizeof(hd->c_maj), HEX); - devminor = (dev_t)asc_ul(hd->c_rmin, sizeof(hd->c_min), HEX); + devmajor = (dev_t)asc_u32(hd->c_rmaj, sizeof(hd->c_maj), HEX); + devminor = (dev_t)asc_u32(hd->c_rmin, sizeof(hd->c_min), HEX); arcn->sb.st_rdev = TODEV(devmajor, devminor); - arcn->crc = asc_ul(hd->c_chksum, sizeof(hd->c_chksum), HEX); + arcn->crc = asc_u32(hd->c_chksum, sizeof(hd->c_chksum), HEX); /* * check the length of the file name, if ok read it in, return -1 if * bogus */ - if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),HEX)) < 2) - return(-1); + if ((nsz = (int)asc_u32(hd->c_namesize,sizeof(hd->c_namesize),HEX)) < 2) + return -1; arcn->nlen = nsz - 1; if (rd_nm(arcn, nsz) < 0) - return(-1); + return -1; /* - * skip padding. header + filename is aligned to 4 byte boundries + * skip padding. header + filename is aligned to 4 byte boundaries */ if (rd_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0) - return(-1); + return -1; /* * if not a link (or a file with no data), calculate pad size (for @@ -641,7 +623,7 @@ vcpio_rd(ARCHD *arcn, char *buf) arcn->ln_nlen = 0; arcn->ln_name[0] = '\0'; arcn->pad = VCPIO_PAD(arcn->sb.st_size); - return(com_rd(arcn)); + return com_rd(arcn); } /* @@ -649,26 +631,26 @@ vcpio_rd(ARCHD *arcn, char *buf) */ if ((rd_ln_nm(arcn) < 0) || (rd_skip((off_t)(VCPIO_PAD(arcn->sb.st_size))) < 0)) - return(-1); + return -1; /* * we have a valid header (with a link) */ - return(com_rd(arcn)); + return com_rd(arcn); } /* * vcpio_endrd() - * no cleanup needed here, just return size of the trailer (for append) + * no cleanup needed here, just return size of the trailer (for append) * Return: - * size of trailer header in this format + * size of trailer header in this format */ off_t vcpio_endrd(void) { - return((off_t)(sizeof(HD_VCPIO) + sizeof(TRAILER) + - (VCPIO_PAD(sizeof(HD_VCPIO) + sizeof(TRAILER))))); + return (off_t)(sizeof(HD_VCPIO) + sizeof(TRAILER) + + (VCPIO_PAD(sizeof(HD_VCPIO) + sizeof(TRAILER)))); } /* @@ -682,7 +664,7 @@ int crc_stwr(void) { docrc = 1; - return(dev_start()); + return dev_start(); } /* @@ -706,7 +688,7 @@ vcpio_wr(ARCHD *arcn) * header */ if (map_dev(arcn, (u_long)VCPIO_MASK, (u_long)VCPIO_MASK) < 0) - return(-1); + return -1; nsz = arcn->nlen + 1; hd = (HD_VCPIO *)hdblk; if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR)) @@ -717,15 +699,15 @@ vcpio_wr(ARCHD *arcn) * file data crc's, and the crc if needed. */ if (docrc) { - if (ul_asc((u_long)VCMAGIC, hd->c_magic, sizeof(hd->c_magic), - OCT) || - ul_asc((u_long)arcn->crc,hd->c_chksum,sizeof(hd->c_chksum), - HEX)) + if (u32_asc((uintmax_t)VCMAGIC, hd->c_magic, sizeof(hd->c_magic), + OCT) || + u32_asc((uintmax_t)arcn->crc,hd->c_chksum,sizeof(hd->c_chksum), + HEX)) goto out; } else { - if (ul_asc((u_long)VMAGIC, hd->c_magic, sizeof(hd->c_magic), - OCT) || - ul_asc((u_long)0L, hd->c_chksum, sizeof(hd->c_chksum),HEX)) + if (u32_asc((uintmax_t)VMAGIC, hd->c_magic, sizeof(hd->c_magic), + OCT) || + u32_asc((uintmax_t)0, hd->c_chksum, sizeof(hd->c_chksum),HEX)) goto out; } @@ -738,16 +720,11 @@ vcpio_wr(ARCHD *arcn) * much to pad. */ arcn->pad = VCPIO_PAD(arcn->sb.st_size); -# ifdef NET2_STAT - if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize, + if (OFFT_ASC(arcn->sb.st_size, hd->c_filesize, sizeof(hd->c_filesize), HEX)) { -# else - if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize, - sizeof(hd->c_filesize), HEX)) { -# endif - paxwarn(1,"File is too large for sv4cpio format %s", + tty_warn(1,"File is too large for sv4cpio format %s", arcn->org_name); - return(1); + return 1; } break; case PAX_SLK: @@ -756,7 +733,7 @@ vcpio_wr(ARCHD *arcn) * the size of the link */ arcn->pad = 0L; - if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize, + if (u32_asc((uintmax_t)arcn->ln_nlen, hd->c_filesize, sizeof(hd->c_filesize), HEX)) goto out; break; @@ -765,7 +742,7 @@ vcpio_wr(ARCHD *arcn) * no file data for the caller to process */ arcn->pad = 0L; - if (ul_asc((u_long)0L, hd->c_filesize, sizeof(hd->c_filesize), + if (u32_asc((uintmax_t)0, hd->c_filesize, sizeof(hd->c_filesize), HEX)) goto out; break; @@ -774,27 +751,27 @@ vcpio_wr(ARCHD *arcn) /* * set the other fields in the header */ - if (ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino), + if (u32_asc((uintmax_t)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino), + HEX) || + u32_asc((uintmax_t)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode), HEX) || - ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode), + u32_asc((uintmax_t)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid), HEX) || - ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid), + u32_asc((uintmax_t)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid), HEX) || - ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid), - HEX) || - ul_asc((u_long)arcn->sb.st_mtime, hd->c_mtime, sizeof(hd->c_mtime), - HEX) || - ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink), - HEX) || - ul_asc((u_long)major(arcn->sb.st_dev),hd->c_maj, sizeof(hd->c_maj), + u32_asc((uintmax_t)arcn->sb.st_mtime, hd->c_mtime, sizeof(hd->c_mtime), HEX) || - ul_asc((u_long)minor(arcn->sb.st_dev),hd->c_min, sizeof(hd->c_min), + u32_asc((uintmax_t)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink), HEX) || - ul_asc((u_long)major(arcn->sb.st_rdev),hd->c_rmaj,sizeof(hd->c_maj), + u32_asc((uintmax_t)MAJOR(arcn->sb.st_dev),hd->c_maj, sizeof(hd->c_maj), HEX) || - ul_asc((u_long)minor(arcn->sb.st_rdev),hd->c_rmin,sizeof(hd->c_min), + u32_asc((uintmax_t)MINOR(arcn->sb.st_dev),hd->c_min, sizeof(hd->c_min), HEX) || - ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), HEX)) + u32_asc((uintmax_t)MAJOR(arcn->sb.st_rdev),hd->c_rmaj,sizeof(hd->c_maj), + HEX) || + u32_asc((uintmax_t)MINOR(arcn->sb.st_rdev),hd->c_rmin,sizeof(hd->c_min), + HEX) || + u32_asc((uintmax_t)nsz, hd->c_namesize, sizeof(hd->c_namesize), HEX)) goto out; /* @@ -803,8 +780,9 @@ vcpio_wr(ARCHD *arcn) if ((wr_rdbuf(hdblk, (int)sizeof(HD_VCPIO)) < 0) || (wr_rdbuf(arcn->name, (int)nsz) < 0) || (wr_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)) { - paxwarn(1,"Could not write sv4cpio header for %s",arcn->org_name); - return(-1); + tty_warn(1,"Could not write sv4cpio header for %s", + arcn->org_name); + return -1; } /* @@ -812,31 +790,32 @@ vcpio_wr(ARCHD *arcn) */ if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) || (arcn->type == PAX_HRG)) - return(0); + return 0; /* * if we are not a link, tell the caller we are done, go to next file */ if (arcn->type != PAX_SLK) - return(1); + return 1; /* * write the link name, tell the caller we are done. */ if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) || (wr_skip((off_t)(VCPIO_PAD(arcn->ln_nlen))) < 0)) { - paxwarn(1,"Could not write sv4cpio link name for %s", + tty_warn(1,"Could not write sv4cpio link name for %s", arcn->org_name); - return(-1); + return -1; } - return(1); + return 1; out: /* * header field is out of range */ - paxwarn(1,"Sv4cpio header field is too small for file %s",arcn->org_name); - return(1); + tty_warn(1,"Sv4cpio header field is too small for file %s", + arcn->org_name); + return 1; } /* @@ -845,34 +824,34 @@ vcpio_wr(ARCHD *arcn) /* * bcpio_id() - * determine if a block given to us is an old binary cpio header + * determine if a block given to us is a old binary cpio header * (with/without header byte swapping) * Return: - * 0 if a valid header, -1 otherwise + * 0 if a valid header, -1 otherwise */ int bcpio_id(char *blk, int size) { if (size < (int)sizeof(HD_BCPIO)) - return(-1); + return -1; /* * check both normal and byte swapped magic cookies */ if (((u_short)SHRT_EXT(blk)) == MAGIC) - return(0); + return 0; if (((u_short)RSHRT_EXT(blk)) == MAGIC) { - if (!swp_head) - ++swp_head; - return(0); + if (!cpio_swp_head) + ++cpio_swp_head; + return 0; } - return(-1); + return -1; } /* * bcpio_rd() - * determine if a buffer is an old binary archive entry. (It may have byte + * determine if a buffer is a old binary archive entry. (it may have byte * swapped header) convert and store the values in the ARCHD parameter. * This is a very old header format and should not really be used. * Return: @@ -889,11 +868,11 @@ bcpio_rd(ARCHD *arcn, char *buf) * check the header */ if (bcpio_id(buf, sizeof(HD_BCPIO)) < 0) - return(-1); + return -1; arcn->pad = 0L; hd = (HD_BCPIO *)buf; - if (swp_head) { + if (cpio_swp_head) { /* * header has swapped bytes on 16 bit boundaries */ @@ -934,16 +913,16 @@ bcpio_rd(ARCHD *arcn, char *buf) * name */ if (nsz < 2) - return(-1); + return -1; arcn->nlen = nsz - 1; if (rd_nm(arcn, nsz) < 0) - return(-1); + return -1; /* - * header + file name are aligned to 2 byte boundries, skip if needed + * header + file name are aligned to 2 byte boundaries, skip if needed */ if (rd_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0) - return(-1); + return -1; /* * if not a link (or a file with no data), calculate pad size (for @@ -956,41 +935,41 @@ bcpio_rd(ARCHD *arcn, char *buf) arcn->ln_nlen = 0; arcn->ln_name[0] = '\0'; arcn->pad = BCPIO_PAD(arcn->sb.st_size); - return(com_rd(arcn)); + return com_rd(arcn); } if ((rd_ln_nm(arcn) < 0) || (rd_skip((off_t)(BCPIO_PAD(arcn->sb.st_size))) < 0)) - return(-1); + return -1; /* * we have a valid header (with a link) */ - return(com_rd(arcn)); + return com_rd(arcn); } /* * bcpio_endrd() - * no cleanup needed here, just return size of the trailer (for append) + * no cleanup needed here, just return size of the trailer (for append) * Return: - * size of trailer header in this format + * size of trailer header in this format */ off_t bcpio_endrd(void) { - return((off_t)(sizeof(HD_BCPIO) + sizeof(TRAILER) + - (BCPIO_PAD(sizeof(HD_BCPIO) + sizeof(TRAILER))))); + return (off_t)(sizeof(HD_BCPIO) + sizeof(TRAILER) + + (BCPIO_PAD(sizeof(HD_BCPIO) + sizeof(TRAILER)))); } /* * bcpio_wr() * copy the data in the ARCHD to buffer in old binary cpio format * There is a real chance of field overflow with this critter. So we - * always check the conversion is ok. nobody in his their right mind - * should write an achive in this format... + * always check the conversion is ok. nobody in their right mind + * should write an archive in this format... * Return - * 0 if file has data to be written after the header, 1 if file has NO + * 0 if file has data to be written after the header, 1 if file has NO * data to write after the header, -1 if archive write failed */ @@ -1009,7 +988,7 @@ bcpio_wr(ARCHD *arcn) * header */ if (map_dev(arcn, (u_long)BCPIO_MASK, (u_long)BCPIO_MASK) < 0) - return(-1); + return -1; if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR)) arcn->sb.st_rdev = 0; @@ -1031,9 +1010,9 @@ bcpio_wr(ARCHD *arcn) t_offt = (off_t)(SHRT_EXT(hd->h_filesize_1)); t_offt = (t_offt<<16) | ((off_t)(SHRT_EXT(hd->h_filesize_2))); if (arcn->sb.st_size != t_offt) { - paxwarn(1,"File is too large for bcpio format %s", + tty_warn(1,"File is too large for bcpio format %s", arcn->org_name); - return(1); + return 1; } break; case PAX_SLK: @@ -1116,8 +1095,9 @@ bcpio_wr(ARCHD *arcn) if ((wr_rdbuf(hdblk, (int)sizeof(HD_BCPIO)) < 0) || (wr_rdbuf(arcn->name, nsz) < 0) || (wr_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)) { - paxwarn(1, "Could not write bcpio header for %s", arcn->org_name); - return(-1); + tty_warn(1, "Could not write bcpio header for %s", + arcn->org_name); + return -1; } /* @@ -1125,28 +1105,30 @@ bcpio_wr(ARCHD *arcn) */ if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) || (arcn->type == PAX_HRG)) - return(0); + return 0; /* * if we are not a link, tell the caller we are done, go to next file */ if (arcn->type != PAX_SLK) - return(1); + return 1; /* * write the link name, tell the caller we are done. */ if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) || (wr_skip((off_t)(BCPIO_PAD(arcn->ln_nlen))) < 0)) { - paxwarn(1,"Could not write bcpio link name for %s",arcn->org_name); - return(-1); + tty_warn(1,"Could not write bcpio link name for %s", + arcn->org_name); + return -1; } - return(1); + return 1; out: /* * header field is out of range */ - paxwarn(1,"Bcpio header field is too small for file %s", arcn->org_name); - return(1); + tty_warn(1,"Bcpio header field is too small for file %s", + arcn->org_name); + return 1; } diff --git a/commands/pax/cpio.h b/bin/pax/cpio.h similarity index 97% rename from commands/pax/cpio.h rename to bin/pax/cpio.h index 66d3d0d58..bbf40ed0d 100644 --- a/commands/pax/cpio.h +++ b/bin/pax/cpio.h @@ -1,3 +1,5 @@ +/* $NetBSD: cpio.h,v 1.6 2003/10/13 07:41:22 agc Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,7 +33,6 @@ * SUCH DAMAGE. * * @(#)cpio.h 8.1 (Berkeley) 5/31/93 - * $FreeBSD: src/bin/pax/cpio.h,v 1.7 2004/04/06 20:06:48 markm Exp $ */ /* diff --git a/bin/pax/dumptar.c b/bin/pax/dumptar.c new file mode 100644 index 000000000..0af32fbba --- /dev/null +++ b/bin/pax/dumptar.c @@ -0,0 +1,122 @@ +/* $NetBSD: dumptar.c,v 1.2 2008/04/28 20:22:51 martin Exp $ */ + +/*- + * Copyright (c) 2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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. + */ + +#include +#include +#include +#include +#include + +#include "tar.h" + +#define ussum(a) 1 + +static char * +buf(const char *p, size_t s) +{ + static char buf[1024]; + (void)snprintf(buf, sizeof(buf), "%s", p); + buf[s] = '\0'; + return buf; +} + +int +intarg(const char *p, size_t s) +{ + char *ep, *b = buf(p, s); + int r = (int)strtol(p, &ep, 8); + return r; +} + +static int +usdump(void *p) +{ + HD_USTAR *t = p; + int size = intarg(t->size, sizeof(t->size)); + size = ((size + 511) / 512) * 512 + 512; + + (void)fprintf(stdout, "*****\n"); +#define PR(a) \ + (void)fprintf(stdout, #a "=%s\n", buf(t->a, sizeof(t->a))); +#define IPR(a) \ + (void)fprintf(stdout, #a "=%d\n", intarg(t->a, sizeof(t->a))); +#define OPR(a) \ + (void)fprintf(stdout, #a "=%o\n", intarg(t->a, sizeof(t->a))); + PR(name); + OPR(mode); + IPR(uid); + IPR(gid); + IPR(size); + OPR(mtime); + OPR(chksum); + (void)fprintf(stdout, "typeflag=%c\n", t->typeflag); + PR(linkname); + PR(magic); + PR(version); + PR(uname); + PR(gname); + OPR(devmajor); + OPR(devminor); + PR(prefix); + return size; +} + +int +main(int argc, char *argv[]) +{ + int fd; + struct stat st; + char *p, *ep; + + if (argc != 2) { + (void)fprintf(stderr, "Usage: %s \n", getprogname()); + return 1; + } + + if ((fd = open(argv[1], O_RDONLY)) == -1) + err(1, "Cannot open `%s'", argv[1]); + + if (fstat(fd, &st) == -1) + err(1, "Cannot fstat `%s'", argv[1]); + + if ((p = mmap(NULL, (size_t)st.st_size, PROT_READ, + MAP_FILE|MAP_PRIVATE, fd, (off_t)0)) == MAP_FAILED) + err(1, "Cannot mmap `%s'", argv[1]); + (void)close(fd); + + ep = (char *)p + (size_t)st.st_size; + + for (; p < ep + sizeof(HD_USTAR);) { + if (ussum(p)) + p += usdump(p); + } + return 0; +} diff --git a/commands/pax/extern.h b/bin/pax/extern.h similarity index 73% rename from commands/pax/extern.h rename to bin/pax/extern.h index 67e0eca10..298600c2d 100644 --- a/commands/pax/extern.h +++ b/bin/pax/extern.h @@ -1,3 +1,5 @@ +/* $NetBSD: extern.h,v 1.59 2012/08/09 08:09:21 christos Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,39 +33,64 @@ * SUCH DAMAGE. * * @(#)extern.h 8.2 (Berkeley) 4/18/94 - * $FreeBSD: src/bin/pax/extern.h,v 1.16 2005/01/12 03:25:55 brian Exp $ */ /* * External references from each source file */ +#include +#include + /* * ar_io.c */ extern const char *arcname; +extern int curdirfd; extern const char *gzip_program; +extern time_t starttime; +extern int force_one_volume; +extern char *chdname; +extern int forcelocal; +extern int secure; + int ar_open(const char *); void ar_close(void); void ar_drain(void); int ar_set_wr(void); int ar_app_ok(void); +#ifdef SYS_NO_RESTART +int read_with_restart(int, void *, int); +int write_with_restart(int, void *, int); +#else +#define read_with_restart read +#define write_with_restart write +#endif +int xread(int, void *, int); +int xwrite(int, void *, int); int ar_read(char *, int); int ar_write(char *, int); int ar_rdsync(void); int ar_fow(off_t, off_t *); int ar_rev(off_t ); int ar_next(void); +void ar_summary(int); +int ar_dochdir(const char *); /* * ar_subs.c */ extern u_long flcnt; -void list(void); -void extract(void); -void append(void); -void archive(void); -void copy(void); +extern ARCHD archd; +int updatepath(void); +int dochdir(const char *); +int fdochdir(int); +int domkdir(const char *, mode_t); +int list(void); +int extract(void); +int append(void); +int archive(void); +int copy(void); /* * buf_subs.c @@ -92,23 +119,12 @@ void cp_file(ARCHD *, int, int); int buf_fill(void); int buf_flush(int); -/* - * cache.c - */ -int uidtb_start(void); -int gidtb_start(void); -int usrtb_start(void); -int grptb_start(void); -const char * name_uid(uid_t, int); -const char * name_gid(gid_t, int); -int uid_name(char *, uid_t *); -int gid_name(char *, gid_t *); - /* * cpio.c */ +extern int cpio_swp_head; int cpio_strd(void); -int cpio_trail(ARCHD *); +int cpio_subtrail(ARCHD *); int cpio_endwr(void); int cpio_id(char *, int); int cpio_rd(ARCHD *, char *); @@ -130,18 +146,21 @@ int bcpio_wr(ARCHD *); /* * file_subs.c */ -int file_creat(ARCHD *); +extern char *gnu_name_string, *gnu_link_string; +extern size_t gnu_name_length, gnu_link_length; +extern char *xtmp_name; +int file_creat(ARCHD *, int); void file_close(ARCHD *, int); -int lnk_creat(ARCHD *); +int lnk_creat(ARCHD *, int *); int cross_lnk(ARCHD *); int chk_same(ARCHD *); int node_creat(ARCHD *); int unlnk_exist(char *, int); int chk_path(char *, uid_t, gid_t); -void set_ftime(char *fnm, time_t mtime, time_t atime, int frc); +void set_ftime(char *fnm, time_t mtime, time_t atime, int frc, int slk); int set_ids(char *, uid_t, gid_t); -int set_lids(char *, uid_t, gid_t); void set_pmode(char *, mode_t); +void set_chflags(char *fnm, u_int32_t flags); int file_write(int, char *, int, int *, int *, int, char *); void file_flush(int, char *, int); void rdfile_close(ARCHD *, int *); @@ -153,7 +172,6 @@ int set_crc(ARCHD *, int); int ftree_start(void); int ftree_add(char *, int); void ftree_sel(ARCHD *); -void ftree_notsel(void); void ftree_chk(void); int next_file(ARCHD *); @@ -162,39 +180,44 @@ int next_file(ARCHD *); */ void ls_list(ARCHD *, time_t, FILE *); void ls_tty(ARCHD *); -int l_strncpy(char *, const char *, int); -u_long asc_ul(char *, int, int); -int ul_asc(u_long, char *, int, int); -#ifndef NET2_STAT -u_quad_t asc_uqd(char *, int, int); -int uqd_asc(u_quad_t, char *, int, int); -#endif +void safe_print(const char *, FILE *); +uint32_t asc_u32(char *, int, int); +int u32_asc(uintmax_t, char *, int, int); +uintmax_t asc_umax(char *, int, int); +int umax_asc(uintmax_t, char *, int, int); +int check_Aflag(void); /* * getoldopt.c */ -int getoldopt(int, char **, const char *); +struct option; +int getoldopt(int, char **, const char *, struct option *, int *); /* * options.c */ extern FSUB fsub[]; extern int ford[]; +extern int sep; +extern int havechd; void options(int, char **); OPLIST * opt_next(void); -int opt_add(const char *); int bad_opt(void); +int mkpath(char *); char *chdname; +#if !HAVE_NBTOOL_CONFIG_H +int do_chroot; +#endif /* * pat_rep.c */ int rep_add(char *); -int pat_add(char *, char *); +int pat_add(char *, char *, int); void pat_chk(void); int pat_sel(ARCHD *); int pat_match(ARCHD *); -int mod_name(ARCHD *); +int mod_name(ARCHD *, int); int set_dest(ARCHD *, char *, int); /* @@ -202,6 +225,7 @@ int set_dest(ARCHD *, char *, int); */ extern int act; extern FSUB *frmt; +extern int Aflag; extern int cflag; extern int cwdfd; extern int dflag; @@ -215,6 +239,8 @@ extern int vflag; extern int Dflag; extern int Hflag; extern int Lflag; +extern int Mflag; +extern int Vflag; extern int Xflag; extern int Yflag; extern int Zflag; @@ -222,19 +248,20 @@ extern int vfpart; extern int patime; extern int pmtime; extern int nodirs; +extern int pfflags; extern int pmode; extern int pids; extern int rmleadslash; extern int exit_val; extern int docrc; +extern int to_stdout; extern char *dirptr; +extern char *ltmfrmt; extern const char *argv0; extern FILE *listf; extern char *tempfile; extern char *tempbase; -void sig_cleanup(int); - /* * sel_subs.c */ @@ -270,6 +297,7 @@ u_int st_hash(char *, int, int); /* * tar.c */ +extern int is_gnutar; int tar_endwr(void); off_t tar_endrd(void); int tar_trail(char *, int, int *); @@ -282,12 +310,17 @@ int ustar_stwr(void); int ustar_id(char *, int); int ustar_rd(ARCHD *, char *); int ustar_wr(ARCHD *); +int tar_gnutar_X_compat(const char *); +int tar_gnutar_minus_minus_exclude(const char *); /* * tty_subs.c */ int tty_init(void); -void tty_prnt(const char *, ...); +void tty_prnt(const char *, ...) + __attribute__((format (printf, 1, 2))); int tty_read(char *, int); -void paxwarn(int, const char *, ...); -void syswarn(int, int, const char *, ...); +void tty_warn(int, const char *, ...) + __attribute__((format (printf, 2, 3))); +void syswarn(int, int, const char *, ...) + __attribute__((format (printf, 3, 4))); diff --git a/commands/pax/file_subs.c b/bin/pax/file_subs.c similarity index 61% rename from commands/pax/file_subs.c rename to bin/pax/file_subs.c index 9157df72a..e3707ca5a 100644 --- a/commands/pax/file_subs.c +++ b/bin/pax/file_subs.c @@ -1,3 +1,5 @@ +/* $NetBSD: file_subs.c,v 1.62 2009/04/07 19:52:35 perry Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,9 +33,16 @@ * SUCH DAMAGE. */ -#ifndef lint +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) #if 0 static char sccsid[] = "@(#)file_subs.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: file_subs.c,v 1.62 2009/04/07 19:52:35 perry Exp $"); #endif #endif /* not lint */ @@ -41,28 +50,54 @@ static char sccsid[] = "@(#)file_subs.c 8.1 (Berkeley) 5/31/93"; #include #include #include +#include #include #include #include +#include #include -#include #include #include #include "pax.h" -#include "options.h" #include "extern.h" +#include "options.h" + +char *xtmp_name; static int mk_link(char *,struct stat *,char *, int); +static int warn_broken; + /* * routines that deal with file operations such as: creating, removing; * and setting access modes, uid/gid and times of files */ +#define SET_BITS (S_ISUID | S_ISGID) +#define FILE_BITS (S_IRWXU | S_IRWXG | S_IRWXO) +#define A_BITS (FILE_BITS | SET_BITS | S_ISVTX) -#define FILEBITS (S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) -#define SETBITS (S_ISUID | S_ISGID) -#define ABITS (FILEBITS | SETBITS) +/* + * The S_ISVTX (sticky bit) can be set by non-superuser on directories + * but not other kinds of files. + */ +#define FILEBITS(dir) ((dir) ? (FILE_BITS | S_ISVTX) : FILE_BITS) +#define SETBITS(dir) ((dir) ? SET_BITS : (SET_BITS | S_ISVTX)) + +static mode_t +apply_umask(mode_t mode) +{ + static mode_t cached_umask; + static int cached_umask_valid; + + if (!cached_umask_valid) { + cached_umask = umask(0); + umask(cached_umask); + cached_umask_valid = 1; + } + + return mode & ~cached_umask; +} /* * file_creat() @@ -72,52 +107,75 @@ mk_link(char *,struct stat *,char *, int); */ int -file_creat(ARCHD *arcn) +file_creat(ARCHD *arcn, int write_to_hardlink) { int fd = -1; - mode_t file_mode; int oerrno; /* - * assume file doesn't exist, so just try to create it, most times this - * works. We have to take special handling when the file does exist. To - * detect this, we use O_EXCL. For example when trying to create a - * file and a character device or fifo exists with the same name, we - * can accidently open the device by mistake (or block waiting to open) - * If we find that the open has failed, then figure spend the effort to - * figure out why. This strategy was found to have better average - * performance in common use than checking the file (and the path) - * first with lstat. + * Some horribly busted tar implementations, have directory nodes + * that end in a /, but they mark as files. Compensate for that + * by not creating a directory node at this point, but a file node, + * and not creating the temp file. */ - file_mode = arcn->sb.st_mode & FILEBITS; - if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, - file_mode)) >= 0) - return(fd); + if (arcn->nlen != 0 && arcn->name[arcn->nlen - 1] == '/') { + if (!warn_broken) { + tty_warn(0, "Archive was created with a broken tar;" + " file `%s' is a directory, but marked as plain.", + arcn->name); + warn_broken = 1; + } + return -1; + } /* - * the file seems to exist. First we try to get rid of it (found to be - * the second most common failure when traced). If this fails, only - * then we go to the expense to check and create the path to the file + * In "cpio" archives it's usually the last record of a set of + * hardlinks which includes the contents of the file. We cannot + * use a tempory file in that case because we couldn't link it + * with the existing other hardlinks after restoring the contents + * to it. And it's also useless to create the hardlink under a + * temporary name because the other hardlinks would have partial + * contents while restoring. + */ + if (write_to_hardlink) + return (open(arcn->name, O_TRUNC | O_EXCL | O_RDWR, 0)); + + /* + * Create a temporary file name so that the file doesn't have partial + * contents while restoring. */ - if (unlnk_exist(arcn->name, arcn->type) != 0) - return(-1); + arcn->tmp_name = malloc(arcn->nlen + 8); + if (arcn->tmp_name == NULL) { + syswarn(1, errno, "Cannot malloc %d bytes", arcn->nlen + 8); + return -1; + } + if (xtmp_name != NULL) + abort(); + xtmp_name = arcn->tmp_name; for (;;) { /* - * try to open it again, if this fails, check all the nodes in - * the path and give it a final try. if chk_path() finds that - * it cannot fix anything, we will skip the last attempt + * try to create the temporary file we use to restore the + * contents info. if this fails, keep checking all the nodes + * in the path until chk_path() finds that it cannot fix + * anything further. if that happens we just give up. */ - if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC, - file_mode)) >= 0) + (void)snprintf(arcn->tmp_name, arcn->nlen + 8, "%s.XXXXXX", + arcn->name); + fd = mkstemp(arcn->tmp_name); + if (fd >= 0) break; oerrno = errno; 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); + (void)fflush(listf); + syswarn(1, oerrno, "Cannot create %s", arcn->tmp_name); + xtmp_name = NULL; + free(arcn->tmp_name); + arcn->tmp_name = NULL; + return -1; } } - return(fd); + return fd; } /* @@ -131,13 +189,17 @@ file_creat(ARCHD *arcn) void file_close(ARCHD *arcn, int fd) { - int res = 0; + char *tmp_name; + int res; if (fd < 0) return; + + tmp_name = (arcn->tmp_name != NULL) ? arcn->tmp_name : arcn->name; + if (close(fd) < 0) - syswarn(0, errno, "Unable to close file descriptor on %s", - arcn->name); + syswarn(0, errno, "Cannot close file descriptor on %s", + tmp_name); /* * set owner/groups first as this may strip off mode bits we want @@ -145,19 +207,48 @@ file_close(ARCHD *arcn, int fd) * modification times. */ if (pids) - res = set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid); + res = set_ids(tmp_name, arcn->sb.st_uid, arcn->sb.st_gid); + else + res = 0; /* * IMPORTANT SECURITY NOTE: * if not preserving mode or we cannot set uid/gid, then PROHIBIT - * set uid/gid bits + * set uid/gid bits but restore the file modes (since mkstemp doesn't). */ if (!pmode || res) - arcn->sb.st_mode &= ~(SETBITS); + arcn->sb.st_mode &= ~SETBITS(0); if (pmode) - set_pmode(arcn->name, arcn->sb.st_mode); + set_pmode(tmp_name, arcn->sb.st_mode); + else + set_pmode(tmp_name, + apply_umask((arcn->sb.st_mode & FILEBITS(0)))); if (patime || pmtime) - set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0); + set_ftime(tmp_name, arcn->sb.st_mtime, + arcn->sb.st_atime, 0, 0); + + /* Did we write directly to the target file? */ + if (arcn->tmp_name == NULL) + return; + + /* + * Finally, now the temp file is fully instantiated rename it to + * the desired file name. + */ + if (rename(tmp_name, arcn->name) < 0) { + syswarn(0, errno, "Cannot rename %s to %s", + tmp_name, arcn->name); + (void)unlink(tmp_name); + } + +#if HAVE_STRUCT_STAT_ST_FLAGS + if (pfflags && arcn->type != PAX_SLK) + set_chflags(arcn->name, arcn->sb.st_flags); +#endif + + free(arcn->tmp_name); + arcn->tmp_name = NULL; + xtmp_name = NULL; } /* @@ -169,27 +260,30 @@ file_close(ARCHD *arcn, int fd) */ int -lnk_creat(ARCHD *arcn) +lnk_creat(ARCHD *arcn, int *payload) { struct stat sb; /* - * we may be running as root, so we have to be sure that link target - * is not a directory, so we lstat and check + * Check if this hardlink carries the "payload". In "cpio" archives + * it's usually the last record of a set of hardlinks which includes + * the contents of the file. + * */ - if (lstat(arcn->ln_name, &sb) < 0) { - syswarn(1,errno,"Unable to link to %s from %s", arcn->ln_name, - arcn->name); - return(-1); - } + *payload = S_ISREG(arcn->sb.st_mode) && + (arcn->sb.st_size > 0) && (arcn->sb.st_size <= arcn->skip); - if (S_ISDIR(sb.st_mode)) { - paxwarn(1, "A hard link to the directory %s is not allowed", + /* + * We may be running as root, so we have to be sure that link target + * is not a directory, so we lstat and check. XXX: This is still racy. + */ + if (lstat(arcn->ln_name, &sb) != -1 && S_ISDIR(sb.st_mode)) { + tty_warn(1, "A hard link to the directory %s is not allowed", arcn->ln_name); - return(-1); + return -1; } - return(mk_link(arcn->ln_name, &sb, arcn->name, 0)); + return mk_link(arcn->ln_name, &sb, arcn->name, 0); } /* @@ -206,13 +300,13 @@ int cross_lnk(ARCHD *arcn) { /* - * try to make a link to original file (-l flag in copy mode). make sure - * we do not try to link to directories in case we are running as root - * (and it might succeed). + * try to make a link to original file (-l flag in copy mode). make + * sure we do not try to link to directories in case we are running as + * root (and it might succeed). */ if (arcn->type == PAX_DIR) - return(1); - return(mk_link(arcn->org_name, &(arcn->sb), arcn->name, 1)); + return 1; + return mk_link(arcn->org_name, &(arcn->sb), arcn->name, 1); } /* @@ -236,19 +330,19 @@ chk_same(ARCHD *arcn) * quietly */ if (lstat(arcn->name, &sb) < 0) - return(1); + return 1; if (kflag) - return(0); + return 0; /* * better make sure the user does not have src == dest by mistake */ if ((arcn->sb.st_dev == sb.st_dev) && (arcn->sb.st_ino == sb.st_ino)) { - paxwarn(1, "Unable to copy %s, file would overwrite itself", + tty_warn(1, "Unable to copy %s, file would overwrite itself", arcn->name); - return(0); + return 0; } - return(1); + return 1; } /* @@ -264,8 +358,7 @@ chk_same(ARCHD *arcn) */ static int -mk_link(char *to, struct stat *to_sb, char *from, - int ign) +mk_link(char *to, struct stat *to_sb, char *from, int ign) { struct stat sb; int oerrno; @@ -276,30 +369,30 @@ mk_link(char *to, struct stat *to_sb, char *from, */ if (lstat(from, &sb) == 0) { if (kflag) - return(0); + return 0; /* * make sure it is not the same file, protect the user */ if ((to_sb->st_dev==sb.st_dev)&&(to_sb->st_ino == sb.st_ino)) { - paxwarn(1, "Unable to link file %s to itself", to); - return(-1);; + tty_warn(1, "Cannot link file %s to itself", to); + return -1; } /* * try to get rid of the file, based on the type */ - if (S_ISDIR(sb.st_mode)) { + if (S_ISDIR(sb.st_mode) && strcmp(from, ".") != 0) { if (rmdir(from) < 0) { - syswarn(1, errno, "Unable to remove %s", from); - return(-1); + syswarn(1, errno, "Cannot remove %s", from); + return -1; } } else if (unlink(from) < 0) { if (!ign) { - syswarn(1, errno, "Unable to remove %s", from); - return(-1); + syswarn(1, errno, "Cannot remove %s", from); + return -1; } - return(1); + return 1; } } @@ -312,20 +405,20 @@ mk_link(char *to, struct stat *to_sb, char *from, if (link(to, from) == 0) break; oerrno = errno; - if (!nodirs && chk_path(from, to_sb->st_uid, to_sb->st_gid) == 0) + if (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, + syswarn(1, oerrno, "Cannot link to %s from %s", to, from); - return(-1); + return -1; } - return(1); + return 1; } /* * all right the link was made */ - return(0); + return 0; } /* @@ -345,6 +438,9 @@ node_creat(ARCHD *arcn) int pass = 0; mode_t file_mode; struct stat sb; + char target[MAXPATHLEN]; + char *nm = arcn->name; + int len; /* * create node based on type, if that fails try to unlink the node and @@ -352,36 +448,59 @@ node_creat(ARCHD *arcn) * file and link creation routines, this method seems to exhibit the * best performance in general use workloads. */ - file_mode = arcn->sb.st_mode & FILEBITS; + file_mode = arcn->sb.st_mode & FILEBITS(arcn->type == PAX_DIR); for (;;) { - switch(arcn->type) { + switch (arcn->type) { case PAX_DIR: - res = mkdir(arcn->name, file_mode); + /* + * If -h (or -L) was given in tar-mode, follow the + * potential symlink chain before trying to create the + * directory. + */ + if (strcmp(NM_TAR, argv0) == 0 && Lflag) { + while (lstat(nm, &sb) == 0 && + S_ISLNK(sb.st_mode)) { + len = readlink(nm, target, + sizeof target - 1); + if (len == -1) { + syswarn(0, errno, + "cannot follow symlink %s " + "in chain for %s", + nm, arcn->name); + res = -1; + goto badlink; + } + target[len] = '\0'; + nm = target; + } + } + res = domkdir(nm, file_mode); +badlink: if (ign) res = 0; break; case PAX_CHR: file_mode |= S_IFCHR; - res = mknod(arcn->name, file_mode, arcn->sb.st_rdev); + res = mknod(nm, file_mode, arcn->sb.st_rdev); break; case PAX_BLK: file_mode |= S_IFBLK; - res = mknod(arcn->name, file_mode, arcn->sb.st_rdev); + res = mknod(nm, file_mode, arcn->sb.st_rdev); break; case PAX_FIF: - res = mkfifo(arcn->name, file_mode); + res = mkfifo(nm, file_mode); break; case PAX_SCK: /* * Skip sockets, operation has no meaning under BSD */ - paxwarn(0, + tty_warn(0, "%s skipped. Sockets cannot be copied or extracted", - arcn->name); - return(-1); + nm); + return (-1); case PAX_SLK: - res = symlink(arcn->ln_name, arcn->name); + res = symlink(arcn->ln_name, nm); break; case PAX_CTG: case PAX_HLK: @@ -391,9 +510,9 @@ node_creat(ARCHD *arcn) /* * we should never get here */ - paxwarn(0, "%s has an unknown file type, skipping", - arcn->name); - return(-1); + tty_warn(0, "%s has an unknown file type, skipping", + nm); + return (-1); } /* @@ -408,41 +527,44 @@ node_creat(ARCHD *arcn) * we failed to make the node */ oerrno = errno; - if ((ign = unlnk_exist(arcn->name, arcn->type)) < 0) - return(-1); - - if (++pass <= 1) + switch (pass++) { + case 0: + if ((ign = unlnk_exist(nm, arcn->type)) < 0) + return (-1); continue; - 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); + case 1: + if (nodirs || + chk_path(nm, arcn->sb.st_uid, + arcn->sb.st_gid) < 0) { + syswarn(1, oerrno, "Cannot create %s", nm); + return (-1); + } + continue; } + + /* + * it must be a file that exists but we can't create or + * remove, but we must avoid the infinite loop. + */ + break; } /* * we were able to create the node. set uid/gid, modes and times */ if (pids) - 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)); + res = set_ids(nm, 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 */ if (!pmode || res) - arcn->sb.st_mode &= ~(SETBITS); + arcn->sb.st_mode &= ~SETBITS(arcn->type == PAX_DIR); if (pmode) set_pmode(arcn->name, arcn->sb.st_mode); @@ -456,11 +578,11 @@ node_creat(ARCHD *arcn) * and modes will be fixed after the entire archive is read and * before pax exits. */ - if (access(arcn->name, R_OK | W_OK | X_OK) < 0) { - if (lstat(arcn->name, &sb) < 0) { - syswarn(0, errno,"Could not access %s (stat)", + if (access(nm, R_OK | W_OK | X_OK) < 0) { + if (lstat(nm, &sb) < 0) { + syswarn(0, errno,"Cannot access %s (stat)", arcn->name); - set_pmode(arcn->name,file_mode | S_IRWXU); + set_pmode(nm,file_mode | S_IRWXU); } else { /* * We have to add rights to the dir, so we make @@ -468,8 +590,9 @@ node_creat(ARCHD *arcn) * restored AS CREATED and not as stored if * pmode is not set. */ - set_pmode(arcn->name, - ((sb.st_mode & FILEBITS) | S_IRWXU)); + set_pmode(nm, ((sb.st_mode & + FILEBITS(arcn->type == PAX_DIR)) | + S_IRWXU)); if (!pmode) arcn->sb.st_mode = sb.st_mode; } @@ -478,14 +601,20 @@ node_creat(ARCHD *arcn) * we have to force the mode to what was set here, * since we changed it from the default as created. */ - add_dir(arcn->name, arcn->nlen, &(arcn->sb), 1); + add_dir(nm, arcn->nlen, &(arcn->sb), 1); } else if (pmode || patime || pmtime) - add_dir(arcn->name, arcn->nlen, &(arcn->sb), 0); + add_dir(nm, arcn->nlen, &(arcn->sb), 0); } if (patime || pmtime) - set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0); - return(0); + set_ftime(arcn->name, arcn->sb.st_mtime, + arcn->sb.st_atime, 0, (arcn->type == PAX_SLK) ? 1 : 0); + +#if HAVE_STRUCT_STAT_ST_FLAGS + if (pfflags && arcn->type != PAX_SLK) + set_chflags(arcn->name, arcn->sb.st_flags); +#endif + return 0; } /* @@ -509,39 +638,45 @@ unlnk_exist(char *name, int type) * the file does not exist, or -k we are done */ if (lstat(name, &sb) < 0) - return(0); + return 0; if (kflag) - return(-1); + return -1; if (S_ISDIR(sb.st_mode)) { /* * try to remove a directory, if it fails and we were going to - * create a directory anyway, tell the caller (return a 1) + * create a directory anyway, tell the caller (return a 1). + * + * don't try to remove the directory if the name is "." + * otherwise later file/directory creation fails. */ + if (strcmp(name, ".") == 0) + return 1; if (rmdir(name) < 0) { if (type == PAX_DIR) - return(1); - syswarn(1,errno,"Unable to remove directory %s", name); - return(-1); + return 1; + syswarn(1, errno, "Cannot remove directory %s", name); + return -1; } - return(0); + return 0; } /* * try to get rid of all non-directory type nodes */ if (unlink(name) < 0) { - syswarn(1, errno, "Could not unlink %s", name); - return(-1); + (void)fflush(listf); + syswarn(1, errno, "Cannot unlink %s", name); + return -1; } - return(0); + return 0; } /* * chk_path() * We were trying to create some kind of node in the file system and it * failed. chk_path() makes sure the path up to the node exists and is - * writeable. When we have to create a directory that is missing along the + * writable. When we have to create a directory that is missing along the * path somewhere, the directory we create will be set to the same * uid/gid as the file has (when uid and gid are being preserved). * NOTE: this routine is a real performance loss. It is only used as a @@ -552,7 +687,7 @@ unlnk_exist(char *name, int type) */ int -chk_path( char *name, uid_t st_uid, gid_t st_gid) +chk_path(char *name, uid_t st_uid, gid_t st_gid) { char *spt = name; struct stat sb; @@ -566,7 +701,8 @@ chk_path( char *name, uid_t st_uid, gid_t st_gid) for(;;) { /* - * work foward from the first / and check each part of the path + * work forward from the first / and check each part of + * the path */ spt = strchr(spt, '/'); if (spt == NULL) @@ -591,7 +727,7 @@ chk_path( char *name, uid_t st_uid, gid_t st_gid) * the path fails at this point, see if we can create the * needed directory and continue on */ - if (mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { + if (domkdir(name, S_IRWXU | S_IRWXG | S_IRWXO) == -1) { *spt = '/'; retval = -1; break; @@ -607,72 +743,98 @@ chk_path( char *name, uid_t st_uid, gid_t st_gid) (void)set_ids(name, st_uid, st_gid); /* - * make sure the user doen't have some strange umask that + * make sure the user doesn't have some strange umask that * causes this newly created directory to be unusable. We fix * the modes and restore them back to the creation default at * the end of pax */ if ((access(name, R_OK | W_OK | X_OK) < 0) && (lstat(name, &sb) == 0)) { - set_pmode(name, ((sb.st_mode & FILEBITS) | S_IRWXU)); + set_pmode(name, ((sb.st_mode & FILEBITS(0)) | + S_IRWXU)); add_dir(name, spt - name, &sb, 1); } *(spt++) = '/'; continue; } - return(retval); + /* + * We perform one final check here, because if someone else + * created the directory in parallel with us, we might return + * the wrong error code, even if the directory exists now. + */ + if (retval == -1 && stat(name, &sb) == 0 && S_ISDIR(sb.st_mode)) + retval = 0; + return retval; } /* * set_ftime() - * Set the access time and modification time for a named file. If frc is - * non-zero we force these times to be set even if the user did not + * Set the access time and modification time for a named file. If frc + * is non-zero we force these times to be set even if the user did not * request access and/or modification time preservation (this is also * used by -t to reset access times). * When ign is zero, only those times the user has asked for are set, the * other ones are left alone. We do not assume the un-documented feature * of many utimes() implementations that consider a 0 time value as a do * not set request. + * + * Unfortunately, there are systems where lutimes() is present but does + * not work on some filesystem types, which cannot be detected at + * compile time. This requires passing down symlink knowledge into + * this function to obtain correct operation. Linux with XFS is one + * example of such a system. */ void -set_ftime(char *fnm, time_t mtime, time_t atime, int frc) +set_ftime(char *fnm, time_t mtime, time_t atime, int frc, int slk) { -#if 0 - static struct timeval tv[2] = {{0L, 0L}, {0L, 0L}}; -#endif + struct timeval tv[2]; struct stat sb; - struct utimbuf ut; - -#if 0 - tv[0].tv_sec = atime; - tv[1].tv_sec = mtime; -#endif - - ut.actime = atime; - ut.modtime = mtime; + tv[0].tv_sec = (long)atime; + tv[0].tv_usec = 0; + tv[1].tv_sec = (long)mtime; + tv[1].tv_usec = 0; if (!frc && (!patime || !pmtime)) { /* * if we are not forcing, only set those times the user wants * set. We get the current values of the times if we need them. */ if (lstat(fnm, &sb) == 0) { +#if BSD4_4 && !HAVE_NBTOOL_CONFIG_H + if (!patime) + TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec); + if (!pmtime) + TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec); +#else if (!patime) - ut.actime = sb.st_atime; + tv[0].tv_sec = sb.st_atime; if (!pmtime) - ut.modtime = sb.st_mtime; + tv[1].tv_sec = sb.st_mtime; +#endif } else - syswarn(0,errno,"Unable to obtain file stats %s", fnm); + syswarn(0, errno, "Cannot obtain file stats %s", fnm); } /* * set the times */ - if (utime(fnm, &ut) < 0) - syswarn(1, errno, "Access/modification time set failed on: %s", - fnm); +#if HAVE_LUTIMES + if (lutimes(fnm, tv) == 0) + return; + if (errno != ENOSYS) /* XXX linux: lutimes is per-FS */ + goto bad; +#endif + if (slk) + return; +#ifndef __minix +/* LSC: FIXME UGLY Hack */ + if (utimes(fnm, tv) == -1) + goto bad; +#endif return; +bad: + syswarn(1, errno, "Access/modification time set failed on: %s", fnm); } /* @@ -685,60 +847,44 @@ set_ftime(char *fnm, time_t mtime, time_t atime, int frc) int set_ids(char *fnm, uid_t uid, gid_t gid) { - if (chown(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", + if (geteuid() == 0) + if (lchown(fnm, uid, gid)) { + (void)fflush(listf); + syswarn(1, errno, "Cannot set file uid/gid of %s", fnm); - return(-1); - } - return(0); + return -1; + } + return 0; } /* - * set_lids() - * set the uid and gid of a file system node - * Return: - * 0 when set, -1 on failure + * set_pmode() + * Set file access mode */ -int -set_lids(char *fnm, uid_t uid, gid_t gid) +void +set_pmode(char *fnm, mode_t mode) { - -#if 0 - 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); + mode &= A_BITS; + if (lchmod(fnm, mode)) { + (void)fflush(listf); + syswarn(1, errno, "Cannot set permissions on %s", fnm); } -#else - return(-1); /* No lchown() in minix. */ -#endif - return(0); + return; } /* - * set_pmode() - * Set file access mode + * set_chflags() + * Set 4.4BSD file flags */ - void -set_pmode(char *fnm, mode_t mode) +set_chflags(char *fnm, u_int32_t flags) { - mode &= ABITS; - if (chmod(fnm, mode) < 0) - syswarn(1, errno, "Could not set permissions on %s", fnm); + +#if 0 + if (chflags(fnm, flags) < 0 && errno != EOPNOTSUPP) + syswarn(1, errno, "Cannot set file flags on %s", fnm); +#endif return; } @@ -761,11 +907,11 @@ set_pmode(char *fnm, mode_t mode) * uses lseek whenever it detects the input data is all 0 within that * file block. In more detail, the strategy is as follows: * While the input is all zero keep doing an lseek. Keep track of when we - * pass over file block boundries. Only write when we hit a non zero + * pass over file block boundaries. Only write when we hit a non zero * input. once we have written a file block, we continue to write it to * the end (we stop looking at the input). When we reach the start of the * next file block, start checking for zero blocks again. Working on file - * block boundries significantly reduces the overhead when copying files + * block boundaries significantly reduces the overhead when copying files * that are NOT very sparse. This overhead (when compared to a write) is * almost below the measurement resolution on many systems. Without it, * files with holes cannot be safely copied. It does has a side effect as @@ -798,6 +944,8 @@ file_write(int fd, char *str, int cnt, int *rem, int *isempt, int sz, char *end; int wcnt; char *st = str; + char **strp; + size_t *lenp; /* * while we have data to process @@ -838,10 +986,11 @@ file_write(int fd, char *str, int cnt, int *rem, int *isempt, int sz, /* * skip, buf is empty so far */ - if (lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) { - syswarn(1,errno,"File seek on %s", + if (fd > -1 && + lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) { + syswarn(1, errno, "File seek on %s", name); - return(-1); + return -1; } st = pt; continue; @@ -855,13 +1004,37 @@ file_write(int fd, char *str, int cnt, int *rem, int *isempt, int sz, /* * have non-zero data in this file system block, have to write */ - if (write(fd, st, wcnt) != wcnt) { + switch (fd) { + case -PAX_GLF: + strp = &gnu_name_string; + lenp = &gnu_name_length; + break; + case -PAX_GLL: + strp = &gnu_link_string; + lenp = &gnu_link_length; + break; + default: + strp = NULL; + lenp = NULL; + break; + } + if (strp) { + char *nstr = *strp ? realloc(*strp, *lenp + wcnt + 1) : + malloc(wcnt + 1); + if (nstr == NULL) { + tty_warn(1, "Out of memory"); + return -1; + } + (void)strlcpy(&nstr[*lenp], st, wcnt + 1); + *strp = nstr; + *lenp += wcnt; + } else if (xwrite(fd, st, wcnt) != wcnt) { syswarn(1, errno, "Failed write to file %s", name); - return(-1); + return -1; } st += wcnt; } - return(st - str); + return st - str; } /* @@ -891,14 +1064,14 @@ file_flush(int fd, char *fname, int isempt) return; } - if (write(fd, blnk, 1) < 0) + if (write_with_restart(fd, blnk, 1) < 0) syswarn(1, errno, "Failed write to file %s", fname); return; } /* * rdfile_close() - * close a file we have beed reading (to copy or archive). If we have to + * close a file we have been reading (to copy or archive). If we have to * reset access time (tflag) do so (the times are stored in arcn). */ @@ -919,7 +1092,7 @@ rdfile_close(ARCHD *arcn, int *fd) /* * user wants last access time reset */ - set_ftime(arcn->org_name, arcn->sb.st_mtime, arcn->sb.st_atime, 1); + set_ftime(arcn->org_name, arcn->sb.st_mtime, arcn->sb.st_atime, 1, 0); return; } @@ -938,7 +1111,7 @@ set_crc(ARCHD *arcn, int fd) int i; int res; off_t cpcnt = 0L; - u_long size = FILEBLK; + u_long size; unsigned long crc = 0L; char tbuf[FILEBLK]; struct stat sb; @@ -948,9 +1121,12 @@ set_crc(ARCHD *arcn, int fd) * hmm, no fd, should never happen. well no crc then. */ arcn->crc = 0L; - return(0); + return 0; } + if ((size = (u_long)arcn->sb.st_blksize) > (u_long)sizeof(tbuf)) + size = (u_long)sizeof(tbuf); + /* * read all the bytes we think that there are in the file. If the user * is trying to archive an active file, forget this file. @@ -965,19 +1141,19 @@ set_crc(ARCHD *arcn, int fd) /* * safety check. we want to avoid archiving files that are active as - * they can create inconsistant archive copies. + * they can create inconsistent archive copies. */ if (cpcnt != arcn->sb.st_size) - paxwarn(1, "File changed size %s", arcn->org_name); + tty_warn(1, "File changed size %s", arcn->org_name); else if (fstat(fd, &sb) < 0) syswarn(1, errno, "Failed stat on %s", arcn->org_name); else if (arcn->sb.st_mtime != sb.st_mtime) - paxwarn(1, "File %s was modified during read", arcn->org_name); + tty_warn(1, "File %s was modified during read", arcn->org_name); else if (lseek(fd, (off_t)0L, SEEK_SET) < 0) syswarn(1, errno, "File rewind failed on: %s", arcn->org_name); else { arcn->crc = crc; - return(0); + return 0; } - return(-1); + return -1; } diff --git a/commands/pax/ftree.c b/bin/pax/ftree.c similarity index 55% rename from commands/pax/ftree.c rename to bin/pax/ftree.c index 083fa8f9f..0d45429e1 100644 --- a/commands/pax/ftree.c +++ b/bin/pax/ftree.c @@ -1,3 +1,5 @@ +/* $NetBSD: ftree.c,v 1.42 2012/09/27 00:44:59 christos Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,24 +33,66 @@ * SUCH DAMAGE. */ -#ifndef lint +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Luke Mewburn of Wasabi Systems. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) #if 0 static char sccsid[] = "@(#)ftree.c 8.2 (Berkeley) 4/18/94"; +#else +__RCSID("$NetBSD: ftree.c,v 1.42 2012/09/27 00:44:59 christos Exp $"); #endif #endif /* not lint */ #include #include #include -#include -#include -#include +#include +#include #include -#include #include +#include +#include +#include +#include #include "pax.h" #include "ftree.h" #include "extern.h" +#include "options.h" +#ifndef SMALL +#include "mtree.h" +#endif /* SMALL */ /* * routines to interface with the fts library function. @@ -72,9 +116,14 @@ static FTREE *fttail = NULL; /* tail of linked list of file args */ static FTREE *ftcur = NULL; /* current file arg being processed */ static FTSENT *ftent = NULL; /* current file tree entry */ static int ftree_skip; /* when set skip to next file arg */ +#ifndef SMALL +static NODE *ftnode = NULL; /* mtree(8) specfile; used by -M */ +#endif /* SMALL */ static int ftree_arg(void); +#define FTS_ERRNO(x) (x)->fts_errno + /* * ftree_start() * initialize the options passed to fts_open() during this run of pax @@ -88,11 +137,35 @@ static int ftree_arg(void); int ftree_start(void) { + +#ifndef SMALL /* - * Set up the operation mode of fts, open the first file arg. We must + * if -M is given, the list of filenames on stdin is actually + * an mtree(8) specfile, so parse the specfile into a NODE * + * tree at ftnode, for use by next_file() + */ + if (Mflag) { + if (fthead != NULL) { + tty_warn(1, + "The -M flag is only supported when reading file list from stdin"); + return -1; + } + ftnode = spec(stdin); + if (ftnode != NULL && + (ftnode->type != F_DIR || strcmp(ftnode->name, ".") != 0)) { + tty_warn(1, + "First node of specfile is not `.' directory"); + return -1; + } + return 0; + } +#endif /* SMALL */ + + /* + * set up the operation mode of fts, open the first file arg. We must * use FTS_NOCHDIR, as the user may have to open multiple archives and * if fts did a chdir off into the boondocks, we may create an archive - * volume in a place where the user did not expect to. + * volume in an place where the user did not expect to. */ ftsopts = FTS_NOCHDIR; @@ -111,24 +184,20 @@ ftree_start(void) else ftsopts |= FTS_PHYSICAL; if (Hflag) -# ifdef NET2_FTS - paxwarn(0, "The -H flag is not supported on this version"); -# else ftsopts |= FTS_COMFOLLOW; -# endif if (Xflag) ftsopts |= FTS_XDEV; if ((fthead == NULL) && ((farray[0] = malloc(PAXPATHLEN+2)) == NULL)) { - paxwarn(1, "Unable to allocate memory for file name buffer"); - return(-1); + tty_warn(1, "Unable to allocate memory for file name buffer"); + return -1; } if (ftree_arg() < 0) - return(-1); + return -1; if (tflag && (atdir_start() < 0)) - return(-1); - return(0); + return -1; + return 0; } /* @@ -140,7 +209,7 @@ ftree_start(void) */ int -ftree_add(char *str, int chflg) +ftree_add(char *str, int isdir) { FTREE *ft; int len; @@ -149,8 +218,8 @@ ftree_add(char *str, int chflg) * simple check for bad args */ if ((str == NULL) || (*str == '\0')) { - paxwarn(0, "Invalid file name argument"); - return(-1); + tty_warn(0, "Invalid file name argument"); + return -1; } /* @@ -159,23 +228,22 @@ ftree_add(char *str, int chflg) * trailing / the user may pass us. (watch out for / by itself). */ if ((ft = (FTREE *)malloc(sizeof(FTREE))) == NULL) { - paxwarn(0, "Unable to allocate memory for filename"); - return(-1); + tty_warn(0, "Unable to allocate memory for filename"); + return -1; } if (((len = strlen(str) - 1) > 0) && (str[len] == '/')) str[len] = '\0'; ft->fname = str; - ft->refcnt = 0; - ft->chflg = chflg; + ft->refcnt = -isdir; ft->fow = NULL; if (fthead == NULL) { fttail = fthead = ft; - return(0); + return 0; } fttail->fow = ft; fttail = ft; - return(0); + return 0; } /* @@ -198,31 +266,20 @@ ftree_sel(ARCHD *arcn) /* * if -n we are done with this arg, force a skip to the next arg when * pax asks for the next file in next_file(). + * if -M we don't use fts(3), so the rest of this function is moot. * if -d we tell fts only to match the directory (if the arg is a dir) * and not the entire file tree rooted at that point. */ if (nflag) ftree_skip = 1; - if (!dflag || (arcn->type != PAX_DIR)) + if (Mflag || !dflag || (arcn->type != PAX_DIR)) return; if (ftent != NULL) (void)fts_set(ftsp, ftent, FTS_SKIP); } -/* - * ftree_notsel() - * this entry has not been selected by pax. - */ - -void -ftree_notsel() -{ - if (ftent != NULL) - (void)fts_set(ftsp, ftent, FTS_SKIP); -} - /* * ftree_chk() * called at end on pax execution. Prints all those file args that did not @@ -246,10 +303,11 @@ ftree_chk(void) * that never had a match */ for (ft = fthead; ft != NULL; ft = ft->fow) { - if ((ft->refcnt > 0) || ft->chflg) + if (ft->refcnt != 0) continue; if (wban == 0) { - paxwarn(1,"WARNING! These file names were not selected:"); + tty_warn(1, + "WARNING! These file names were not selected:"); ++wban; } (void)fprintf(stderr, "%s\n", ft->fname); @@ -269,14 +327,13 @@ ftree_chk(void) static int ftree_arg(void) { - char *pt; - /* * close off the current file tree */ if (ftsp != NULL) { (void)fts_close(ftsp); ftsp = NULL; + ftent = NULL; } /* @@ -285,14 +342,24 @@ ftree_arg(void) */ for(;;) { if (fthead == NULL) { + int i, c = EOF; /* * the user didn't supply any args, get the file trees * to process from stdin; */ - if (fgets(farray[0], PAXPATHLEN+1, stdin) == NULL) - return(-1); - if ((pt = strchr(farray[0], '\n')) != NULL) - *pt = '\0'; + for (i = 0; i < PAXPATHLEN + 2;) { + c = getchar(); + if (c == EOF) + break; + else if (c == sep) { + if (i != 0) + break; + } else + farray[0][i++] = c; + } + if (i == 0) + return -1; + farray[0][i] = '\0'; } else { /* * the user supplied the file args as arguments to pax @@ -300,27 +367,23 @@ ftree_arg(void) if (ftcur == NULL) ftcur = fthead; else if ((ftcur = ftcur->fow) == NULL) - return(-1); - 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); - } + return -1; + + if (ftcur->refcnt < 0) { + /* + * chdir entry. + * Change directory and retry loop. + */ + if (ar_dochdir(ftcur->fname)) + return (-1); continue; - } else - farray[0] = ftcur->fname; + } + farray[0] = ftcur->fname; } /* - * Watch it, fts wants the file arg stored in an array of char - * ptrs, with the last one a null. We use a two element array + * watch it, fts wants the file arg stored in a array of char + * ptrs, with the last one a null. we use a two element array * and set farray[0] to point at the buffer with the file name * in it. We cannot pass all the file args to fts at one shot * as we need to keep a handle on which file arg generates what @@ -330,7 +393,7 @@ ftree_arg(void) if ((ftsp = fts_open(farray, ftsopts, NULL)) != NULL) break; } - return(0); + return 0; } /* @@ -343,9 +406,151 @@ ftree_arg(void) int next_file(ARCHD *arcn) { - int cnt; - time_t atime; - time_t mtime; +#ifndef SMALL + static char curdir[PAXPATHLEN+2], curpath[PAXPATHLEN+2]; + static int curdirlen; + + struct stat statbuf; + FTSENT Mftent; +#endif /* SMALL */ + int cnt; + time_t atime, mtime; + char *curlink; +#define MFTENT_DUMMY_DEV UINT_MAX + + curlink = NULL; +#ifndef SMALL + /* + * if parsing an mtree(8) specfile, build up `dummy' ftsent + * from specfile info, and jump below to complete setup of arcn. + */ + if (Mflag) { + int skipoptional; + + next_ftnode: + skipoptional = 0; + if (ftnode == NULL) /* tree is empty */ + return (-1); + + /* get current name */ + if (snprintf(curpath, sizeof(curpath), "%s%s%s", + curdir, curdirlen ? "/" : "", ftnode->name) + >= (int)sizeof(curpath)) { + tty_warn(1, "line %lu: %s: %s", (u_long)ftnode->lineno, + curdir, strerror(ENAMETOOLONG)); + return (-1); + } + ftnode->flags |= F_VISIT; /* mark node visited */ + + /* construct dummy FTSENT */ + Mftent.fts_path = curpath; + Mftent.fts_statp = &statbuf; + Mftent.fts_pointer = ftnode; + ftent = &Mftent; + /* look for existing file */ + if (lstat(Mftent.fts_path, &statbuf) == -1) { + if (ftnode->flags & F_OPT) + skipoptional = 1; + + /* missing: fake up stat info */ + memset(&statbuf, 0, sizeof(statbuf)); + statbuf.st_dev = MFTENT_DUMMY_DEV; + statbuf.st_ino = ftnode->lineno; + statbuf.st_size = 0; +#define NODETEST(t, m) \ + if (!(t)) { \ + tty_warn(1, "line %lu: %s: %s not specified", \ + (u_long)ftnode->lineno, \ + ftent->fts_path, m); \ + return -1; \ + } + statbuf.st_mode = nodetoino(ftnode->type); + NODETEST(ftnode->flags & F_TYPE, "type"); + NODETEST(ftnode->flags & F_MODE, "mode"); + if (!(ftnode->flags & F_TIME)) + statbuf.st_mtime = starttime; + NODETEST(ftnode->flags & (F_GID | F_GNAME), "group"); + NODETEST(ftnode->flags & (F_UID | F_UNAME), "user"); + if (ftnode->type == F_BLOCK || ftnode->type == F_CHAR) + NODETEST(ftnode->flags & F_DEV, + "device number"); + if (ftnode->type == F_LINK) + NODETEST(ftnode->flags & F_SLINK, "symlink"); + /* don't require F_FLAGS or F_SIZE */ +#undef NODETEST + } else { + if (ftnode->flags & F_TYPE && nodetoino(ftnode->type) + != (statbuf.st_mode & S_IFMT)) { + tty_warn(1, + "line %lu: %s: type mismatch: specfile %s, tree %s", + (u_long)ftnode->lineno, ftent->fts_path, + inotype(nodetoino(ftnode->type)), + inotype(statbuf.st_mode)); + return -1; + } + if (ftnode->type == F_DIR && (ftnode->flags & F_OPT)) + skipoptional = 1; + } + /* + * override settings with those from specfile + */ + if (ftnode->flags & F_MODE) { + statbuf.st_mode &= ~ALLPERMS; + statbuf.st_mode |= (ftnode->st_mode & ALLPERMS); + } + if (ftnode->flags & (F_GID | F_GNAME)) + statbuf.st_gid = ftnode->st_gid; + if (ftnode->flags & (F_UID | F_UNAME)) + statbuf.st_uid = ftnode->st_uid; +#if HAVE_STRUCT_STAT_ST_FLAGS + if (ftnode->flags & F_FLAGS) + statbuf.st_flags = ftnode->st_flags; +#endif + if (ftnode->flags & F_TIME) +#if BSD4_4 && !HAVE_NBTOOL_CONFIG_H + statbuf.st_mtimespec = ftnode->st_mtimespec; +#else + statbuf.st_mtime = ftnode->st_mtimespec.tv_sec; +#endif + if (ftnode->flags & F_DEV) + statbuf.st_rdev = ftnode->st_rdev; + if (ftnode->flags & F_SLINK) + curlink = ftnode->slink; + /* ignore F_SIZE */ + + /* + * find next node + */ + if (ftnode->type == F_DIR && ftnode->child != NULL) { + /* directory with unseen child */ + ftnode = ftnode->child; + curdirlen = strlcpy(curdir, curpath, sizeof(curdir)); + } else do { + if (ftnode->next != NULL) { + /* next node at current level */ + ftnode = ftnode->next; + } else { /* move back to parent */ + /* reset time only on first cd.. */ + if (Mftent.fts_pointer == ftnode && tflag && + (get_atdir(MFTENT_DUMMY_DEV, ftnode->lineno, + &mtime, &atime) == 0)) { + set_ftime(ftent->fts_path, + mtime, atime, 1, 0); + } + ftnode = ftnode->parent; + if (ftnode->parent == ftnode) + ftnode = NULL; + else { + curdirlen -= strlen(ftnode->name) + 1; + curdir[curdirlen] = '\0'; + } + } + } while (ftnode != NULL && ftnode->flags & F_VISIT); + if (skipoptional) /* skip optional entries */ + goto next_ftnode; + goto got_ftent; + } +#endif /* SMALL */ /* * ftree_sel() might have set the ftree_skip flag if the user has the @@ -359,9 +564,11 @@ next_file(ARCHD *arcn) */ ftree_skip = 0; if (ftree_arg() < 0) - return(-1); + return -1; } + if (ftsp == NULL) + return -1; /* * loop until we get a valid file to process */ @@ -372,7 +579,7 @@ next_file(ARCHD *arcn) * we are done */ if (ftree_arg() < 0) - return(-1); + return -1; continue; } @@ -398,49 +605,37 @@ next_file(ARCHD *arcn) * remember to force the time (this is -t on a read * directory, not a created directory). */ -# ifdef NET2_FTS - if (!tflag || (get_atdir(ftent->fts_statb.st_dev, - ftent->fts_statb.st_ino, &mtime, &atime) < 0)) -# else - if (!tflag || (get_atdir(ftent->fts_statp->st_dev, - ftent->fts_statp->st_ino, &mtime, &atime) < 0)) -# endif + if (!tflag || (get_atdir( + ftent->fts_statp->st_dev, ftent->fts_statp->st_ino, + &mtime, &atime) < 0)) continue; - set_ftime(ftent->fts_path, mtime, atime, 1); + set_ftime(ftent->fts_path, mtime, atime, 1, 0); continue; case FTS_DC: /* * fts claims a file system cycle */ - paxwarn(1,"File system cycle found at %s",ftent->fts_path); + tty_warn(1,"File system cycle found at %s", + ftent->fts_path); continue; case FTS_DNR: -# ifdef NET2_FTS - syswarn(1, errno, -# else - syswarn(1, ftent->fts_errno, -# endif + syswarn(1, FTS_ERRNO(ftent), "Unable to read directory %s", ftent->fts_path); continue; case FTS_ERR: -# ifdef NET2_FTS - syswarn(1, errno, -# else - syswarn(1, ftent->fts_errno, -# endif + syswarn(1, FTS_ERRNO(ftent), "File system traversal error"); continue; case FTS_NS: case FTS_NSOK: -# ifdef NET2_FTS - syswarn(1, errno, -# else - syswarn(1, ftent->fts_errno, -# endif + syswarn(1, FTS_ERRNO(ftent), "Unable to access %s", ftent->fts_path); continue; } +#ifndef SMALL + got_ftent: +#endif /* SMALL */ /* * ok got a file tree node to process. copy info into arcn * structure (initialize as required) @@ -449,11 +644,7 @@ next_file(ARCHD *arcn) arcn->pad = 0; arcn->ln_nlen = 0; arcn->ln_name[0] = '\0'; -# ifdef NET2_FTS - arcn->sb = ftent->fts_statb; -# else arcn->sb = *(ftent->fts_statp); -# endif /* * file type based set up and copy into the arcn struct @@ -492,23 +683,27 @@ next_file(ARCHD *arcn) break; case S_IFLNK: arcn->type = PAX_SLK; + if (curlink != NULL) { + cnt = strlcpy(arcn->ln_name, curlink, + sizeof(arcn->ln_name)); /* * have to read the symlink path from the file */ - if ((cnt = readlink(ftent->fts_path, arcn->ln_name, - PAXPATHLEN - 1)) < 0) { + } else if ((cnt = + readlink(ftent->fts_path, arcn->ln_name, + sizeof(arcn->ln_name) - 1)) < 0) { syswarn(1, errno, "Unable to read symlink %s", ftent->fts_path); continue; } /* * set link name length, watch out readlink does not - * always NUL terminate the link path + * always null terminate the link path */ arcn->ln_name[cnt] = '\0'; arcn->ln_nlen = cnt; break; -#if 0 +#ifdef S_IFSOCK case S_IFSOCK: /* * under BSD storing a socket is senseless but we will @@ -528,8 +723,19 @@ next_file(ARCHD *arcn) /* * copy file name, set file name length */ - 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); + arcn->nlen = strlcpy(arcn->name, ftent->fts_path, sizeof(arcn->name)); + arcn->org_name = arcn->fts_name; + strlcpy(arcn->fts_name, ftent->fts_path, sizeof arcn->fts_name); + if (strcmp(NM_CPIO, argv0) == 0) { + /* + * cpio does *not* descend directories listed in the + * arguments, unlike pax/tar, so needs special handling + * here. failure to do so results in massive amounts + * of duplicated files in the output. We kill fts after + * the first name is extracted, what a waste. + */ + ftcur->refcnt = 1; + (void)ftree_arg(); + } + return 0; } diff --git a/commands/pax/ftree.h b/bin/pax/ftree.h similarity index 92% rename from commands/pax/ftree.h rename to bin/pax/ftree.h index fe18dcee9..490cf5190 100644 --- a/commands/pax/ftree.h +++ b/bin/pax/ftree.h @@ -1,3 +1,5 @@ +/* $NetBSD: ftree.h,v 1.5 2003/10/13 07:41:22 agc Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,7 +33,6 @@ * SUCH DAMAGE. * * @(#)ftree.h 8.1 (Berkeley) 5/31/93 - * $FreeBSD: src/bin/pax/ftree.h,v 1.7 2004/04/06 20:06:48 markm Exp $ */ /* @@ -43,6 +44,5 @@ 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/commands/pax/gen_subs.c b/bin/pax/gen_subs.c similarity index 66% rename from commands/pax/gen_subs.c rename to bin/pax/gen_subs.c index 5785a694a..1ffa95a36 100644 --- a/commands/pax/gen_subs.c +++ b/bin/pax/gen_subs.c @@ -1,3 +1,5 @@ +/* $NetBSD: gen_subs.c,v 1.36 2012/08/09 08:09:21 christos Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,22 +33,35 @@ * SUCH DAMAGE. */ -#ifndef lint +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) #if 0 static char sccsid[] = "@(#)gen_subs.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: gen_subs.c,v 1.36 2012/08/09 08:09:21 christos Exp $"); #endif #endif /* not lint */ #include #include #include -#include +#include + +#include +#include +#include +#include #include -#include -#include #include #include #include +#include +#include + #include "pax.h" #include "extern.h" @@ -59,17 +74,32 @@ static char sccsid[] = "@(#)gen_subs.c 8.1 (Berkeley) 5/31/93"; */ #define MODELEN 20 #define DATELEN 64 -#define SIXMONTHS ((365 / 2) * 86400) -#define CURFRMTM "%b %e %H:%M" -#define OLDFRMTM "%b %e %Y" -#define CURFRMTD "%e %b %H:%M" -#define OLDFRMTD "%e %b %Y" +#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY) +#define CURFRMT "%b %e %H:%M" +#define OLDFRMT "%b %e %Y" #ifndef UT_NAMESIZE #define UT_NAMESIZE 8 #endif #define UT_GRPSIZE 6 -static int d_first = -1; +/* + * convert time to string + */ +static void +formattime(char *buf, size_t buflen, time_t when) +{ + int error; + struct tm tm; + (void)localtime_r(&when, &tm); + + if (when + SIXMONTHS <= time(NULL)) + error = strftime(buf, buflen, OLDFRMT, &tm); + else + error = strftime(buf, buflen, CURFRMT, &tm); + + if (error == 0) + buf[0] = '\0'; +} /* * ls_list() @@ -82,7 +112,7 @@ ls_list(ARCHD *arcn, time_t now, FILE *fp) struct stat *sbp; char f_mode[MODELEN]; char f_date[DATELEN]; - const char *timefrmt; + const char *user, *group; /* * if not verbose, just print the file name @@ -93,54 +123,33 @@ ls_list(ARCHD *arcn, time_t now, FILE *fp) return; } - if (d_first < 0) - d_first = 0; /* * user wants long mode */ sbp = &(arcn->sb); -#if 0 strmode(sbp->st_mode, f_mode); -#else - strcpy(f_mode, ""); -#endif /* * time format based on age compared to the time pax was started. */ - if ((sbp->st_mtime + SIXMONTHS) <= now) - timefrmt = d_first ? OLDFRMTD : OLDFRMTM; - else - timefrmt = d_first ? CURFRMTD : CURFRMTM; - + formattime(f_date, sizeof(f_date), arcn->sb.st_mtime); /* * print file mode, link count, uid, gid and time */ -#if 0 - if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0) -#endif - f_date[0] = '\0'; - (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)); + user = user_from_uid(sbp->st_uid, 0); + group = group_from_gid(sbp->st_gid, 0); + (void)fprintf(fp, "%s%2lu %-*s %-*s ", f_mode, + (unsigned long)sbp->st_nlink, + UT_NAMESIZE, user ? user : "", UT_GRPSIZE, group ? group : ""); /* * print device id's for devices, or sizes for other nodes */ if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK)) -# ifdef NET2_STAT - (void)fprintf(fp, "%4u,%4u ", major(sbp->st_rdev), - minor(sbp->st_rdev)); -# else - (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)major(sbp->st_rdev), - (unsigned long)minor(sbp->st_rdev)); -# endif + (void)fprintf(fp, "%4lu,%4lu ", (long) MAJOR(sbp->st_rdev), + (long) MINOR(sbp->st_rdev)); else { -# ifdef NET2_STAT - (void)fprintf(fp, "%9lu ", sbp->st_size); -# else - (void)fprintf(fp, "%9ju ", (uintmax_t)sbp->st_size); -# endif + (void)fprintf(fp, OFFT_FP("9") " ", (OFFT_T)sbp->st_size); } /* @@ -150,16 +159,15 @@ ls_list(ARCHD *arcn, time_t now, FILE *fp) if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) (void)fprintf(fp, " == %s\n", arcn->ln_name); else if (arcn->type == PAX_SLK) - (void)fprintf(fp, " => %s\n", arcn->ln_name); + (void)fprintf(fp, " -> %s\n", arcn->ln_name); else - (void)putc('\n', fp); + (void)fputc('\n', fp); (void)fflush(fp); - return; } /* * tty_ls() - * print a short summary of file to tty. + * print a short summary of file to tty. */ void @@ -167,73 +175,47 @@ ls_tty(ARCHD *arcn) { char f_date[DATELEN]; char f_mode[MODELEN]; - const char *timefrmt; - - if (d_first < 0) - d_first = 0; - - if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL)) - timefrmt = d_first ? OLDFRMTD : OLDFRMTM; - else - timefrmt = d_first ? CURFRMTD : CURFRMTM; - /* - * convert time to string, and print - */ -#if 0 - if (strftime(f_date, DATELEN, timefrmt, - localtime(&(arcn->sb.st_mtime))) == 0) -#endif - f_date[0] = '\0'; -#if 0 + formattime(f_date, sizeof(f_date), arcn->sb.st_mtime); strmode(arcn->sb.st_mode, f_mode); -#else - strcpy(f_mode, ""); -#endif tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name); return; } -/* - * l_strncpy() - * 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(), a strlen(), and then a possible memset()) - */ - -int -l_strncpy(char *dest, const char *src, int len) +void +safe_print(const char *str, FILE *fp) { - char *stop; - char *start; - - stop = dest + len; - start = dest; - while ((dest < stop) && (*src != '\0')) - *dest++ = *src++; - len = dest - start; - while (dest < stop) - *dest++ = '\0'; - return(len); + char visbuf[5]; + const char *cp; + + /* + * if printing to a tty, use vis(3) to print special characters. + */ + if (isatty(fileno(fp))) { + for (cp = str; *cp; cp++) { + (void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]); + (void)fputs(visbuf, fp); + } + } else { + (void)fputs(str, fp); + } } /* - * asc_ul() - * convert hex/octal character string into a u_long. We do not have to + * asc_u32() + * convert hex/octal character string into a uint32_t. We do not have to * check for overflow! (the headers in all supported formats are not large * enough to create an overflow). * NOTE: strings passed to us are NOT TERMINATED. * Return: - * unsigned long value + * uint32_t value */ -u_long -asc_ul(char *str, int len, int base) +uint32_t +asc_u32(char *str, int len, int base) { char *stop; - u_long tval = 0; + uint32_t tval = 0; stop = str + len; @@ -259,24 +241,31 @@ asc_ul(char *str, int len, int base) break; } } else { - while ((str < stop) && (*str >= '0') && (*str <= '7')) + while ((str < stop) && (*str >= '0') && (*str <= '7')) tval = (tval << 3) + (*str++ - '0'); } - return(tval); + return tval; } /* - * ul_asc() - * convert an unsigned long into an hex/oct ascii string. pads with LEADING + * u32_asc() + * convert an uintmax_t into an hex/oct ascii string. pads with LEADING * ascii 0's to fill string completely * NOTE: the string created is NOT TERMINATED. */ int -ul_asc(u_long val, char *str, int len, int base) +u32_asc(uintmax_t val, char *str, int len, int base) { char *pt; - u_long digit; + uint32_t digit; + uintmax_t p; + + p = val & TOP_HALF; + if (p && p != TOP_HALF) + return -1; + + val &= BOTTOM_HALF; /* * WARNING str is not '\0' terminated by this routine @@ -300,7 +289,7 @@ ul_asc(u_long val, char *str, int len, int base) } else { while (pt >= str) { *pt-- = '0' + (char)(val & 0x7); - if ((val = (val >> 3)) == (u_long)0) + if ((val = (val >> 3)) == 0) break; } } @@ -310,27 +299,26 @@ ul_asc(u_long val, char *str, int len, int base) */ while (pt >= str) *pt-- = '0'; - if (val != (u_long)0) - return(-1); - return(0); + if (val != 0) + return -1; + return 0; } -#ifndef NET2_STAT /* - * asc_uqd() - * convert hex/octal character string into a u_quad_t. We do not have to - * check for overflow! (the headers in all supported formats are not large - * enough to create an overflow). + * asc_umax() + * convert hex/octal character string into a uintmax. We do + * not have to to check for overflow! (the headers in all supported + * formats are not large enough to create an overflow). * NOTE: strings passed to us are NOT TERMINATED. * Return: - * u_quad_t value + * uintmax_t value */ -u_quad_t -asc_uqd(char *str, int len, int base) +uintmax_t +asc_umax(char *str, int len, int base) { char *stop; - u_quad_t tval = 0; + uintmax_t tval = 0; stop = str + len; @@ -356,24 +344,24 @@ asc_uqd(char *str, int len, int base) break; } } else { - while ((str < stop) && (*str >= '0') && (*str <= '7')) + while ((str < stop) && (*str >= '0') && (*str <= '7')) tval = (tval << 3) + (*str++ - '0'); } - return(tval); + return tval; } /* - * uqd_asc() - * convert an u_quad_t into a hex/oct ascii string. pads with LEADING - * ascii 0's to fill string completely + * umax_asc() + * convert an uintmax_t into a hex/oct ascii string. pads with + * LEADING ascii 0's to fill string completely * NOTE: the string created is NOT TERMINATED. */ int -uqd_asc(u_quad_t val, char *str, int len, int base) +umax_asc(uintmax_t val, char *str, int len, int base) { char *pt; - u_quad_t digit; + uintmax_t digit; /* * WARNING str is not '\0' terminated by this routine @@ -391,13 +379,13 @@ uqd_asc(u_quad_t val, char *str, int len, int base) *pt-- = '0' + (char)digit; else *pt-- = 'a' + (char)(digit - 10); - if ((val = (val >> 4)) == (u_quad_t)0) + if ((val = (val >> 4)) == 0) break; } } else { while (pt >= str) { *pt-- = '0' + (char)(val & 0x7); - if ((val = (val >> 3)) == (u_quad_t)0) + if ((val = (val >> 3)) == 0) break; } } @@ -407,8 +395,21 @@ uqd_asc(u_quad_t val, char *str, int len, int base) */ while (pt >= str) *pt-- = '0'; - if (val != (u_quad_t)0) - return(-1); - return(0); + if (val != 0) + return -1; + return 0; +} + +int +check_Aflag(void) +{ + + if (Aflag > 0) + return 1; + if (Aflag == 0) { + Aflag = -1; + tty_warn(0, + "Removing leading / from absolute path names in the archive"); + } + return 0; } -#endif diff --git a/commands/pax/getoldopt.c b/bin/pax/getoldopt.c similarity index 52% rename from commands/pax/getoldopt.c rename to bin/pax/getoldopt.c index e077298c9..2d02e7e71 100644 --- a/commands/pax/getoldopt.c +++ b/bin/pax/getoldopt.c @@ -1,27 +1,40 @@ -/* $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 $ */ +/* $NetBSD: getoldopt.c,v 1.23 2012/08/09 11:05:59 christos 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. + * in the Public Domain for your edification and enjoyment. */ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif -#include -#include +#include +#if !defined(lint) +__RCSID("$NetBSD: getoldopt.c,v 1.23 2012/08/09 11:05:59 christos Exp $"); +#endif /* not lint */ + +#if HAVE_NBTOOL_CONFIG_H +#include "compat_getopt.h" +#else +#include +#endif #include #include +#include #include - +#include +#include #include "pax.h" #include "extern.h" int -getoldopt(int argc, char **argv, const char *optstring) +getoldopt(int argc, char **argv, const char *optstring, + struct option *longopts, int *idx) { static char *key; /* Points to next keyletter */ static char use_getopt; /* !=0 if argv[1][0] was '-' */ @@ -31,7 +44,7 @@ getoldopt(int argc, char **argv, const char *optstring) optarg = NULL; if (key == NULL) { /* First time */ - if (argc < 2) return EOF; + if (argc < 2) return -1; key = argv[1]; if (*key == '-') use_getopt++; @@ -39,19 +52,28 @@ getoldopt(int argc, char **argv, const char *optstring) optind = 2; } - if (use_getopt) - return getopt(argc, argv, optstring); - - c = *key++; - if (c == '\0') { - key--; - return EOF; + c = '\0'; + if (!use_getopt) { + c = *key++; + if (c == '\0') { + key--; + use_getopt = 1; + } } + if (use_getopt) { + if (longopts != NULL) { + return getopt_long(argc, argv, optstring, + longopts, idx); + } else { + return getopt(argc, argv, optstring); + } + } + place = strchr(optstring, c); if (place == NULL || c == ':') { fprintf(stderr, "%s: unknown option %c\n", argv[0], c); - return('?'); + return '?'; } place++; @@ -62,9 +84,9 @@ getoldopt(int argc, char **argv, const char *optstring) } else { fprintf(stderr, "%s: %c argument missing\n", argv[0], c); - return('?'); + return '?'; } } - return(c); + return c; } diff --git a/bin/pax/options.c b/bin/pax/options.c new file mode 100644 index 000000000..c6c9eb908 --- /dev/null +++ b/bin/pax/options.c @@ -0,0 +1,2161 @@ +/* $NetBSD: options.c,v 1.114 2012/08/09 11:05:59 christos Exp $ */ + +/*- + * Copyright (c) 1992 Keith Muller. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) +#if 0 +static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 4/18/94"; +#else +__RCSID("$NetBSD: options.c,v 1.114 2012/08/09 11:05:59 christos Exp $"); +#endif +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#if HAVE_NBTOOL_CONFIG_H +#include "compat_getopt.h" +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include "pax.h" +#include "options.h" +#include "cpio.h" +#include "tar.h" +#include "extern.h" +#ifndef SMALL +#include "mtree.h" +#endif /* SMALL */ + +/* + * Routines which handle command line options + */ + +static int nopids; /* tar mode: suppress "pids" for -p option */ +static char flgch[] = FLGCH; /* list of all possible flags (pax) */ +static OPLIST *ophead = NULL; /* head for format specific options -x */ +static OPLIST *optail = NULL; /* option tail */ + +static int opt_add(const char *); +static int no_op(void); +static void printflg(unsigned int); +static int c_frmt(const void *, const void *); +static off_t str_offt(char *); +static char *get_line(FILE *fp); +static void pax_options(int, char **); +__dead static void pax_usage(void); +static void tar_options(int, char **); +__dead static void tar_usage(void); +#ifndef NO_CPIO +static void cpio_options(int, char **); +__dead static void cpio_usage(void); +#endif + +/* errors from get_line */ +#define GETLINE_FILE_CORRUPT 1 +#define GETLINE_OUT_OF_MEM 2 +static int get_line_error; + +#define BZIP2_CMD "bzip2" /* command to run as bzip2 */ +#define GZIP_CMD "gzip" /* command to run as gzip */ +#define XZ_CMD "xz" /* command to run as xz */ +#define COMPRESS_CMD "compress" /* command to run as compress */ + +/* + * Long options. + */ +#define OPT_USE_COMPRESS_PROGRAM 0 +#define OPT_CHECKPOINT 1 +#define OPT_UNLINK 2 +#define OPT_HELP 3 +#define OPT_ATIME_PRESERVE 4 +#define OPT_IGNORE_FAILED_READ 5 +#define OPT_REMOVE_FILES 6 +#define OPT_NULL 7 +#define OPT_TOTALS 8 +#define OPT_VERSION 9 +#define OPT_EXCLUDE 10 +#define OPT_BLOCK_COMPRESS 11 +#define OPT_NORECURSE 12 +#define OPT_FORCE_LOCAL 13 +#define OPT_INSECURE 14 +#define OPT_STRICT 15 +#define OPT_SPARSE 16 +#define OPT_XZ 17 +#if !HAVE_NBTOOL_CONFIG_H +#define OPT_CHROOT 18 +#endif + +/* + * Format specific routine table - MUST BE IN SORTED ORDER BY NAME + * (see pax.h for description of each function) + * + * name, blksz, hdsz, udev, hlk, blkagn, inhead, id, st_read, + * read, end_read, st_write, write, end_write, trail, + * subtrail, rd_data, wr_data, options + */ + +FSUB fsub[] = { +#ifndef NO_CPIO +/* 0: OLD BINARY CPIO */ + { "bcpio", 5120, sizeof(HD_BCPIO), 1, 0, 0, 1, bcpio_id, cpio_strd, + bcpio_rd, bcpio_endrd, cpio_stwr, bcpio_wr, cpio_endwr, NULL, + cpio_subtrail, rd_wrfile, wr_rdfile, bad_opt }, + +/* 1: OLD OCTAL CHARACTER CPIO */ + { "cpio", 5120, sizeof(HD_CPIO), 1, 0, 0, 1, cpio_id, cpio_strd, + cpio_rd, cpio_endrd, cpio_stwr, cpio_wr, cpio_endwr, NULL, + cpio_subtrail, rd_wrfile, wr_rdfile, bad_opt }, + +/* 2: SVR4 HEX CPIO */ + { "sv4cpio", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, vcpio_id, cpio_strd, + vcpio_rd, vcpio_endrd, cpio_stwr, vcpio_wr, cpio_endwr, NULL, + cpio_subtrail, rd_wrfile, wr_rdfile, bad_opt }, + +/* 3: SVR4 HEX CPIO WITH CRC */ + { "sv4crc", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd, + vcpio_rd, vcpio_endrd, crc_stwr, vcpio_wr, cpio_endwr, NULL, + cpio_subtrail, rd_wrfile, wr_rdfile, bad_opt }, +#endif +/* 4: OLD TAR */ + { "tar", 10240, BLKMULT, 0, 1, BLKMULT, 0, tar_id, no_op, + tar_rd, tar_endrd, no_op, tar_wr, tar_endwr, tar_trail, + NULL, rd_wrfile, wr_rdfile, tar_opt }, + +/* 5: POSIX USTAR */ + { "ustar", 10240, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, ustar_strd, + ustar_rd, tar_endrd, ustar_stwr, ustar_wr, tar_endwr, tar_trail, + NULL, rd_wrfile, wr_rdfile, bad_opt } +}; +#ifndef NO_CPIO +#define F_BCPIO 0 /* old binary cpio format */ +#define F_CPIO 1 /* old octal character cpio format */ +#define F_SV4CPIO 2 /* SVR4 hex cpio format */ +#define F_SV4CRC 3 /* SVR4 hex with crc cpio format */ +#define F_TAR 4 /* old V7 UNIX tar format */ +#define F_USTAR 5 /* ustar format */ +#else +#define F_TAR 0 /* old V7 UNIX tar format */ +#define F_USTAR 1 /* ustar format */ +#endif +#define DEFLT F_USTAR /* default write format from list above */ + +/* + * ford is the archive search order used by get_arc() to determine what kind + * of archive we are dealing with. This helps to properly id archive formats + * some formats may be subsets of others.... + */ +int ford[] = {F_USTAR, F_TAR, +#ifndef NO_CPIO + F_SV4CRC, F_SV4CPIO, F_CPIO, F_BCPIO, +#endif + -1}; + +/* + * filename record separator + */ +int sep = '\n'; + +/* + * Do we have -C anywhere? + */ +int havechd = 0; + +/* + * options() + * figure out if we are pax, tar or cpio. Call the appropriate options + * parser + */ + +void +options(int argc, char **argv) +{ + + /* + * Are we acting like pax, tar or cpio (based on argv[0]) + */ + if ((argv0 = strrchr(argv[0], '/')) != NULL) + argv0++; + else + argv0 = argv[0]; + + if (strstr(argv0, NM_TAR)) { + argv0 = NM_TAR; + tar_options(argc, argv); +#ifndef NO_CPIO + } else if (strstr(argv0, NM_CPIO)) { + argv0 = NM_CPIO; + cpio_options(argc, argv); +#endif + } else { + argv0 = NM_PAX; + pax_options(argc, argv); + } +} + +struct option pax_longopts[] = { + { "insecure", no_argument, 0, + OPT_INSECURE }, + { "force-local", no_argument, 0, + OPT_FORCE_LOCAL }, + { "use-compress-program", required_argument, 0, + OPT_USE_COMPRESS_PROGRAM }, + { "xz", no_argument, 0, + OPT_XZ }, + { 0, 0, 0, + 0 }, +}; + +/* + * pax_options() + * look at the user specified flags. set globals as required and check if + * the user specified a legal set of flags. If not, complain and exit + */ + +static void +pax_options(int argc, char **argv) +{ + int c; + size_t i; + u_int64_t flg = 0; + u_int64_t bflg = 0; + char *pt; + FSUB tmp; + + /* + * process option flags + */ + while ((c = getopt_long(argc, argv, + "0ab:cdf:ijklno:p:rs:tuvwx:zAB:DE:G:HLMN:OPT:U:VXYZ", + pax_longopts, NULL)) != -1) { + switch (c) { + case '0': + sep = '\0'; + break; + case 'a': + /* + * append + */ + flg |= AF; + break; + case 'b': + /* + * specify blocksize + */ + flg |= BF; + if ((wrblksz = (int)str_offt(optarg)) <= 0) { + tty_warn(1, "Invalid block size %s", optarg); + pax_usage(); + } + break; + case 'c': + /* + * inverse match on patterns + */ + cflag = 1; + flg |= CF; + break; + case 'd': + /* + * match only dir on extract, not the subtree at dir + */ + dflag = 1; + flg |= DF; + break; + case 'f': + /* + * filename where the archive is stored + */ + arcname = optarg; + flg |= FF; + break; + case 'i': + /* + * interactive file rename + */ + iflag = 1; + flg |= IF; + break; + case 'j': + /* + * pass through bzip2 + */ + gzip_program = BZIP2_CMD; + break; + case 'k': + /* + * do not clobber files that exist + */ + kflag = 1; + flg |= KF; + break; + case 'l': + /* + * try to link src to dest with copy (-rw) + */ + lflag = 1; + flg |= LF; + break; + case 'n': + /* + * select first match for a pattern only + */ + nflag = 1; + flg |= NF; + break; + case 'o': + /* + * pass format specific options + */ + flg |= OF; + if (opt_add(optarg) < 0) + pax_usage(); + break; + case 'p': + /* + * specify file characteristic options + */ + for (pt = optarg; *pt != '\0'; ++pt) { + switch(*pt) { + case 'a': + /* + * do not preserve access time + */ + patime = 0; + break; + case 'e': + /* + * preserve user id, group id, file + * mode, access/modification times + * and file flags. + */ + pids = 1; + pmode = 1; + patime = 1; + pmtime = 1; + pfflags = 1; + break; +#if 0 + case 'f': + /* + * do not preserve file flags + */ + pfflags = 0; + break; +#endif + case 'm': + /* + * do not preserve modification time + */ + pmtime = 0; + break; + case 'o': + /* + * preserve uid/gid + */ + pids = 1; + break; + case 'p': + /* + * preserve file mode bits + */ + pmode = 1; + break; + default: + tty_warn(1, "Invalid -p string: %c", + *pt); + pax_usage(); + break; + } + } + flg |= PF; + break; + case 'r': + /* + * read the archive + */ + flg |= RF; + break; + case 's': + /* + * file name substitution name pattern + */ + if (rep_add(optarg) < 0) { + pax_usage(); + break; + } + flg |= SF; + break; + case 't': + /* + * preserve access time on filesystem nodes we read + */ + tflag = 1; + flg |= TF; + break; + case 'u': + /* + * ignore those older files + */ + uflag = 1; + flg |= UF; + break; + case 'v': + /* + * verbose operation mode + */ + vflag = 1; + flg |= VF; + break; + case 'w': + /* + * write an archive + */ + flg |= WF; + break; + case 'x': + /* + * specify an archive format on write + */ + tmp.name = optarg; + frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub, + sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt); + if (frmt != NULL) { + flg |= XF; + break; + } + tty_warn(1, "Unknown -x format: %s", optarg); + (void)fputs("pax: Known -x formats are:", stderr); + for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i) + (void)fprintf(stderr, " %s", fsub[i].name); + (void)fputs("\n\n", stderr); + pax_usage(); + break; + case 'z': + /* + * use gzip. Non standard option. + */ + gzip_program = GZIP_CMD; + break; + case 'A': + Aflag = 1; + flg |= CAF; + break; + case 'B': + /* + * non-standard option on number of bytes written on a + * single archive volume. + */ + if ((wrlimit = str_offt(optarg)) <= 0) { + tty_warn(1, "Invalid write limit %s", optarg); + pax_usage(); + } + if (wrlimit % BLKMULT) { + tty_warn(1, + "Write limit is not a %d byte multiple", + BLKMULT); + pax_usage(); + } + flg |= CBF; + break; + case 'D': + /* + * On extraction check file inode change time before the + * modification of the file name. Non standard option. + */ + Dflag = 1; + flg |= CDF; + break; + case 'E': + /* + * non-standard limit on read faults + * 0 indicates stop after first error, values + * indicate a limit, "none" try forever + */ + flg |= CEF; + if (strcmp(none, optarg) == 0) + maxflt = -1; + else if ((maxflt = atoi(optarg)) < 0) { + tty_warn(1, + "Error count value must be positive"); + pax_usage(); + } + break; + case 'G': + /* + * non-standard option for selecting files within an + * archive by group (gid or name) + */ + if (grp_add(optarg) < 0) { + pax_usage(); + break; + } + flg |= CGF; + break; + case 'H': + /* + * follow command line symlinks only + */ + Hflag = 1; + flg |= CHF; + break; + case 'L': + /* + * follow symlinks + */ + Lflag = 1; + flg |= CLF; + break; +#ifdef SMALL + case 'M': + case 'N': + tty_warn(1, "Support for -%c is not compiled in", c); + exit(1); +#else /* !SMALL */ + case 'M': + /* + * Treat list of filenames on stdin as an + * mtree(8) specfile. Non standard option. + */ + Mflag = 1; + flg |= CMF; + break; + case 'N': + /* + * Use alternative directory for user db lookups. + */ + if (!setup_getid(optarg)) { + tty_warn(1, + "Unable to use user and group databases in `%s'", + optarg); + pax_usage(); + } + break; +#endif /* !SMALL */ + case 'O': + /* + * Force one volume. Non standard option. + */ + force_one_volume = 1; + break; + case 'P': + /* + * do NOT follow symlinks (default) + */ + Lflag = 0; + flg |= CPF; + break; + case 'T': + /* + * non-standard option for selecting files within an + * archive by modification time range (lower,upper) + */ + if (trng_add(optarg) < 0) { + pax_usage(); + break; + } + flg |= CTF; + break; + case 'U': + /* + * non-standard option for selecting files within an + * archive by user (uid or name) + */ + if (usr_add(optarg) < 0) { + pax_usage(); + break; + } + flg |= CUF; + break; + case 'V': + /* + * somewhat verbose operation mode (no listing) + */ + Vflag = 1; + flg |= VSF; + break; + case 'X': + /* + * do not pass over mount points in the file system + */ + Xflag = 1; + flg |= CXF; + break; + case 'Y': + /* + * On extraction check file inode change time after the + * modification of the file name. Non standard option. + */ + Yflag = 1; + flg |= CYF; + break; + case 'Z': + /* + * On extraction check modification time after the + * modification of the file name. Non standard option. + */ + Zflag = 1; + flg |= CZF; + break; + case OPT_INSECURE: + secure = 0; + break; + case OPT_FORCE_LOCAL: + forcelocal = 1; + break; + case OPT_USE_COMPRESS_PROGRAM: + gzip_program = optarg; + break; + case OPT_XZ: + gzip_program = XZ_CMD; + break; + case '?': + default: + pax_usage(); + break; + } + } + + /* + * figure out the operation mode of pax read,write,extract,copy,append + * or list. check that we have not been given a bogus set of flags + * for the operation mode. + */ + if (ISLIST(flg)) { + act = LIST; + listf = stdout; + bflg = flg & BDLIST; + } else if (ISEXTRACT(flg)) { + act = EXTRACT; + bflg = flg & BDEXTR; + } else if (ISARCHIVE(flg)) { + act = ARCHIVE; + bflg = flg & BDARCH; + } else if (ISAPPND(flg)) { + act = APPND; + bflg = flg & BDARCH; + } else if (ISCOPY(flg)) { + act = COPY; + bflg = flg & BDCOPY; + } else + pax_usage(); + if (bflg) { + printflg(flg); + pax_usage(); + } + + /* + * if we are writing (ARCHIVE) we use the default format if the user + * did not specify a format. when we write during an APPEND, we will + * adopt the format of the existing archive if none was supplied. + */ + if (!(flg & XF) && (act == ARCHIVE)) + frmt = &(fsub[DEFLT]); + + /* + * process the args as they are interpreted by the operation mode + */ + switch (act) { + case LIST: + case EXTRACT: + for (; optind < argc; optind++) + if (pat_add(argv[optind], NULL, 0) < 0) + pax_usage(); + break; + case COPY: + if (optind >= argc) { + tty_warn(0, "Destination directory was not supplied"); + pax_usage(); + } + --argc; + dirptr = argv[argc]; + if (mkpath(dirptr) < 0) + exit(1); + /* FALLTHROUGH */ + case ARCHIVE: + case APPND: + for (; optind < argc; optind++) + if (ftree_add(argv[optind], 0) < 0) + pax_usage(); + /* + * no read errors allowed on updates/append operation! + */ + maxflt = 0; + break; + } +} + + +/* + * tar_options() + * look at the user specified flags. set globals as required and check if + * the user specified a legal set of flags. If not, complain and exit + */ + +struct option tar_longopts[] = { + { "block-size", required_argument, 0, 'b' }, + { "bunzip2", no_argument, 0, 'j' }, + { "bzip2", no_argument, 0, 'j' }, + { "create", no_argument, 0, 'c' }, /* F */ + /* -e -- no corresponding long option */ + { "file", required_argument, 0, 'f' }, + { "dereference", no_argument, 0, 'h' }, + { "keep-old-files", no_argument, 0, 'k' }, + { "one-file-system", no_argument, 0, 'l' }, + { "modification-time", no_argument, 0, 'm' }, + { "old-archive", no_argument, 0, 'o' }, + { "portability", no_argument, 0, 'o' }, + { "same-permissions", no_argument, 0, 'p' }, + { "preserve-permissions", no_argument, 0, 'p' }, + { "preserve", no_argument, 0, 'p' }, + { "fast-read", no_argument, 0, 'q' }, + { "append", no_argument, 0, 'r' }, /* F */ + { "update", no_argument, 0, 'u' }, /* F */ + { "list", no_argument, 0, 't' }, /* F */ + { "verbose", no_argument, 0, 'v' }, + { "interactive", no_argument, 0, 'w' }, + { "confirmation", no_argument, 0, 'w' }, + { "extract", no_argument, 0, 'x' }, /* F */ + { "get", no_argument, 0, 'x' }, /* F */ + { "gzip", no_argument, 0, 'z' }, + { "gunzip", no_argument, 0, 'z' }, + { "read-full-blocks", no_argument, 0, 'B' }, + { "directory", required_argument, 0, 'C' }, + { "to-stdout", no_argument, 0, 'O' }, + { "absolute-paths", no_argument, 0, 'P' }, + { "sparse", no_argument, 0, 'S' }, + { "files-from", required_argument, 0, 'T' }, + { "summary", no_argument, 0, 'V' }, + { "stats", no_argument, 0, 'V' }, + { "exclude-from", required_argument, 0, 'X' }, + { "compress", no_argument, 0, 'Z' }, + { "uncompress", no_argument, 0, 'Z' }, + { "strict", no_argument, 0, + OPT_STRICT }, + { "atime-preserve", no_argument, 0, + OPT_ATIME_PRESERVE }, + { "unlink", no_argument, 0, + OPT_UNLINK }, + { "use-compress-program", required_argument, 0, + OPT_USE_COMPRESS_PROGRAM }, + { "force-local", no_argument, 0, + OPT_FORCE_LOCAL }, + { "insecure", no_argument, 0, + OPT_INSECURE }, + { "exclude", required_argument, 0, + OPT_EXCLUDE }, + { "no-recursion", no_argument, 0, + OPT_NORECURSE }, + { "xz", no_argument, 0, + OPT_XZ }, +#if !HAVE_NBTOOL_CONFIG_H + { "chroot", no_argument, 0, + OPT_CHROOT }, +#endif +#if 0 /* Not implemented */ + { "catenate", no_argument, 0, 'A' }, /* F */ + { "concatenate", no_argument, 0, 'A' }, /* F */ + { "diff", no_argument, 0, 'd' }, /* F */ + { "compare", no_argument, 0, 'd' }, /* F */ + { "checkpoint", no_argument, 0, + OPT_CHECKPOINT }, + { "help", no_argument, 0, + OPT_HELP }, + { "info-script", required_argument, 0, 'F' }, + { "new-volume-script", required_argument, 0, 'F' }, + { "incremental", no_argument, 0, 'G' }, + { "listed-incremental", required_argument, 0, 'g' }, + { "ignore-zeros", no_argument, 0, 'i' }, + { "ignore-failed-read", no_argument, 0, + OPT_IGNORE_FAILED_READ }, + { "starting-file", no_argument, 0, 'K' }, + { "tape-length", required_argument, 0, 'L' }, + { "multi-volume", no_argument, 0, 'M' }, + { "after-date", required_argument, 0, 'N' }, + { "newer", required_argument, 0, 'N' }, + { "record-number", no_argument, 0, 'R' }, + { "remove-files", no_argument, 0, + OPT_REMOVE_FILES }, + { "same-order", no_argument, 0, 's' }, + { "preserve-order", no_argument, 0, 's' }, + { "null", no_argument, 0, + OPT_NULL }, + { "totals", no_argument, 0, + OPT_TOTALS }, + { "volume-name", required_argument, 0, 'V' }, /* XXX */ + { "label", required_argument, 0, 'V' }, /* XXX */ + { "version", no_argument, 0, + OPT_VERSION }, + { "verify", no_argument, 0, 'W' }, + { "block-compress", no_argument, 0, + OPT_BLOCK_COMPRESS }, +#endif + { 0, 0, 0, 0 }, +}; + +static void +tar_set_action(int op) +{ + if (act != ERROR && act != op) + tar_usage(); + act = op; +} + +static void +tar_options(int argc, char **argv) +{ + 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; + is_gnutar = 1; + + /* + * process option flags + */ + while ((c = getoldopt(argc, argv, + "+b:cef:hjklmopqrs:tuvwxzBC:HI:OPST:X:Z014578", + tar_longopts, NULL)) + != -1) { + switch(c) { + case 'b': + /* + * specify blocksize in 512-byte blocks + */ + if ((wrblksz = (int)str_offt(optarg)) <= 0) { + tty_warn(1, "Invalid block size %s", optarg); + tar_usage(); + } + wrblksz *= 512; /* XXX - check for int oflow */ + break; + case 'c': + /* + * create an archive + */ + tar_set_action(ARCHIVE); + break; + case 'e': + /* + * stop after first error + */ + maxflt = 0; + break; + case 'f': + /* + * filename where the archive is stored + */ + if ((optarg[0] == '-') && (optarg[1]== '\0')) { + /* + * treat a - as stdin + */ + fstdin = 1; + arcname = NULL; + break; + } + fstdin = 0; + arcname = optarg; + break; + case 'h': + /* + * follow symlinks + */ + Lflag = 1; + break; + case 'j': + /* + * pass through bzip2. not a standard option + */ + gzip_program = BZIP2_CMD; + break; + case 'k': + /* + * do not clobber files that exist + */ + kflag = 1; + break; + case 'l': + /* + * do not pass over mount points in the file system + */ + Xflag = 1; + break; + case 'm': + /* + * do not preserve modification time + */ + pmtime = 0; + break; + case 'o': + /* + * This option does several things based on whether + * this is a create or extract operation. + */ + if (act == ARCHIVE) { + /* GNU tar: write V7 format archives. */ + Oflag = 1; + /* 4.2BSD: don't add directory entries. */ + if (opt_add("write_opt=nodir") < 0) + tar_usage(); + + } else { + /* SUS: don't preserve owner/group. */ + pids = 0; + nopids = 1; + } + break; + case 'O': + Oflag = 1; + break; + case 'p': + /* + * preserve user id, group id, file + * mode, access/modification times + */ + if (!nopids) + pids = 1; + pmode = 1; + patime = 1; + pmtime = 1; + break; + case 'q': + /* + * select first match for a pattern only + */ + nflag = 1; + break; + case 'r': + case 'u': + /* + * append to the archive + */ + tar_set_action(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 + */ + tar_set_action(LIST); + break; + case 'v': + /* + * verbose operation mode + */ + vflag = 1; + break; + case 'w': + /* + * interactive file rename + */ + iflag = 1; + break; + case 'x': + /* + * extract an archive, preserving mode, + * and mtime if possible. + */ + tar_set_action(EXTRACT); + pmtime = 1; + break; + case 'z': + /* + * use gzip. Non standard option. + */ + gzip_program = GZIP_CMD; + break; + case 'B': + /* + * Nothing to do here, this is pax default + */ + break; + case 'C': + havechd++; + chdname = optarg; + break; + case 'H': + /* + * follow command line symlinks only + */ + Hflag = 1; + break; + case 'I': + case 'T': + if (++nincfiles > incfiles_max) { + incfiles_max = nincfiles + 3; + incfiles = realloc(incfiles, + sizeof(*incfiles) * incfiles_max); + if (incfiles == NULL) { + tty_warn(0, "Unable to allocate space " + "for option list"); + exit(1); + } + } + incfiles[nincfiles - 1].file = optarg; + incfiles[nincfiles - 1].dir = chdname; + break; + case 'P': + /* + * do not remove leading '/' from pathnames + */ + rmleadslash = 0; + Aflag = 1; + break; + case 'S': + /* do nothing; we already generate sparse files */ + break; + case 'V': + /* + * semi-verbose operation mode (no listing) + */ + Vflag = 1; + break; + case 'X': + /* + * GNU tar compat: exclude the files listed in optarg + */ + if (tar_gnutar_X_compat(optarg) != 0) + tar_usage(); + break; + case 'Z': + /* + * use compress. + */ + gzip_program = COMPRESS_CMD; + break; + case '0': + arcname = DEV_0; + break; + case '1': + arcname = DEV_1; + break; + case '4': + arcname = DEV_4; + break; + case '5': + arcname = DEV_5; + break; + case '7': + arcname = DEV_7; + break; + case '8': + arcname = DEV_8; + break; + case OPT_ATIME_PRESERVE: + patime = 1; + break; + case OPT_UNLINK: + /* Just ignore -- we always unlink first. */ + break; + case OPT_USE_COMPRESS_PROGRAM: + gzip_program = optarg; + break; + case OPT_FORCE_LOCAL: + forcelocal = 1; + break; + case OPT_INSECURE: + secure = 0; + break; + case OPT_STRICT: + /* disable gnu extensions */ + is_gnutar = 0; + break; + case OPT_EXCLUDE: + if (tar_gnutar_minus_minus_exclude(optarg) != 0) + tar_usage(); + break; + case OPT_NORECURSE: + dflag = 1; + break; +#if !HAVE_NBTOOL_CONFIG_H + case OPT_CHROOT: + do_chroot = 1; + break; +#endif + case OPT_XZ: + gzip_program = XZ_CMD; + break; + default: + tar_usage(); + break; + } + } + argc -= optind; + argv += optind; + + /* Tar requires an action. */ + if (act == ERROR) + tar_usage(); + + /* 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 || act == APPND) + frmt = &(fsub[Oflag ? F_TAR : F_USTAR]); + else if (Oflag) { + if (act == EXTRACT) + to_stdout = 1; + else { + tty_warn(1, "The -O/-o options are only valid when " + "writing or extracting an archive"); + tar_usage(); + } + } + + /* + * process the args as they are interpreted by the operation mode + */ + switch (act) { + case LIST: + case EXTRACT: + default: + { + int sawpat = 0; + int dirisnext = 0; + char *file, *dir = NULL; + int mustfreedir = 0; + + 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; + mustfreedir = 0; + incfiles++; + nincfiles--; + } else if (strcmp(*argv, "-I") == 0) { + if (*++argv == NULL) + break; + file = *argv++; + dir = chdname; + mustfreedir = 0; + } else { + file = NULL; + dir = NULL; + mustfreedir = 0; + } + if (file != NULL) { + FILE *fp; + char *str; + + if (strcmp(file, "-") == 0) + fp = stdin; + else if ((fp = fopen(file, "r")) == NULL) { + tty_warn(1, "Unable to open file '%s' for read", file); + tar_usage(); + } + while ((str = get_line(fp)) != NULL) { + if (dirisnext) { + if (dir && mustfreedir) + free(dir); + dir = str; + mustfreedir = 1; + dirisnext = 0; + continue; + } + if (strcmp(str, "-C") == 0) { + havechd++; + dirisnext = 1; + free(str); + continue; + } + if (strncmp(str, "-C ", 3) == 0) { + havechd++; + if (dir && mustfreedir) + free(dir); + dir = strdup(str + 3); + mustfreedir = 1; + free(str); + continue; + } + if (pat_add(str, dir, NOGLOB_MTCH) < 0) + tar_usage(); + sawpat = 1; + } + /* Bomb if given -C w/out a dir. */ + if (dirisnext) + tar_usage(); + if (dir && mustfreedir) + free(dir); + if (strcmp(file, "-") != 0) + fclose(fp); + if (get_line_error) { + tty_warn(1, "Problem with file '%s'", file); + tar_usage(); + } + } else if (strcmp(*argv, "-C") == 0) { + if (*++argv == NULL) + break; + chdname = *argv++; + havechd++; + } else if (pat_add(*argv++, chdname, 0) < 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: + if (chdname != NULL) { /* initial chdir() */ + if (ftree_add(chdname, 1) < 0) + tar_usage(); + } + + while (nincfiles || *argv != NULL) { + char *file, *dir; + + /* + * 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; + dir = NULL; + } + if (file != NULL) { + FILE *fp; + char *str; + int dirisnext = 0; + + /* 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) { + tty_warn(1, "Unable to open file '%s' for read", file); + tar_usage(); + } + while ((str = get_line(fp)) != NULL) { + if (dirisnext) { + if (ftree_add(str, 1) < 0) + tar_usage(); + dirisnext = 0; + continue; + } + if (strcmp(str, "-C") == 0) { + dirisnext = 1; + continue; + } + if (strncmp(str, "-C ", 3) == 0) { + if (ftree_add(str + 3, 1) < 0) + tar_usage(); + continue; + } + if (ftree_add(str, 0) < 0) + tar_usage(); + } + /* Bomb if given -C w/out a dir. */ + if (dirisnext) + tar_usage(); + if (strcmp(file, "-") != 0) + fclose(fp); + if (get_line_error) { + tty_warn(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! + */ + maxflt = 0; + break; + } + if (!fstdin && ((arcname == NULL) || (*arcname == '\0'))) { + arcname = getenv("TAPE"); + if ((arcname == NULL) || (*arcname == '\0')) + arcname = _PATH_DEFTAPE; + } +} + +int +mkpath(char *path) +{ + char *slash; + int done = 0; + + slash = path; + + while (!done) { + slash += strspn(slash, "/"); + slash += strcspn(slash, "/"); + + done = (*slash == '\0'); + *slash = '\0'; + + if (domkdir(path, 0777) == -1) + goto out; + + if (!done) + *slash = '/'; + } + + return 0; +out: + /* Can't create or or not a directory */ + syswarn(1, errno, "Cannot create directory `%s'", path); + return -1; +} + + +#ifndef NO_CPIO +struct option cpio_longopts[] = { + { "reset-access-time", no_argument, 0, 'a' }, + { "make-directories", no_argument, 0, 'd' }, + { "nonmatching", no_argument, 0, 'f' }, + { "extract", no_argument, 0, 'i' }, + { "link", no_argument, 0, 'l' }, + { "preserve-modification-time", no_argument, 0, 'm' }, + { "create", no_argument, 0, 'o' }, + { "pass-through", no_argument, 0, 'p' }, + { "rename", no_argument, 0, 'r' }, + { "list", no_argument, 0, 't' }, + { "unconditional", no_argument, 0, 'u' }, + { "verbose", no_argument, 0, 'v' }, + { "append", no_argument, 0, 'A' }, + { "pattern-file", required_argument, 0, 'E' }, + { "file", required_argument, 0, 'F' }, + { "force-local", no_argument, 0, + OPT_FORCE_LOCAL }, + { "format", required_argument, 0, 'H' }, + { "dereference", no_argument, 0, 'L' }, + { "swap-halfwords", no_argument, 0, 'S' }, + { "summary", no_argument, 0, 'V' }, + { "stats", no_argument, 0, 'V' }, + { "insecure", no_argument, 0, + OPT_INSECURE }, + { "sparse", no_argument, 0, + OPT_SPARSE }, + { "xz", no_argument, 0, + OPT_XZ }, + +#ifdef notyet +/* Not implemented */ + { "null", no_argument, 0, '0' }, + { "swap", no_argument, 0, 'b' }, + { "numeric-uid-gid", no_argument, 0, 'n' }, + { "swap-bytes", no_argument, 0, 's' }, + { "message", required_argument, 0, 'M' }, + { "owner", required_argument, 0 'R' }, + { "dot", no_argument, 0, 'V' }, /* xxx */ + { "block-size", required_argument, 0, + OPT_BLOCK_SIZE }, + { "no-absolute-pathnames", no_argument, 0, + OPT_NO_ABSOLUTE_PATHNAMES }, + { "no-preserve-owner", no_argument, 0, + OPT_NO_PRESERVE_OWNER }, + { "only-verify-crc", no_argument, 0, + OPT_ONLY_VERIFY_CRC }, + { "rsh-command", required_argument, 0, + OPT_RSH_COMMAND }, + { "version", no_argument, 0, + OPT_VERSION }, +#endif + { 0, 0, 0, 0 }, +}; + +static void +cpio_set_action(int op) +{ + if ((act == APPND && op == ARCHIVE) || (act == ARCHIVE && op == APPND)) + act = APPND; + else if (act == EXTRACT && op == LIST) + act = op; + else if (act != ERROR && act != op) + cpio_usage(); + else + act = op; +} + +/* + * cpio_options() + * look at the user specified flags. set globals as required and check if + * the user specified a legal set of flags. If not, complain and exit + */ + +static void +cpio_options(int argc, char **argv) +{ + FSUB tmp; + u_int64_t flg = 0; + u_int64_t bflg = 0; + int c; + size_t i; + FILE *fp; + char *str; + + uflag = 1; + kflag = 1; + pids = 1; + pmode = 1; + pmtime = 0; + arcname = NULL; + dflag = 1; + nodirs = 1; + /* + * process option flags + */ + while ((c = getoldopt(argc, argv, + "+abcdfiklmoprstuvzABC:E:F:H:I:LM:O:R:SVZ6", + cpio_longopts, NULL)) != -1) { + switch(c) { + case 'a': + /* + * preserve access time on filesystem nodes we read + */ + tflag = 1; + flg |= TF; + break; +#ifdef notyet + case 'b': + /* + * swap bytes and half-words when reading data + */ + break; +#endif + case 'c': + /* + * ASCII cpio header + */ + frmt = &fsub[F_SV4CPIO]; + break; + case 'd': + /* + * create directories as needed + * pax does this by default .. + */ + nodirs = 0; + break; + case 'f': + /* + * inverse match on patterns + */ + cflag = 1; + flg |= CF; + break; + case 'i': + /* + * read the archive + */ + cpio_set_action(EXTRACT); + flg |= RF; + break; +#ifdef notyet + case 'k': + break; +#endif + case 'l': + /* + * try to link src to dest with copy (-rw) + */ + lflag = 1; + flg |= LF; + break; + case 'm': + /* + * preserve mtime + */ + flg |= PF; + pmtime = 1; + break; + case 'o': + /* + * write an archive + */ + cpio_set_action(ARCHIVE); + frmt = &(fsub[F_SV4CRC]); + flg |= WF; + break; + case 'p': + /* + * cpio -p is like pax -rw + */ + cpio_set_action(COPY); + flg |= RF | WF; + break; + case 'r': + /* + * interactive file rename + */ + iflag = 1; + flg |= IF; + break; +#ifdef notyet + case 's': + /* + * swap bytes after reading data + */ + break; +#endif + case 't': + /* + * list contents of archive + */ + cpio_set_action(LIST); + listf = stdout; + flg &= ~RF; + break; + case 'u': + /* + * don't ignore those older files + */ + uflag = 0; + kflag = 0; + flg |= UF; + break; + case 'v': + /* + * verbose operation mode + */ + vflag = 1; + flg |= VF; + break; + case 'z': + /* + * use gzip. Non standard option. + */ + gzip_program = GZIP_CMD; + break; + case 'A': + /* + * append to an archive + */ + cpio_set_action(APPND); + flg |= AF; + break; + case 'B': + /* + * set blocksize to 5120 + */ + blksz = 5120; + break; + case 'C': + /* + * specify blocksize + */ + if ((blksz = (int)str_offt(optarg)) <= 0) { + tty_warn(1, "Invalid block size %s", optarg); + cpio_usage(); + } + break; + case 'E': + /* + * file with patterns to extract or list + */ + if ((fp = fopen(optarg, "r")) == NULL) { + tty_warn(1, "Unable to open file '%s' for read", + optarg); + cpio_usage(); + } + while ((str = get_line(fp)) != NULL) { + pat_add(str, NULL, 0); + } + fclose(fp); + if (get_line_error) { + tty_warn(1, "Problem with file '%s'", optarg); + cpio_usage(); + } + break; + case 'H': + /* + * specify an archive format on write + */ + tmp.name = optarg; + frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub, + sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt); + if (frmt != NULL) { + flg |= XF; + break; + } + tty_warn(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 '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 'L': + /* + * follow symlinks + */ + Lflag = 1; + flg |= CLF; + break; +#ifdef notyet + case 'M': + arg = optarg; + break; + case 'R': + arg = optarg; + break; +#endif + case 'S': + /* + * swap halfwords after reading data + */ + cpio_swp_head = 1; + break; +#ifdef notyet + case 'V': /* print a '.' for each file processed */ + break; +#endif + case 'V': + /* + * semi-verbose operation mode (no listing) + */ + Vflag = 1; + flg |= VF; + break; + case 'Z': + /* + * use compress. Non standard option. + */ + gzip_program = COMPRESS_CMD; + break; + case '6': + /* + * process Version 6 cpio format + */ + frmt = &(fsub[F_BCPIO]); + break; + case OPT_FORCE_LOCAL: + forcelocal = 1; + break; + case OPT_INSECURE: + secure = 0; + break; + case OPT_SPARSE: + /* do nothing; we already generate sparse files */ + break; + case OPT_XZ: + gzip_program = XZ_CMD; + break; + default: + cpio_usage(); + break; + } + } + + /* + * figure out the operation mode of cpio. check that we have not been + * given a bogus set of flags for the operation mode. + */ + if (ISLIST(flg)) { + act = LIST; + bflg = flg & BDLIST; + } else if (ISEXTRACT(flg)) { + act = EXTRACT; + bflg = flg & BDEXTR; + } else if (ISARCHIVE(flg)) { + act = ARCHIVE; + bflg = flg & BDARCH; + } else if (ISAPPND(flg)) { + act = APPND; + bflg = flg & BDARCH; + } else if (ISCOPY(flg)) { + act = COPY; + bflg = flg & BDCOPY; + } else + cpio_usage(); + if (bflg) { + cpio_usage(); + } + + /* + * if we are writing (ARCHIVE) we use the default format if the user + * did not specify a format. when we write during an APPEND, we will + * adopt the format of the existing archive if none was supplied. + */ + if (!(flg & XF) && (act == ARCHIVE)) + frmt = &(fsub[F_BCPIO]); + + /* + * process the args as they are interpreted by the operation mode + */ + switch (act) { + case LIST: + case EXTRACT: + for (; optind < argc; optind++) + if (pat_add(argv[optind], NULL, 0) < 0) + cpio_usage(); + break; + case COPY: + if (optind >= argc) { + tty_warn(0, "Destination directory was not supplied"); + cpio_usage(); + } + --argc; + dirptr = argv[argc]; + /* FALLTHROUGH */ + case ARCHIVE: + case APPND: + if (argc != optind) { + for (; optind < argc; optind++) + if (ftree_add(argv[optind], 0) < 0) + cpio_usage(); + break; + } + /* + * no read errors allowed on updates/append operation! + */ + maxflt = 0; + while ((str = get_line(stdin)) != NULL) { + ftree_add(str, 0); + } + if (get_line_error) { + tty_warn(1, "Problem while reading stdin"); + cpio_usage(); + } + break; + default: + cpio_usage(); + break; + } +} +#endif + +/* + * printflg() + * print out those invalid flag sets found to the user + */ + +static void +printflg(unsigned int flg) +{ + int nxt; + + (void)fprintf(stderr,"%s: Invalid combination of options:", argv0); + while ((nxt = ffs(flg)) != 0) { + flg &= ~(1 << (nxt - 1)); + (void)fprintf(stderr, " -%c", flgch[nxt - 1]); + } + (void)putc('\n', stderr); +} + +/* + * c_frmt() + * comparison routine used by bsearch to find the format specified + * by the user + */ + +static int +c_frmt(const void *a, const void *b) +{ + return strcmp(((const FSUB *)a)->name, ((const FSUB *)b)->name); +} + +/* + * opt_next() + * called by format specific options routines to get each format specific + * flag and value specified with -o + * Return: + * pointer to next OPLIST entry or NULL (end of list). + */ + +OPLIST * +opt_next(void) +{ + OPLIST *opt; + + if ((opt = ophead) != NULL) + ophead = ophead->fow; + return opt; +} + +/* + * bad_opt() + * generic routine used to complain about a format specific options + * when the format does not support options. + */ + +int +bad_opt(void) +{ + OPLIST *opt; + + if (ophead == NULL) + return 0; + /* + * print all we were given + */ + tty_warn(1," These format options are not supported for %s", + frmt->name); + while ((opt = opt_next()) != NULL) + (void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value); + if (strcmp(NM_TAR, argv0) == 0) + tar_usage(); +#ifndef NO_CPIO + else if (strcmp(NM_CPIO, argv0) == 0) + cpio_usage(); +#endif + else + pax_usage(); + return 0; +} + +/* + * opt_add() + * breaks the value supplied to -o into a option name and value. options + * are given to -o in the form -o name-value,name=value + * multiple -o may be specified. + * Return: + * 0 if format in name=value format, -1 if -o is passed junk + */ + +int +opt_add(const char *str) +{ + OPLIST *opt; + char *frpt; + char *pt; + char *endpt; + char *dstr; + + if ((str == NULL) || (*str == '\0')) { + tty_warn(0, "Invalid option name"); + return -1; + } + if ((dstr = strdup(str)) == NULL) { + tty_warn(0, "Unable to allocate space for option list"); + return -1; + } + frpt = endpt = dstr; + + /* + * break into name and values pieces and stuff each one into a + * OPLIST structure. When we know the format, the format specific + * option function will go through this list + */ + while ((frpt != NULL) && (*frpt != '\0')) { + if ((endpt = strchr(frpt, ',')) != NULL) + *endpt = '\0'; + if ((pt = strchr(frpt, '=')) == NULL) { + tty_warn(0, "Invalid options format"); + free(dstr); + return -1; + } + if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) { + tty_warn(0, "Unable to allocate space for option list"); + free(dstr); + return -1; + } + *pt++ = '\0'; + opt->name = frpt; + opt->value = pt; + opt->fow = NULL; + if (endpt != NULL) + frpt = endpt + 1; + else + frpt = NULL; + if (ophead == NULL) { + optail = ophead = opt; + continue; + } + optail->fow = opt; + optail = opt; + } + return 0; +} + +/* + * str_offt() + * Convert an expression of the following forms to an off_t > 0. + * 1) A positive decimal number. + * 2) A positive decimal number followed by a b (mult by 512). + * 3) A positive decimal number followed by a k (mult by 1024). + * 4) A positive decimal number followed by a m (mult by 512). + * 5) A positive decimal number followed by a w (mult by sizeof int) + * 6) Two or more positive decimal numbers (with/without k,b or w). + * separated by x (also * for backwards compatibility), specifying + * the product of the indicated values. + * Return: + * 0 for an error, a positive value o.w. + */ + +static off_t +str_offt(char *val) +{ + char *expr; + off_t num, t; + + num = STRTOOFFT(val, &expr, 0); + if ((num == OFFT_MAX) || (num <= 0) || (expr == val)) + return 0; + + switch(*expr) { + case 'b': + t = num; + num *= 512; + if (t > num) + return 0; + ++expr; + break; + case 'k': + t = num; + num *= 1024; + if (t > num) + return 0; + ++expr; + break; + case 'm': + t = num; + num *= 1048576; + if (t > num) + return 0; + ++expr; + break; + case 'w': + t = num; + num *= sizeof(int); + if (t > num) + return 0; + ++expr; + break; + } + + switch(*expr) { + case '\0': + break; + case '*': + case 'x': + t = num; + num *= str_offt(expr + 1); + if (t > num) + return 0; + break; + default: + return 0; + } + return num; +} + +static char * +get_line(FILE *f) +{ + char *name, *temp; + size_t len; + + name = fgetln(f, &len); + if (!name) { + get_line_error = ferror(f) ? GETLINE_FILE_CORRUPT : 0; + return 0; + } + if (name[len-1] != '\n') + len++; + temp = malloc(len); + if (!temp) { + get_line_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. + * Return: + * 0 + */ + +static int +no_op(void) +{ + return 0; +} + +/* + * pax_usage() + * print the usage summary to the user + */ + +static void +pax_usage(void) +{ + fprintf(stderr, +"usage: pax [-0cdjnvzVO] [-E limit] [-f archive] [-N dbdir] [-s replstr] ...\n" +" [-U user] ... [-G group] ... [-T [from_date][,to_date]] ...\n" +" [pattern ...]\n"); + fprintf(stderr, +" pax -r [-cdijknuvzADOVYZ] [-E limit] [-f archive] [-N dbdir]\n" +" [-o options] ... [-p string] ... [-s replstr] ... [-U user] ...\n" +" [-G group] ... [-T [from_date][,to_date]] ... [pattern ...]\n"); + fprintf(stderr, +" pax -w [-dijtuvzAHLMOPVX] [-b blocksize] [[-a] [-f archive]] [-x format]\n" +" [-B bytes] [-N dbdir] [-o options] ... [-s replstr] ...\n" +" [-U user] ... [-G group] ...\n" +" [-T [from_date][,to_date][/[c][m]]] ... [file ...]\n"); + fprintf(stderr, +" pax -r -w [-dijklntuvzADHLMOPVXYZ] [-N dbdir] [-p string] ...\n" +" [-s replstr] ... [-U user] ... [-G group] ...\n" +" [-T [from_date][,to_date][/[c][m]]] ... [file ...] directory\n"); + exit(1); + /* NOTREACHED */ +} + +/* + * tar_usage() + * print the usage summary to the user + */ + +static void +tar_usage(void) +{ + (void)fputs("usage: tar [-]{crtux}[-befhjklmopqvwzHOPSXZ014578] [archive] " + "[blocksize]\n" + " [-C directory] [-T file] [-s replstr] " + "[file ...]\n", stderr); + exit(1); + /* NOTREACHED */ +} + +#ifndef NO_CPIO +/* + * cpio_usage() + * print the usage summary to the user + */ + +static void +cpio_usage(void) +{ + + (void)fputs("usage: cpio -o [-aABcLvzZ] [-C bytes] [-F archive] " + "[-H format] [-O archive]\n" + " < name-list [> archive]\n" + " cpio -i [-bBcdfmrsStuvzZ6] [-C bytes] [-E file] " + "[-F archive] [-H format] \n" + " [-I archive] " + "[pattern ...] [< archive]\n" + " cpio -p [-adlLmuv] destination-directory " + "< name-list\n", stderr); + exit(1); + /* NOTREACHED */ +} +#endif diff --git a/commands/pax/options.h b/bin/pax/options.h similarity index 63% rename from commands/pax/options.h rename to bin/pax/options.h index 86351e859..6517174cd 100644 --- a/commands/pax/options.h +++ b/bin/pax/options.h @@ -1,3 +1,5 @@ +/* $NetBSD: options.h,v 1.11 2007/04/23 18:40:22 christos Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,7 +33,6 @@ * SUCH DAMAGE. * * @(#)options.h 8.2 (Berkeley) 4/18/94 - * $FreeBSD: src/bin/pax/options.h,v 1.6 2004/04/06 20:06:48 markm Exp $ */ /* @@ -42,52 +43,57 @@ #define NM_CPIO "cpio" #define NM_PAX "pax" +/* special value for -E */ +#define none "none" + /* * Constants used to specify the legal sets of flags in pax. For each major * operation mode of pax, a set of illegal flags is defined. If any one of * those illegal flags are found set, we scream and exit */ -#define NONE "none" /* * flags (one for each option). */ -#define AF 0x00000001 -#define BF 0x00000002 -#define CF 0x00000004 -#define DF 0x00000008 -#define FF 0x00000010 -#define IF 0x00000020 -#define KF 0x00000040 -#define LF 0x00000080 -#define NF 0x00000100 -#define OF 0x00000200 -#define PF 0x00000400 -#define RF 0x00000800 -#define SF 0x00001000 -#define TF 0x00002000 -#define UF 0x00004000 -#define VF 0x00008000 -#define WF 0x00010000 -#define XF 0x00020000 -#define CBF 0x00040000 /* nonstandard extension */ -#define CDF 0x00080000 /* nonstandard extension */ -#define CEF 0x00100000 /* nonstandard extension */ -#define CGF 0x00200000 /* nonstandard extension */ -#define CHF 0x00400000 /* nonstandard extension */ -#define CLF 0x00800000 /* nonstandard extension */ -#define CPF 0x01000000 /* nonstandard extension */ -#define CTF 0x02000000 /* nonstandard extension */ -#define CUF 0x04000000 /* nonstandard extension */ -#define CXF 0x08000000 -#define CYF 0x10000000 /* nonstandard extension */ -#define CZF 0x20000000 /* nonstandard extension */ +#define AF 0x000000001ULL +#define BF 0x000000002ULL +#define CF 0x000000004ULL +#define DF 0x000000008ULL +#define FF 0x000000010ULL +#define IF 0x000000020ULL +#define KF 0x000000040ULL +#define LF 0x000000080ULL +#define NF 0x000000100ULL +#define OF 0x000000200ULL +#define PF 0x000000400ULL +#define RF 0x000000800ULL +#define SF 0x000001000ULL +#define TF 0x000002000ULL +#define UF 0x000004000ULL +#define VF 0x000008000ULL +#define WF 0x000010000ULL +#define XF 0x000020000ULL +#define CAF 0x000040000ULL /* nonstandard extension */ +#define CBF 0x000080000ULL /* nonstandard extension */ +#define CDF 0x000100000ULL /* nonstandard extension */ +#define CEF 0x000200000ULL /* nonstandard extension */ +#define CGF 0x000400000ULL /* nonstandard extension */ +#define CHF 0x000800000ULL /* nonstandard extension */ +#define CLF 0x001000000ULL /* nonstandard extension */ +#define CMF 0x002000000ULL /* nonstandard extension */ +#define CPF 0x004000000ULL /* nonstandard extension */ +#define CTF 0x008000000ULL /* nonstandard extension */ +#define CUF 0x010000000ULL /* nonstandard extension */ +#define VSF 0x020000000ULL /* non-standard */ +#define CXF 0x040000000ULL +#define CYF 0x080000000ULL /* nonstandard extension */ +#define CZF 0x100000000ULL /* nonstandard extension */ /* * ascii string indexed by bit position above (alter the above and you must * alter this string) used to tell the user what flags caused us to complain */ -#define FLGCH "abcdfiklnoprstuvwxBDEGHLPTUXYZ" +#define FLGCH "abcdfiklnoprstuvwxABDEGHLMPTUVXYZ" /* * legal pax operation bit patterns @@ -104,7 +110,7 @@ * Illegal option flag subsets based on pax operation */ -#define BDEXTR (AF|BF|LF|TF|WF|XF|CBF|CHF|CLF|CPF|CXF) +#define BDEXTR (AF|BF|LF|TF|WF|XF|CBF|CHF|CLF|CMF|CPF|CXF) #define BDARCH (CF|KF|LF|NF|PF|RF|CDF|CEF|CYF|CZF) -#define BDCOPY (AF|BF|FF|OF|XF|CBF|CEF) -#define BDLIST (AF|BF|IF|KF|LF|OF|PF|RF|TF|UF|WF|XF|CBF|CDF|CHF|CLF|CPF|CXF|CYF|CZF) +#define BDCOPY (AF|BF|FF|OF|XF|CAF|CBF|CEF) +#define BDLIST (AF|BF|IF|KF|LF|OF|PF|RF|TF|UF|WF|XF|CBF|CDF|CHF|CLF|CMF|CPF|CXF|CYF|CZF) diff --git a/commands/pax/pat_rep.c b/bin/pax/pat_rep.c similarity index 82% rename from commands/pax/pat_rep.c rename to bin/pax/pat_rep.c index 31ee7a44a..fd402e292 100644 --- a/commands/pax/pat_rep.c +++ b/bin/pax/pat_rep.c @@ -1,3 +1,5 @@ +/* $NetBSD: pat_rep.c,v 1.29 2009/04/07 19:52:35 perry Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,24 +33,28 @@ * SUCH DAMAGE. */ -#ifndef lint +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) #if 0 static char sccsid[] = "@(#)pat_rep.c 8.2 (Berkeley) 4/18/94"; +#else +__RCSID("$NetBSD: pat_rep.c,v 1.29 2009/04/07 19:52:35 perry Exp $"); #endif #endif /* not lint */ #include +#include #include +#include #include +#include #include #include #include -#include -#ifdef NET2_REGEX -#include -#else -#include -#endif #include "pax.h" #include "pat_rep.h" #include "extern.h" @@ -66,21 +72,18 @@ static PATTERN *pattail = NULL; /* file pattern match list tail */ static REPLACE *rephead = NULL; /* replacement string list head */ static REPLACE *reptail = NULL; /* replacement string list tail */ -static int rep_name(char *, int *, int); +static int rep_name(char *, size_t, int *, int); static int tty_rename(ARCHD *); static int fix_path(char *, int *, char *, int); -static int fn_match(char *, char *, char **); +static int fn_match(char *, char *, char **, int); static char * range_match(char *, int); -#ifdef NET2_REGEX -static int resub(regexp *, char *, char *, char *); -#else -static int resub(regex_t *, regmatch_t *, char *, char *, char *); -#endif +static int checkdotdot(const char *); +static int resub(regex_t *, regmatch_t *, char *, char *, char *, char *); /* * rep_add() * parses the -s replacement string; compiles the regular expression - * and stores the compiled value and it's replacement string together in + * and stores the compiled value and its replacement string together in * replacement string list. Input to this function is of the form: * /old/new/pg * The first char in the string specifies the delimiter used by this @@ -99,26 +102,32 @@ rep_add(char *str) char *pt1; char *pt2; REPLACE *rep; -# ifndef NET2_REGEX int res; char rebuf[BUFSIZ]; -# endif /* * throw out the bad parameters */ if ((str == NULL) || (*str == '\0')) { - paxwarn(1, "Empty replacement string"); - return(-1); + tty_warn(1, "Empty replacement string"); + return -1; } /* * first character in the string specifies what the delimiter is for - * this expression + * this expression. */ - if ((pt1 = strchr(str+1, *str)) == NULL) { - paxwarn(1, "Invalid replacement string %s", str); - return(-1); + for (pt1 = str+1; *pt1; pt1++) { + if (*pt1 == '\\') { + pt1++; + continue; + } + if (*pt1 == *str) + break; + } + if (*pt1 == 0) { + tty_warn(1, "Invalid replacement string %s", str); + return -1; } /* @@ -126,20 +135,17 @@ rep_add(char *str) * and split out the regular expression and try to compile it */ if ((rep = (REPLACE *)malloc(sizeof(REPLACE))) == NULL) { - paxwarn(1, "Unable to allocate memory for replacement string"); - return(-1); + tty_warn(1, "Unable to allocate memory for replacement string"); + return -1; } *pt1 = '\0'; -# ifdef NET2_REGEX - if ((rep->rcmp = regcomp(str+1)) == NULL) { -# else if ((res = regcomp(&(rep->rcmp), str+1, 0)) != 0) { regerror(res, &(rep->rcmp), rebuf, sizeof(rebuf)); - paxwarn(1, "%s while compiling regular expression %s", rebuf, str); -# endif + tty_warn(1, "%s while compiling regular expression %s", rebuf, + str); (void)free((char *)rep); - return(-1); + return -1; } /* @@ -148,19 +154,31 @@ rep_add(char *str) * we then point the node at the new substitution string */ *pt1++ = *str; - if ((pt2 = strchr(pt1, *str)) == NULL) { -# ifdef NET2_REGEX - (void)free((char *)rep->rcmp); -# else + for (pt2 = pt1; *pt2; pt2++) { + if (*pt2 == '\\') { + pt2++; + continue; + } + if (*pt2 == *str) + break; + } + if (*pt2 == 0) { regfree(&(rep->rcmp)); -# endif (void)free((char *)rep); - paxwarn(1, "Invalid replacement string %s", str); - return(-1); + tty_warn(1, "Invalid replacement string %s", str); + return -1; } *pt2 = '\0'; - rep->nstr = pt1; + + /* Make sure to dup replacement, who knows where it came from! */ + if ((rep->nstr = strdup(pt1)) == NULL) { + regfree(&(rep->rcmp)); + (void)free((char *)rep); + tty_warn(1, "Unable to allocate memory for replacement string"); + return -1; + } + pt1 = pt2++; rep->flgs = 0; @@ -177,16 +195,17 @@ rep_add(char *str) case 'P': rep->flgs |= PRNT; break; + case 's': + case 'S': + rep->flgs |= SYML; + break; default: -# ifdef NET2_REGEX - (void)free((char *)rep->rcmp); -# else regfree(&(rep->rcmp)); -# endif (void)free((char *)rep); *pt1 = *str; - paxwarn(1, "Invalid replacement string option %s", str); - return(-1); + tty_warn(1, "Invalid replacement string option %s", + str); + return -1; } ++pt2; } @@ -197,11 +216,11 @@ rep_add(char *str) rep->fow = NULL; if (rephead == NULL) { reptail = rephead = rep; - return(0); + return 0; } reptail->fow = rep; reptail = rep; - return(0); + return 0; } /* @@ -211,12 +230,13 @@ rep_add(char *str) * arguments to pax in the list and read modes). If no patterns are * supplied to pax, all members in the archive will be selected (and the * pattern match list is empty). + * * Return: * 0 if the pattern was added to the list, -1 otherwise */ int -pat_add(char *str, char *chdnam) +pat_add(char *str, char *chdn, int flags) { PATTERN *pt; @@ -224,8 +244,8 @@ pat_add(char *str, char *chdnam) * throw out the junk */ if ((str == NULL) || (*str == '\0')) { - paxwarn(1, "Empty pattern string"); - return(-1); + tty_warn(1, "Empty pattern string"); + return -1; } /* @@ -234,24 +254,23 @@ pat_add(char *str, char *chdnam) * node to the end of the pattern list */ if ((pt = (PATTERN *)malloc(sizeof(PATTERN))) == NULL) { - paxwarn(1, "Unable to allocate memory for pattern string"); - return(-1); + tty_warn(1, "Unable to allocate memory for pattern string"); + return -1; } pt->pstr = str; pt->pend = NULL; pt->plen = strlen(str); pt->fow = NULL; - pt->flgs = 0; - pt->chdname = chdnam; - + pt->flgs = flags; + pt->chdname = chdn; if (pathead == NULL) { pattail = pathead = pt; - return(0); + return 0; } pattail->fow = pt; pattail = pt; - return(0); + return 0; } /* @@ -274,7 +293,7 @@ pat_chk(void) if (pt->flgs & MTCH) continue; if (!wban) { - paxwarn(1, "WARNING! These patterns were not matched:"); + tty_warn(1, "WARNING! These patterns were not matched:"); ++wban; } (void)fprintf(stderr, "%s\n", pt->pstr); @@ -289,9 +308,9 @@ pat_chk(void) * * NOTE: When the -c option is used, we are called when there was no match * by pat_match() (that means we did match before the inverted sense of - * the logic). Now this seems really strange at first, but with -c we - * need to keep track of those patterns that cause an archive member to NOT - * be selected (it found an archive member with a specified pattern) + * the logic). Now this seems really strange at first, but with -c we + * need to keep track of those patterns that cause an archive member to + * NOT be selected (it found an archive member with a specified pattern) * Return: * 0 if the pattern pointed at by arcn->pat was tagged as creating a * match, -1 otherwise. @@ -308,7 +327,7 @@ pat_sel(ARCHD *arcn) * if no patterns just return */ if ((pathead == NULL) || ((pt = arcn->pat) == NULL)) - return(0); + return 0; /* * when we are NOT limited to a single match per pattern mark the @@ -316,7 +335,7 @@ pat_sel(ARCHD *arcn) */ if (!nflag) { pt->flgs |= MTCH; - return(0); + return 0; } /* @@ -327,7 +346,7 @@ pat_sel(ARCHD *arcn) * with -d, this pattern was already selected and we are done */ if (pt->flgs & DIR_MTCH) - return(0); + return 0; if (!dflag && ((pt->pend != NULL) || (arcn->type == PAX_DIR))) { /* @@ -347,11 +366,11 @@ pat_sel(ARCHD *arcn) *pt->pend = '\0'; if ((pt->pstr = strdup(arcn->name)) == NULL) { - paxwarn(1, "Pattern select out of memory"); + tty_warn(1, "Pattern select out of memory"); if (pt->pend != NULL) *pt->pend = '/'; pt->pend = NULL; - return(-1); + return -1; } /* @@ -373,14 +392,14 @@ pat_sel(ARCHD *arcn) } pt->flgs = DIR_MTCH | MTCH; arcn->pat = pt; - return(0); + return 0; } /* * we are then done with this pattern, so we delete it from the list * because it can never be used for another match. * Seems kind of strange to do for a -c, but the pax spec is really - * vague on the interaction of -c -n and -d. We assume that when -c + * vague on the interaction of -c, -n, and -d. We assume that when -c * and the pattern rejects a member (i.e. it matched it) it is done. * In effect we place the order of the flags as having -c last. */ @@ -395,13 +414,13 @@ pat_sel(ARCHD *arcn) /* * should never happen.... */ - paxwarn(1, "Pattern list inconsistant"); - return(-1); + tty_warn(1, "Pattern list inconsistent"); + return -1; } *ppt = pt->fow; (void)free((char *)pt); arcn->pat = NULL; - return(0); + return 0; } /* @@ -429,8 +448,8 @@ pat_match(ARCHD *arcn) */ if (pathead == NULL) { if (nflag && !cflag) - return(-1); - return(0); + return -1; + return 0; } /* @@ -452,7 +471,8 @@ pat_match(ARCHD *arcn) if ((arcn->name[pt->plen] == '/') && (strncmp(pt->pstr, arcn->name, pt->plen) == 0)) break; - } else if (fn_match(pt->pstr, arcn->name, &pt->pend) == 0) + } else if (fn_match(pt->pstr, arcn->name, &pt->pend, + pt->flgs & NOGLOB_MTCH) == 0) break; pt = pt->fow; } @@ -462,21 +482,22 @@ pat_match(ARCHD *arcn) * match */ if (pt == NULL) - return(cflag ? 0 : 1); + return cflag ? 0 : 1; /* - * We had a match, now when we invert the sense (-c) we reject this + * we had a match, now when we invert the sense (-c) we reject this * member. However we have to tag the pattern a being successful, (in a - * match, not in selecting an archive member) so we call pat_sel() here. + * match, not in selecting an archive member) so we call pat_sel() + * here. */ arcn->pat = pt; if (!cflag) - return(0); + return 0; if (pat_sel(arcn) < 0) - return(-1); + return -1; arcn->pat = NULL; - return(1); + return 1; } /* @@ -489,7 +510,7 @@ pat_match(ARCHD *arcn) */ static int -fn_match(char *pattern, char *string, char **pend) +fn_match(char *pattern, char *string, char **pend, int noglob) { char c; char test; @@ -502,25 +523,29 @@ fn_match(char *pattern, char *string, char **pend) * Ok we found an exact match */ if (*string == '\0') - return(0); + return 0; /* * Check if it is a prefix match */ if ((dflag == 1) || (*string != '/')) - return(-1); + return -1; /* * It is a prefix match, remember where the trailing * / is located */ *pend = string; - return(0); + return 0; case '?': + if (noglob) + goto regular; if ((test = *string++) == '\0') return (-1); break; case '*': + if (noglob) + goto regular; c = *pattern; /* * Collapse multiple *'s. @@ -538,12 +563,14 @@ fn_match(char *pattern, char *string, char **pend) * General case, use recursion. */ while ((test = *string) != '\0') { - if (!fn_match(pattern, string, pend)) + if (!fn_match(pattern, string, pend, noglob)) return (0); ++string; } return (-1); case '[': + if (noglob) + goto regular; /* * range match */ @@ -553,6 +580,7 @@ fn_match(char *pattern, char *string, char **pend) break; case '\\': default: + regular: if (c != *string++) return (-1); break; @@ -605,40 +633,23 @@ range_match(char *pattern, int test) */ int -mod_name(ARCHD *arcn) +mod_name(ARCHD *arcn, int flags) { 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 (secure) { + if (checkdotdot(arcn->name)) { + tty_warn(0, "Ignoring file containing `..' (%s)", + arcn->name); + return 1; } - 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"); +#ifdef notdef + if (checkdotdot(arcn->ln_name)) { + tty_warn(0, "Ignoring link containing `..' (%s)", + arcn->ln_name); + return 1; } +#endif } /* @@ -661,17 +672,21 @@ mod_name(ARCHD *arcn) * call an oracle here. :) */ if (rephead != NULL) { + flags |= (flags & RENM) ? PRNT : 0; /* * we have replacement strings, modify the name and the link * name if any. */ - if ((res = rep_name(arcn->name, &(arcn->nlen), 1)) != 0) - return(res); + if ((res = rep_name(arcn->name, sizeof(arcn->name), + &(arcn->nlen), flags)) != 0) + return res; if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) && - ((res = rep_name(arcn->ln_name, &(arcn->ln_nlen), 0)) != 0)) - return(res); + ((res = rep_name(arcn->ln_name, + sizeof(arcn->ln_name), &(arcn->ln_nlen), + flags | (arcn->type == PAX_SLK ? SYML : 0))) != 0)) + return res; } if (iflag) { @@ -679,12 +694,45 @@ mod_name(ARCHD *arcn) * perform interactive file rename, then map the link if any */ if ((res = tty_rename(arcn)) != 0) - return(res); + return res; if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) sub_name(arcn->ln_name, &(arcn->ln_nlen), sizeof(arcn->ln_name)); } - return(res); + + /* + * 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; + tty_warn(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; + tty_warn(0, "Removing leading / from absolute path names in the archive"); + } + } + + return res; } /* @@ -717,7 +765,7 @@ tty_rename(ARCHD *arcn) tty_prnt("or a \"return\" to skip this file.\n"); tty_prnt("Input > "); if (tty_read(tmpname, sizeof(tmpname)) < 0) - return(-1); + return -1; if (strcmp(tmpname, "..") == 0) { tty_prnt("Try again, illegal file name: ..\n"); continue; @@ -734,11 +782,11 @@ tty_rename(ARCHD *arcn) */ if (tmpname[0] == '\0') { tty_prnt("Skipping file.\n"); - return(1); + return 1; } if ((tmpname[0] == '.') && (tmpname[1] == '\0')) { tty_prnt("Processing continues, name unchanged.\n"); - return(0); + return 0; } /* @@ -748,11 +796,10 @@ tty_rename(ARCHD *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, sizeof(arcn->name) - 1); - arcn->name[arcn->nlen] = '\0'; + arcn->nlen = strlcpy(arcn->name, tmpname, sizeof(arcn->name)); if (res < 0) - return(-1); - return(0); + return -1; + return 0; } /* @@ -767,7 +814,7 @@ int set_dest(ARCHD *arcn, char *dest_dir, int dir_len) { if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0) - return(-1); + return -1; /* * It is really hard to deal with symlinks here, we cannot be sure @@ -775,11 +822,11 @@ set_dest(ARCHD *arcn, char *dest_dir, int dir_len) * leave them alone. */ if ((arcn->type != PAX_HLK) && (arcn->type != PAX_HRG)) - return(0); + return 0; if (fix_path(arcn->ln_name, &(arcn->ln_nlen), dest_dir, dir_len) < 0) - return(-1); - return(0); + return -1; + return 0; } /* @@ -812,8 +859,8 @@ fix_path( char *or_name, int *or_len, char *dir_name, int dir_len) --dest; } if ((len = dest - or_name) > PAXPATHLEN) { - paxwarn(1, "File name %s/%s, too long", dir_name, start); - return(-1); + tty_warn(1, "File name %s/%s, too long", dir_name, start); + return -1; } *or_len = len; @@ -831,7 +878,7 @@ fix_path( char *or_name, int *or_len, char *dir_name, int dir_len) *dest-- = *src--; *(or_name + len) = '\0'; - return(0); + return 0; } /* @@ -845,6 +892,7 @@ fix_path( char *or_name, int *or_len, char *dir_name, int dir_len) * --Parameters-- * name is the file name we are going to apply the regular expressions to * (and may be modified) + * namelen the size of the name buffer. * nlen is the length of this name (and is modified to hold the length of * the final string). * prnt is a flag that says whether to print the final result. @@ -854,7 +902,7 @@ fix_path( char *or_name, int *or_len, char *dir_name, int dir_len) */ static int -rep_name(char *name, int *nlen, int prnt) +rep_name(char *name, size_t namelen, int *nlen, int flags) { REPLACE *pt; char *inpt; @@ -863,9 +911,7 @@ rep_name(char *name, int *nlen, int prnt) char *rpt; int found = 0; int res; -# ifndef NET2_REGEX regmatch_t pm[MAXSUBEXP]; -# endif char nname[PAXPATHLEN+1]; /* final result of all replacements */ char buf1[PAXPATHLEN+1]; /* where we work on the name */ @@ -888,15 +934,13 @@ rep_name(char *name, int *nlen, int prnt) */ while (pt != NULL) { do { + if ((flags & SYML) && (pt->flgs & SYML)) + continue; /* * check for a successful substitution, if not go to * the next pattern, or cleanup if we were global */ -# ifdef NET2_REGEX - if (regexec(pt->rcmp, inpt) == 0) -# else if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0) -# endif break; /* @@ -907,11 +951,7 @@ rep_name(char *name, int *nlen, int prnt) * do not create a string too long). */ found = 1; -# ifdef NET2_REGEX - rpt = pt->rcmp->startp[0]; -# else rpt = inpt + pm[0].rm_so; -# endif while ((inpt < rpt) && (outpt < endpt)) *outpt++ = *inpt++; @@ -924,16 +964,13 @@ rep_name(char *name, int *nlen, int prnt) * replacement string and place it the prefix in the * final output. If we have problems, skip it. */ -# ifdef NET2_REGEX - if ((res = resub(pt->rcmp,pt->nstr,outpt,endpt)) < 0) { -# else - if ((res = resub(&(pt->rcmp),pm,pt->nstr,outpt,endpt)) - < 0) { -# endif - if (prnt) - paxwarn(1, "Replacement name error %s", + if ((res = + resub(&(pt->rcmp),pm,pt->nstr,inpt, outpt,endpt) + ) < 0) { + if (flags & PRNT) + tty_warn(1, "Replacement name error %s", name); - return(1); + return 1; } outpt += res; @@ -947,11 +984,7 @@ rep_name(char *name, int *nlen, int prnt) * the final result. Make sure we do not overrun the * output buffer */ -# ifdef NET2_REGEX - inpt = pt->rcmp->endp[0]; -# else inpt += pm[0].rm_eo - pm[0].rm_so; -# endif if ((outpt == endpt) || (*inpt == '\0')) break; @@ -981,16 +1014,16 @@ rep_name(char *name, int *nlen, int prnt) *outpt = '\0'; if ((outpt == endpt) && (*inpt != '\0')) { - if (prnt) - paxwarn(1,"Replacement name too long %s >> %s", + if (flags & PRNT) + tty_warn(1,"Replacement name too long %s >> %s", name, nname); - return(1); + return 1; } /* * inform the user of the result if wanted */ - if (prnt && (pt->flgs & PRNT)) { + if ((flags & PRNT) && (pt->flgs & PRNT)) { if (*nname == '\0') (void)fprintf(stderr,"%s >> \n", name); @@ -1003,73 +1036,53 @@ rep_name(char *name, int *nlen, int prnt) * otherwise copy the new name over the orig name and return */ if (*nname == '\0') - return(1); - *nlen = l_strncpy(name, nname, PAXPATHLEN + 1); - name[PAXPATHLEN] = '\0'; + return 1; + if (flags & RENM) + *nlen = strlcpy(name, nname, namelen); } - return(0); + return 0; } -#ifdef NET2_REGEX + /* - * resub() - * apply the replacement to the matched expression. expand out the old - * style ed(1) subexpression expansion. - * Return: - * -1 if error, or the number of characters added to the destination. + * checkdotdot() + * Return true if a component of the name contains a reference to ".." */ - static int -resub(regexp *prog, char *src, char *dest, char *destend) +checkdotdot(const char *name) { - char *spt; - char *dpt; - char c; - int no; - int len; - - spt = src; - dpt = dest; - while ((dpt < destend) && ((c = *spt++) != '\0')) { - if (c == '&') - no = 0; - else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) - no = *spt++ - '0'; - else { - if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) - c = *spt++; - *dpt++ = c; - continue; - } - if ((prog->startp[no] == NULL) || (prog->endp[no] == NULL) || - ((len = prog->endp[no] - prog->startp[no]) <= 0)) - continue; - - /* - * copy the subexpression to the destination. - * fail if we run out of space or the match string is damaged - */ - if (len > (destend - dpt)) - len = destend - dpt; - if (l_strncpy(dpt, prog->startp[no], len) != len) - return(-1); - dpt += len; - } - return(dpt - dest); + const char *p; + /* 1. "..{[/],}" */ + if (name[0] == '.' && name[1] == '.' && + (name[2] == '/' || name[2] == '\0')) + return 1; + + /* 2. "*[/]..[/]*" */ + if (strstr(name, "/../") != NULL) + return 1; + + /* 3. "*[/].." */ + for (p = name; *p; p++) + continue; + if (p - name < 3) + return 0; + if (p[-1] == '.' && p[-2] == '.' && p[-3] == '/') + return 1; + + return 0; } -#else /* * resub() * apply the replacement to the matched expression. expand out the old - * style ed(1) subexpression expansion. + * style ed(1) subexpression expansion. * Return: * -1 if error, or the number of characters added to the destination. */ static int -resub(regex_t *rp, regmatch_t *pm, char *src, char *dest, +resub(regex_t *rp, regmatch_t *pm, char *src, char *txt, char *dest, char *destend) { char *spt; @@ -1089,20 +1102,20 @@ resub(regex_t *rp, regmatch_t *pm, char *src, char *dest, */ if (c == '&') { pmpt = pm; - } else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) { + } else if ((c == '\\') && (*spt >= '1') && (*spt <= '9')) { /* * make sure there is a subexpression as specified */ if ((len = *spt++ - '0') > subexcnt) - return(-1); + return -1; pmpt = pm + len; } else { - /* + /* * Ordinary character, just copy it */ - if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) - c = *spt++; - *dpt++ = c; + if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) + c = *spt++; + *dpt++ = c; continue; } @@ -1118,11 +1131,9 @@ resub(regex_t *rp, regmatch_t *pm, char *src, char *dest, * fail if we run out of space or the match string is damaged */ if (len > (destend - dpt)) - len = destend - dpt; - if (l_strncpy(dpt, src + pmpt->rm_so, len) != len) - return(-1); + return -1; + strncpy(dpt, txt + pmpt->rm_so, len); dpt += len; } - return(dpt - dest); + return dpt - dest; } -#endif diff --git a/commands/pax/pat_rep.h b/bin/pax/pat_rep.h similarity index 90% rename from commands/pax/pat_rep.h rename to bin/pax/pat_rep.h index 325458315..f2e0cbeca 100644 --- a/commands/pax/pat_rep.h +++ b/bin/pax/pat_rep.h @@ -1,3 +1,5 @@ +/* $NetBSD: pat_rep.h,v 1.7 2008/02/24 20:42:46 joerg Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,21 +33,19 @@ * SUCH DAMAGE. * * @(#)pat_rep.h 8.1 (Berkeley) 5/31/93 - * $FreeBSD: src/bin/pax/pat_rep.h,v 1.6 2004/04/06 20:06:48 markm Exp $ */ +#include /* * data structure for storing user supplied replacement strings (-s) */ typedef struct replace { char *nstr; /* the new string we will substitute with */ -# ifdef NET2_REGEX - regexp *rcmp; /* compiled regular expression used to match */ -# else regex_t rcmp; /* compiled regular expression used to match */ -# endif int flgs; /* print conversions? global in operation? */ #define PRNT 0x1 #define GLOB 0x2 +#define RENM 0x4 +#define SYML 0x8 struct replace *fow; /* pointer to next pattern */ } REPLACE; diff --git a/commands/pax/pax.1 b/bin/pax/pax.1 similarity index 82% rename from commands/pax/pax.1 rename to bin/pax/pax.1 index 059340446..1682e1af4 100644 --- a/commands/pax/pax.1 +++ b/bin/pax/pax.1 @@ -1,4 +1,5 @@ -.\"- +.\" $NetBSD: pax.1,v 1.61 2011/06/19 07:34:24 wiz Exp $ +.\" .\" Copyright (c) 1992 Keith Muller. .\" Copyright (c) 1992, 1993 .\" The Regents of the University of California. All rights reserved. @@ -14,7 +15,7 @@ .\" 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. -.\" 4. Neither the name of the University nor the names of its contributors +.\" 3. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" @@ -31,9 +32,8 @@ .\" SUCH DAMAGE. .\" .\" @(#)pax.1 8.4 (Berkeley) 4/18/94 -.\" $FreeBSD$ .\" -.Dd July 3, 2004 +.Dd June 18, 2011 .Dt PAX 1 .Os .Sh NAME @@ -41,147 +41,115 @@ .Nd read and write file archives and copy directory hierarchies .Sh SYNOPSIS .Nm -.Op Fl cdnvz -.Bk -words +.Op Fl 0cdjnOVvz +.Op Fl E Ar limit .Op Fl f Ar archive -.Ek -.Bk -words +.Op Fl N Ar dbdir .Op Fl s Ar replstr .Ar ...\& -.Ek -.Bk -words .Op Fl U Ar user .Ar ...\& -.Ek -.Bk -words .Op Fl G Ar group .Ar ...\& -.Ek -.Bk -words .Oo .Fl T +.Sm off .Op Ar from_date -.Op Ar ,to_date +.Oo , Ar to_date Oc +.Sm on .Oc .Ar ...\& -.Ek .Op Ar pattern ...\& .Nm .Fl r -.Op Fl cdiknuvzDYZ -.Bk -words +.Op Fl AcDdijknOuVvYZz +.Op Fl E Ar limit .Op Fl f Ar archive -.Ek -.Bk -words +.Op Fl N Ar dbdir .Op Fl o Ar options .Ar ...\& -.Ek -.Bk -words .Op Fl p Ar string .Ar ...\& -.Ek -.Bk -words .Op Fl s Ar replstr .Ar ...\& -.Ek -.Op Fl E Ar limit -.Bk -words .Op Fl U Ar user .Ar ...\& -.Ek -.Bk -words .Op Fl G Ar group .Ar ...\& -.Ek -.Bk -words .Oo .Fl T +.Sm off .Op Ar from_date -.Op Ar ,to_date +.Oo , Ar to_date Oc +.Sm on .Oc .Ar ...\& -.Ek .Op Ar pattern ...\& .Nm .Fl w -.Op Fl dituvzHLPX -.Bk -words +.Op Fl AdHijLMOPtuVvXz .Op Fl b Ar blocksize -.Ek .Oo .Op Fl a .Op Fl f Ar archive .Oc -.Bk -words .Op Fl x Ar format -.Ek -.Bk -words -.Op Fl s Ar replstr -.Ar ...\& -.Ek -.Bk -words +.Op Fl B Ar bytes +.Op Fl N Ar dbdir .Op Fl o Ar options .Ar ...\& -.Ek -.Bk -words +.Op Fl s Ar replstr +.Ar ...\& .Op Fl U Ar user .Ar ...\& -.Ek -.Bk -words .Op Fl G Ar group .Ar ...\& -.Ek -.Bk -words -.Op Fl B Ar bytes -.Ek -.Bk -words .Oo .Fl T +.Sm off .Op Ar from_date -.Op Ar ,to_date -.Op Ar /[c][m] +.Oo , Ar to_date Oc +.Oo /[ Cm c ] [ Cm m ] Oc +.Sm on .Oc .Ar ...\& -.Ek -.Op Ar +.Op Ar file ...\& .Nm .Fl r .Fl w -.Op Fl diklntuvDHLPXYZ -.Bk -words +.Op Fl ADdHijkLlMnOPtuVvXYZz +.Op Fl N Ar dbdir .Op Fl p Ar string .Ar ...\& -.Ek -.Bk -words .Op Fl s Ar replstr .Ar ...\& -.Ek -.Bk -words .Op Fl U Ar user .Ar ...\& -.Ek -.Bk -words .Op Fl G Ar group .Ar ...\& -.Ek -.Bk -words .Oo .Fl T +.Sm off .Op Ar from_date -.Op Ar ,to_date -.Op Ar /[c][m] +.Oo , Ar to_date Oc +.Oo /[ Cm c ] [ Cm m ] Oc +.Sm on .Oc .Ar ...\& -.Ek -.Op Ar +.Op Ar file ...\& .Ar directory .Sh DESCRIPTION -The .Nm -utility will read, write, and list the members of an archive file, +will read, write, and list the members of an archive file, and will copy directory hierarchies. -These operations are independent of the specific archive format, -and support a wide variety of different archive formats. +If the archive file is of the form: +.Ar [[user@]host:]file +then the archive will be processed using +.Xr rmt 8 . +.Pp +.Nm +operation is independent of the specific archive format, +and supports a wide variety of different archive formats. A list of supported archive formats can be found under the description of the .Fl x option. @@ -197,9 +165,10 @@ will operate under: and .Em copy . .Bl -tag -width 6n -.It +.It Aq none .Em List . -Write to +.Nm +will write to .Dv standard output a table of contents of the members of the archive file read from .Dv standard input , @@ -209,7 +178,8 @@ The table of contents contains one filename per line and is written using single line buffering. .It Fl r .Em Read . -Extract the members of the archive file read from the +.Nm +extracts the members of the archive file read from the .Dv standard input , with pathnames matching the specified .Ar patterns . @@ -223,7 +193,8 @@ the extracted files are discussed in more detail under the option. .It Fl w .Em Write . -Write an archive containing the +.Nm +writes an archive containing the .Ar file operands to .Dv standard output @@ -238,7 +209,8 @@ operand is also a directory, the entire file hierarchy rooted at that directory will be included. .It Fl r Fl w .Em Copy . -Copy the +.Nm +copies the .Ar file operands to the destination .Ar directory . @@ -394,10 +366,7 @@ 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 64512 bytes. -Archives larger than 32256 bytes violate the -.Tn POSIX -standard and will not be portable to all systems. +must be a multiple of 512 bytes with a maximum of 32256 bytes. A .Ar blocksize can end with @@ -458,21 +427,23 @@ operand, will prompt to .Pa /dev/tty giving the name of the file, its file mode and its modification time. -The .Nm -utility will then read a line from +will then read a line from .Pa /dev/tty . If this line is blank, the file or archive member is skipped. If this line consists of a single period, the file or archive member is processed with no modification to its name. Otherwise, its name is replaced with the contents of the line. -The .Nm -utility will immediately exit with a non-zero exit status if -.Dv +will immediately exit with a non-zero exit status if +.Aq Dv EOF is encountered when reading a response or if .Pa /dev/tty cannot be opened for reading and writing. +.It Fl j +Use +.Xr bzip2 1 +for compression when reading or writing archive files. .It Fl k Do not overwrite existing files. .It Fl l @@ -481,7 +452,8 @@ Link files. In the .Em copy mode -.Pq Fl r w , +.Fl ( r +.Fl w ) , hard links are made between the source and destination file hierarchies whenever possible. .It Fl n @@ -509,7 +481,8 @@ The option-argument is a string specifying file characteristics to be retained or discarded on extraction. The string consists of the specification characters -.Cm a , e , m , o , +.Cm a , e , +.Cm m , o , and .Cm p . Multiple characteristics can be concatenated within the same string @@ -536,6 +509,9 @@ flag is the sum of the and .Cm p flags. +.\" .It Cm f +.\" Do not preserve file flags. +.\" By default, file flags are preserved whenever possible. .It Cm m Do not preserve file modification times. By default, file modification times are preserved whenever possible. @@ -544,7 +520,7 @@ Preserve the user ID and group ID. .It Cm p .Sq Preserve the file mode bits. -This intended to be used by a +This is intended to be used by a .Em user with regular privileges who wants to preserve all aspects of the file other than the ownership. @@ -602,12 +578,12 @@ As in .Cm old is a basic regular expression and .Cm new -can contain an ampersand (&), \\n (where n is a digit) back-references, +can contain an ampersand (\*[Am]), \en (where n is a digit) back-references, or subexpression matching. The .Cm old string may also contain -.Dv +.Aq Dv newline characters. Any non-null character can be used as a delimiter (/ is shown here). Multiple @@ -628,14 +604,16 @@ The optional trailing will cause the final result of a successful substitution to be written to .Dv standard error in the following format: -.Dl >> +.Dl Ao "original pathname" Ac \*[Gt]\*[Gt] Ao "new pathname" Ac File or archive member names that substitute to the empty string are not selected and will be skipped. .It Fl t Reset the access times of any file or directory read or accessed by .Nm to be the same as they were before being read or accessed by -.Nm . +.Nm , +if the user has the appropriate permissions required by +.Xr utime 3 . .It Fl u Ignore files that are older (having a less recent file modification time) than a pre-existing file or archive member with the same name. @@ -662,14 +640,15 @@ utility with the option. For pathnames representing a hard link to a previous member of the archive, the output has the format: -.Dl == -For pathnames representing a symbolic link, the output has the format: -.Dl => -Where is the output format specified by the +.Dl Ao "ls -l listing" Ac == Ao "link name" Ac +Where +.Aq "ls -l listing" +is the output format specified by the .Xr ls 1 utility when used with the .Fl l option. +.Pp Otherwise for all the other operational modes .Em ( read , write , and @@ -677,18 +656,20 @@ and pathnames are written and flushed to .Dv standard error without a trailing -.Dv +.Aq Dv newline as soon as processing begins on that file or archive member. The trailing -.Dv , +.Aq Dv newline , is not buffered, and is written only after the file has been read or written. +.Pp +A final summary of archive operations is printed after they have been +completed. .It Fl x Ar format Specify the output archive format, with the default format being .Ar ustar . -The .Nm -utility currently supports the following formats: +currently supports the following formats: .Bl -tag -width "sv4cpio" .It Ar cpio The extended cpio interchange format specified in the @@ -709,14 +690,18 @@ by this format) which may be truncated by this format is detected by .Nm and is repaired. .It Ar sv4cpio -The System V release 4 cpio. +The +.At V.4 +cpio. The default blocksize for this format is 5120 bytes. Inode and device information about a file (used for detecting file hard links by this format) which may be truncated by this format is detected by .Nm and is repaired. .It Ar sv4crc -The System V release 4 cpio with file crc checksums. +The +.At V.4 +cpio with file crc checksums. The default blocksize for this format is 5120 bytes. Inode and device information about a file (used for detecting file hard links by this format) which may be truncated by this format is detected by @@ -732,11 +717,11 @@ Pathnames stored by this format must be 100 characters or less in length. Only .Em regular files, -.Em hard links , soft links , +.Em hard links , soft links , and -.Em directories -will be archived (other file system types are not supported). -For backwards compatibility with even older tar formats, a +.Em directories +will be archived (other file types are not supported). +For backward compatibility with even older tar formats, a .Fl o option can be used when writing an archive to omit the storage of directories. This option takes the form: @@ -749,19 +734,22 @@ The default blocksize for this format is 10240 bytes. Pathnames stored by this format must be 250 characters or less in length. .El .Pp -The .Nm -utility will detect and report any file that it is unable to store or extract +will detect and report any file that it is unable to store or extract as the result of any specific archive format restrictions. The individual archive formats may impose additional restrictions on use. Typical archive format restrictions include (but are not limited to): file pathname length, file size, link pathname length and the type of the file. +.It Fl Fl xz +Use +.Xr xz 1 +compression, when reading or writing archive files. .It Fl z Use .Xr gzip 1 -to compress (decompress) the archive while writing (reading). -Incompatible with -.Fl a . +compression, when reading or writing archive files. +.It Fl A +Do not strip leading `/'s from file names. .It Fl B Ar bytes Limit the number of bytes written to a single archive volume to .Ar bytes . @@ -790,7 +778,7 @@ This option is the same as the option, except that the file inode change time is checked instead of the file modification time. The file inode change time can be used to select files whose inode information -(e.g.\& uid, gid, etc.) is newer than a copy of the file in the destination +(e.g. uid, gid, etc.) is newer than a copy of the file in the destination .Ar directory . .It Fl E Ar limit Limit the number of consecutive read faults while trying to read a flawed @@ -829,7 +817,7 @@ Select a file based on its name, or when starting with a .Cm # , a numeric gid. -A '\\' can be used to escape the +A '\e' can be used to escape the .Cm # . Multiple .Fl G @@ -839,6 +827,75 @@ Follow only command line symbolic links while performing a physical file system traversal. .It Fl L Follow all symbolic links to perform a logical file system traversal. +.It Fl M +During a +.Em write +or +.Em copy +operation, treat the list of files on +.Dv standard input +as an +.Xr mtree 8 +.Sq specfile +specification, and write or copy only those items in the specfile. +.Pp +If the file exists in the underlying file system, its permissions and +modification time will be used unless specifically overridden by the specfile. +An error will be raised if the type of entry in the specfile conflicts +with that of an existing file. +A directory entry that is marked +.Sq Sy optional +will not be copied (even though its contents will be). +.Pp +Otherwise, the entry will be +.Sq faked-up , +and it is necessary to specify at least the following parameters +in the specfile: +.Sy type , +.Sy mode , +.Sy gname +or +.Sy gid , +and +.Sy uname +or +.Sy uid , +.Sy device +(in the case of block or character devices), and +.Sy link +(in the case of symbolic links). +If +.Sy time +isn't provided, the current time will be used. +A +.Sq faked-up +entry that is marked +.Sq Sy optional +will not be copied. +.It Fl N Ar dbdir +Except for lookups for the +.Fl G +and +.Fl U +options, +use the user database text file +.Pa master.passwd +and group database text file +.Pa group +from +.Ar dbdir , +rather than using the results from the system's +.Xr getpwnam 3 +and +.Xr getgrnam 3 +(and related) library calls. +.It Fl O +Force the archive to be one volume. +If a volume ends prematurely, +.Nm +will not prompt for a new volume. +This option can be useful for +automated tasks where error recovery cannot be performed by a human. .It Fl P Do not follow symbolic links, perform a physical file system traversal. This is the default mode. @@ -882,7 +939,7 @@ the file was last written). The .Ar c specifies the comparison of inode change time (the time when the file -inode was last changed; e.g.\& a change of owner, group, mode, etc). +inode was last changed; e.g. a change of owner, group, mode, etc). When .Ar c and @@ -902,8 +959,10 @@ changed during a specified time range will be archived). A time range is made up of six different fields and each field must contain two digits. The format is: -.Dl [yy[mm[dd[hh]]]]mm[.ss] +.Dl [[[[[cc]yy]mm]dd]hh]mm[\&.ss] Where +.Cm cc +is the first two digits of the year (the century), .Cm yy is the last two digits of the year, the first @@ -918,15 +977,15 @@ the second is the minute (from 00 to 59), and .Cm ss -is the seconds (from 00 to 59). -The minute field +is the seconds (from 00 to 61). +Only the minute field .Cm mm -is required, while the other fields are optional and must be added in the -following order: -.Dl Cm hh , dd , mm , yy . +is required; the others will default to the current system values. The .Cm ss field may be added independently of the other fields. +If the century is not specified, it defaults to 1900 for +years between 69 and 99, or 2000 for years between 0 and 68. Time ranges are relative to the current time, so .Dl Fl T Ar 1234/cm would select all files with a modification or inode change time @@ -940,11 +999,15 @@ Select a file based on its name, or when starting with a .Cm # , a numeric uid. -A '\\' can be used to escape the +A '\e' can be used to escape the .Cm # . Multiple .Fl U options may be supplied and checking stops with the first match. +.It Fl V +A final summary of archive operations is printed after they have been +completed. +Some potentially long-running tape operations are noted. .It Fl X When traversing the file hierarchy specified by a pathname, do not descend into directories that have a different device ID. @@ -963,6 +1026,24 @@ This option is the same as the .Fl u option, except that the modification time is checked using the pathname created after all the file name modifications have completed. +.It Fl 0 +Use the nul character instead of \en as the file separator when reading +files from standard input. +.It Fl Fl force-local +Do not interpret filenames that contain a `:' as remote files. +.It Fl Fl insecure +Normally +.Nm +ignores filenames that contain +.Dq .. +as a path component. +With this option, +files that contain +.Dq .. +can be processed. +.It Fl Fl use-compress-program +Use the named program as the program to decompress the input or compress +the output. .El .Pp The options that operate on the names of files or archive members @@ -1050,20 +1131,55 @@ options are specified along with the option, a file is not considered selected unless it is newer than the file to which it is compared. .Sh EXIT STATUS -The .Nm -utility will exit with one of the following values: +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 reading an archive or cannot +find a file when writing an archive, or cannot preserve the user ID, +group ID, or file mode when the +.Fl p +option is specified, a diagnostic message is written to +.Dv standard error +and a non-zero exit status will be returned, but processing will continue. +In the case where pax 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 a 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. +.Pp +If while doing a +.Em copy , +.Nm +detects a file is about to overwrite itself, the file is not copied, +a diagnostic message is written to +.Dv standard error +and when +.Nm +completes it will exit with a non-zero exit status. .Sh EXAMPLES The command: -.Dl "pax -w -f /dev/sa0 ." +.Dl pax -w -f /dev/rst0 \&. copies the contents of the current directory to the device -.Pa /dev/sa0 . +.Pa /dev/rst0 . .Pp The command: .Dl pax -v -f filename @@ -1071,13 +1187,25 @@ gives the verbose table of contents for an archive stored in .Pa filename . .Pp The following commands: -.Dl mkdir /tmp/to -.Dl cd /tmp/from -.Dl pax -rw .\ /tmp/to +.Dl mkdir newdir +.Dl cd olddir +.Dl pax -rw -pp .\ ../newdir will copy the entire -.Pa /tmp/from +.Pa olddir directory hierarchy to -.Pa /tmp/to . +.Pa newdir , +preserving permissions and access times. +.Pp +When running as root, one may also wish to preserve file +ownership when copying directory trees. +This can be done with the following commands: +.Dl cd olddir +.Dl pax -rw -pe .\ ../newdir +which will copy the contents of +.Pa olddir +into +.Pa ../newdir , +preserving ownership, permissions and access times. .Pp The command: .Dl pax -r -s ',^//*usr//*,,' -f a.pax @@ -1109,45 +1237,11 @@ will update (and list) only those files in the destination directory which are older (less recent inode change or file modification times) than files with the same name found in the source file tree .Pa home . -.Sh DIAGNOSTICS -Whenever -.Nm -cannot create a file or a link when reading an archive or cannot -find a file when writing an archive, or cannot preserve the user ID, -group ID, or file mode when the -.Fl p -option is specified, a diagnostic message is written to -.Dv standard error -and a non-zero exit status will be returned, but processing will continue. -In the case where pax 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 a 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. -.Pp -If while doing a -.Em copy , -.Nm -detects a file is about to overwrite itself, the file is not copied, -a diagnostic message is written to -.Dv standard error -and when -.Nm -completes it will exit with a non-zero exit status. .Sh SEE ALSO .Xr cpio 1 , -.Xr tar 1 +.Xr tar 1 , +.Xr symlink 7 , +.Xr mtree 8 .Sh STANDARDS The .Nm @@ -1155,18 +1249,20 @@ utility is a superset of the .St -p1003.2 standard. The options -.Fl z , .Fl B , .Fl D , .Fl E , .Fl G , .Fl H , .Fl L , +.Fl M , +.Fl O , .Fl P , .Fl T , .Fl U , .Fl Y , .Fl Z , +.Fl z , the archive formats .Ar bcpio , .Ar sv4cpio , @@ -1179,15 +1275,7 @@ and operations are extensions to the .Tn POSIX standard. -.Sh HISTORY -The -.Nm -utility appeared in -.Bx 4.4 . .Sh AUTHORS -.An Keith Muller -at the University of California, San Diego -.Sh BUGS -The -.Nm -utility does not recognize multibyte characters. +Keith Muller at the University of California, San Diego. +Luke Mewburn implemented +.Fl M . diff --git a/commands/pax/pax.c b/bin/pax/pax.c similarity index 81% rename from commands/pax/pax.c rename to bin/pax/pax.c index e454e1a45..563f71d37 100644 --- a/commands/pax/pax.c +++ b/bin/pax/pax.c @@ -1,3 +1,5 @@ +/* $NetBSD: pax.c,v 1.47 2011/08/29 14:47:48 joerg Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,31 +33,35 @@ * SUCH DAMAGE. */ -#if 0 -#ifndef lint -static char const copyright[] = -"@(#) Copyright (c) 1992, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif -#ifndef lint +#include +#if !defined(lint) +__COPYRIGHT("@(#) Copyright (c) 1992, 1993\ + The Regents of the University of California. All rights reserved."); +#if 0 static char sccsid[] = "@(#)pax.c 8.2 (Berkeley) 4/18/94"; -#endif /* not lint */ +#else +__RCSID("$NetBSD: pax.c,v 1.47 2011/08/29 14:47:48 joerg Exp $"); #endif +#endif /* not lint */ #include +#include #include #include #include -#include +#include #include -#include -#include #include -#include +#include #include #include -#include +#include +#include +#include #include "pax.h" #include "extern.h" static int gen_init(void); @@ -70,7 +76,7 @@ static int gen_init(void); int act = ERROR; /* read/write/append/copy */ FSUB *frmt = NULL; /* archive format type */ int cflag; /* match all EXCEPT pattern/file */ -int cwdfd; /* starting cwd */ +int cwdfd = -1; /* starting cwd */ int dflag; /* directory member match only */ int iflag; /* interactive file/archive rename */ int kflag; /* do not overwrite existing files */ @@ -79,9 +85,12 @@ int nflag; /* select first archive member match */ int tflag; /* restore access time after read */ int uflag; /* ignore older modification time files */ int vflag; /* produce verbose output */ +int Aflag; /* honor absolute path */ int Dflag; /* same as uflag except inode change time */ int Hflag; /* follow command line symlinks (write only) */ int Lflag; /* follow symlinks when writing */ +int Mflag; /* treat stdin as an mtree(8) specfile */ +int Vflag; /* produce somewhat verbose output (no listing) */ int Xflag; /* archive files with same device id only */ int Yflag; /* same as Dflg except after name mode */ int Zflag; /* same as uflg except after name mode */ @@ -89,22 +98,29 @@ 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 pfflags = 1; /* preserve file flags */ 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 */ +int to_stdout; /* extract to stdout */ char *dirptr; /* destination dir in a copy */ -const char *argv0; /* root of argv[0] */ +char *ltmfrmt; /* -v locale time format (if any) */ +const char *argv0; /* root of argv[0] */ sigset_t s_mask; /* signal mask for cleanup critical sect */ FILE *listf; /* 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) */ +int forcelocal; /* force local operation even if the name + * contains a : + */ +int secure = 1; /* don't extract names that contain .. */ /* * PAX - Portable Archive Interchange * - * A utility to read, write, and write lists of the members of archive + * A utility to read, write, and write lists of the members of archive * files and copy directory hierarchies. A variety of archive formats * are supported (some are described in POSIX 1003.1 10.1): * @@ -131,7 +147,7 @@ char *tempbase; /* basename of tempfile to use for mkstemp(3) */ * of times to correct, or try to correct forever. * 1.4 Sparse files (lseek holes) stored on the archive (but stored with blocks * of all zeros will be restored with holes appropriate for the target - * file system + * filesystem * 1.5 The user is notified whenever something is found during archive * read operations which violates spec (but the read will continue). * 1.6 Multiple archive volumes can be read and may span over different @@ -185,7 +201,7 @@ char *tempbase; /* basename of tempfile to use for mkstemp(3) */ * 3 COPY ENHANCEMENTS * 3.1 Sparse files (lseek holes) can be copied without expanding the holes * into zero filled blocks. The file copy is created with holes which are - * appropriate for the target file system + * appropriate for the target filesystem * 3.2 Access time as well as modification time on copied file trees can be * preserved with the appropriate -p options. * 3.3 Access time reset with the -t applies to all file nodes (including @@ -200,9 +216,9 @@ char *tempbase; /* basename of tempfile to use for mkstemp(3) */ * more -G options. * 3.8 Symlinks which appear on the command line can be followed (without * following other symlinks; -H flag) - * 3.9 File inode change time can be checked against existing file before + * 3.9 File inode change time can be checked against existing file before * name modification (-D) - * 3.10 File inode change time can be checked against existing file after + * 3.10 File inode change time can be checked against existing file after * name modification (-Y) * 3.11 File modification time can be checked against existing file after * name modification (-Z) @@ -222,21 +238,37 @@ char *tempbase; /* basename of tempfile to use for mkstemp(3) */ */ int -main(int argc, char *argv[]) +main(int argc, char **argv) { const char *tmpdir; size_t tdlen; + int rval; + + setprogname(argv[0]); - (void) setlocale(LC_ALL, ""); listf = stderr; + + /* + * parse options, determine operational mode + */ + options(argc, argv); + + /* + * general init + */ + if ((gen_init() < 0) || (tty_init() < 0)) + return exit_val; + /* * 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); + syswarn(1, errno, "Can't open current working directory."); + return exit_val; } + if (updatepath() == -1) + return exit_val; /* * Where should we put temporary files? @@ -248,45 +280,52 @@ main(int argc, char *argv[]) tdlen--; tempfile = malloc(tdlen + 1 + sizeof(_TFILE_BASE)); if (tempfile == NULL) { - paxwarn(1, "Cannot allocate memory for temp file name."); - return(exit_val); + tty_warn(1, "Cannot allocate memory for temp file name."); + return exit_val; } if (tdlen) memcpy(tempfile, tmpdir, tdlen); tempbase = tempfile + tdlen; *tempbase++ = '/'; - /* - * parse options, determine operational mode, general init - */ - options(argc, argv); - if ((gen_init() < 0) || (tty_init() < 0)) - return(exit_val); - + (void)time(&starttime); +#ifdef SIGINFO + (void)signal(SIGINFO, ar_summary); +#endif /* * select a primary operation mode */ - switch(act) { + switch (act) { case EXTRACT: - extract(); + rval = extract(); break; case ARCHIVE: - archive(); + rval = archive(); break; case APPND: if (gzip_program != NULL) - err(1, "can not gzip while appending"); - append(); + err(1, "cannot gzip while appending"); + rval = append(); + /* + * Check if we tried to append on an empty file and + * turned into ARCHIVE mode. + */ + if (act == -ARCHIVE) { + act = ARCHIVE; + rval = archive(); + } break; case COPY: - copy(); + rval = copy(); break; default: case LIST: - list(); + rval = list(); break; } - return(exit_val); + if (rval != 0) + exit_val = 1; + return exit_val; } /* @@ -298,7 +337,7 @@ main(int argc, char *argv[]) * never.... */ -void +__dead static void sig_cleanup(int which_sig) { /* @@ -307,18 +346,22 @@ sig_cleanup(int which_sig) * will clearly see the message on a line by itself. */ vflag = vfpart = 1; -#if 0 - /* ignore this under minix */ +#ifdef SIGXCPU if (which_sig == SIGXCPU) - paxwarn(0, "Cpu time limit reached, cleaning up."); + tty_warn(1, "CPU time limit reached, cleaning up."); else #endif - paxwarn(0, "Signal caught, cleaning up."); + tty_warn(1, "Signal caught, cleaning up."); + /* delete any open temporary file */ + if (xtmp_name) + (void)unlink(xtmp_name); ar_close(); proc_dir(); if (tflag) atdir_end(); + + (void)raise_default_signal(which_sig); exit(1); } @@ -331,13 +374,13 @@ sig_cleanup(int which_sig) static int gen_init(void) { -#if 0 +#ifndef __minix struct rlimit reslimit; #endif struct sigaction n_hand; struct sigaction o_hand; -#if 0 +#ifndef __minix /* * Really needed to handle large archives. We can run out of memory for * internal tables really fast when we have a whole lot of files... @@ -364,6 +407,7 @@ gen_init(void) (void)setrlimit(RLIMIT_STACK , &reslimit); } +#ifdef RLIMIT_RSS /* * not really needed, but doesn't hurt */ @@ -372,24 +416,40 @@ gen_init(void) (void)setrlimit(RLIMIT_RSS , &reslimit); } #endif +#endif /* __minix */ + + /* + * Handle posix locale + * + * set user defines time printing format for -v option + */ + ltmfrmt = getenv("LC_TIME"); /* * signal handling to reset stored directory times and modes. Since * we deal with broken pipes via failed writes we ignore it. We also - * deal with any file size limit thorugh failed writes. Cpu time + * deal with any file size limit through failed writes. CPU time * limits are caught and a cleanup is forced. */ - if ((sigemptyset(&s_mask) < 0) || (sigaddset(&s_mask, SIGTERM) < 0) || (sigaddset(&s_mask,SIGINT) < 0)||(sigaddset(&s_mask,SIGHUP) < 0) || - (sigaddset(&s_mask,SIGPIPE) < 0)||(sigaddset(&s_mask,SIGQUIT)<0) -#if 0 - || (sigaddset(&s_mask,SIGXCPU) < 0)||(sigaddset(&s_mask,SIGXFSZ)<0) + (sigaddset(&s_mask,SIGPIPE) < 0)||(sigaddset(&s_mask,SIGQUIT)<0)){ + tty_warn(1, "Unable to set up signal mask"); + return -1; + } +#ifdef SIGXCPU + if (sigaddset(&s_mask,SIGXCPU) < 0) { + tty_warn(1, "Unable to set up signal mask"); + return -1; + } #endif - ) { - paxwarn(1, "Unable to set up signal mask"); - return(-1); +#ifdef SIGXFSZ + if (sigaddset(&s_mask,SIGXFSZ) < 0) { + tty_warn(1, "Unable to set up signal mask"); + return -1; } +#endif + memset(&n_hand, 0, sizeof n_hand); n_hand.sa_mask = s_mask; n_hand.sa_flags = 0; @@ -415,25 +475,22 @@ gen_init(void) (sigaction(SIGQUIT, &o_hand, &o_hand) < 0)) goto out; -#if 0 +#ifdef SIGXCPU if ((sigaction(SIGXCPU, &n_hand, &o_hand) < 0) && (o_hand.sa_handler == SIG_IGN) && (sigaction(SIGXCPU, &o_hand, &o_hand) < 0)) goto out; #endif - n_hand.sa_handler = SIG_IGN; - if ((sigaction(SIGPIPE, &n_hand, &o_hand) < 0) -#if 0 - || (sigaction(SIGXFSZ, &n_hand, &o_hand) < 0) -#endif - ) - - + if (sigaction(SIGPIPE, &n_hand, &o_hand) < 0) + goto out; +#ifdef SIGXFSZ + if (sigaction(SIGXFSZ, &n_hand, &o_hand) < 0) goto out; - return(0); +#endif + return 0; out: syswarn(1, errno, "Unable to set up signal handler"); - return(-1); + return -1; } diff --git a/commands/pax/pax.h b/bin/pax/pax.h similarity index 72% rename from commands/pax/pax.h rename to bin/pax/pax.h index afbc114df..eb09e39e6 100644 --- a/commands/pax/pax.h +++ b/bin/pax/pax.h @@ -1,3 +1,5 @@ +/* $NetBSD: pax.h,v 1.31 2012/08/09 08:09:21 christos Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,32 +33,31 @@ * SUCH DAMAGE. * * @(#)pax.h 8.2 (Berkeley) 4/18/94 - * $FreeBSD: src/bin/pax/pax.h,v 1.18 2004/04/06 20:06:48 markm Exp $ */ - -#include -#include +#if ! HAVE_NBTOOL_CONFIG_H && !defined(__minix) +#define HAVE_LUTIMES 1 +#define HAVE_STRUCT_STAT_ST_FLAGS 1 +#endif /* * BSD PAX global data structures and constants. */ -#define MAXBLK 64512 /* MAX blocksize supported (posix SPEC) */ +#define MAXBLK 32256 /* 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 */ #define FILEBLK 10240 /* default read blksize for files */ #define PAXPATHLEN 3072 /* maximum path length for pax. MUST be */ - /* longer than the system PATH_MAX */ + /* longer than the system MAXPATHLEN */ /* * Pax modes of operation */ -#define ERROR -1 /* nothing selected */ +#define ERROR -1 /* nothing selected */ #define LIST 0 /* List the file in an archive */ #define EXTRACT 1 /* extract the files in an archive */ #define ARCHIVE 2 /* write a new archive */ @@ -71,11 +72,69 @@ #define ISBLK 2 /* block device */ #define ISTAPE 3 /* tape drive */ #define ISPIPE 4 /* pipe/socket */ +#ifdef SUPPORT_RMT +#define ISRMT 5 /* rmt */ +#endif + +/* + * Pattern matching structure + * + * Used to store command line patterns + */ +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 */ +#define DIR_MTCH 0x2 /* pattern matched a directory */ +#define NOGLOB_MTCH 0x4 /* non-globbing match */ + struct pattern *fow; /* next pattern */ +} PATTERN; -typedef struct archd ARCHD; -typedef struct fsub FSUB; -typedef struct oplist OPLIST; -typedef struct pattern PATTERN; +/* + * General Archive Structure (used internal to pax) + * + * This structure is used to pass information about archive members between + * the format independent routines and the format specific routines. When + * new archive formats are added, they must accept requests and supply info + * encoded in a structure of this type. The name fields are declared statically + * here, as there is only ONE of these floating around, size is not a major + * consideration. Eventually converting the name fields to a dynamic length + * may be required if and when the supporting operating system removes all + * restrictions on the length of pathnames it will resolve. + */ +typedef struct { + int nlen; /* file name length */ + char name[PAXPATHLEN+1]; /* file name */ + int ln_nlen; /* link name length */ + char ln_name[PAXPATHLEN+1]; /* name to link to (if any) */ + char *org_name; /* orig name in file system */ + char fts_name[PAXPATHLEN+1]; /* name from fts (for *org_name) */ + char *tmp_name; /* tmp name used to restore */ + PATTERN *pat; /* ptr to pattern match (if any) */ + struct stat sb; /* stat buffer see stat(2) */ + off_t pad; /* bytes of padding after file xfer */ + off_t skip; /* bytes of real data after header */ + /* IMPORTANT. The st_size field does */ + /* not always indicate the amount of */ + /* data following the header. */ + u_long crc; /* file crc */ + int type; /* type of file node */ +#define PAX_DIR 1 /* directory */ +#define PAX_CHR 2 /* character device */ +#define PAX_BLK 3 /* block device */ +#define PAX_REG 4 /* regular file */ +#define PAX_SLK 5 /* symbolic link */ +#define PAX_SCK 6 /* socket */ +#define PAX_FIF 7 /* fifo */ +#define PAX_HLK 8 /* hard link */ +#define PAX_HRG 9 /* hard link to a regular file */ +#define PAX_CTG 10 /* high performance file */ +#define PAX_GLL 11 /* GNU long symlink */ +#define PAX_GLF 12 /* GNU long file */ +} ARCHD; /* * Format Specific Routine Table @@ -87,13 +146,13 @@ typedef struct pattern PATTERN; * independent of the archive format. Data flow in and out of the format * dependent routines pass pointers to ARCHD structure (described below). */ -struct fsub { +typedef struct { const char *name; /* name of format, this is the name the user */ /* gives to -x option to select it. */ int bsz; /* default block size. used when the user */ /* does not specify a blocksize for writing */ /* Appends continue to with the blocksize */ - /* the archive is currently using. */ + /* the archive is currently using.*/ int hsz; /* Header size in bytes. this is the size of */ /* the smallest header this format supports. */ /* Headers are assumed to fit in a BLKMULT. */ @@ -118,19 +177,18 @@ struct fsub { int (*st_rd)(void); /* initialize routine for read. so format */ /* can set up tables etc before it starts */ /* reading an archive */ - int (*rd)(ARCHD *, char *); - /* read header routine. passed a pointer to */ - /* ARCHD. It must extract the info from the */ - /* format and store it in the ARCHD struct. */ - /* This routine is expected to fill all the */ - /* fields in the ARCHD (including stat buf) */ - /* 0 is returned when a valid header is */ - /* found. -1 when not valid. This routine */ - /* set the skip and pad fields so the format */ - /* independent routines know the amount of */ - /* padding and the number of bytes of data */ - /* which follow the header. This info is */ - /* used skip to the next file header */ + int (*rd) /* read header routine. passed a pointer to */ + (ARCHD *, char *); /* ARCHD. It must extract the info */ + /* from the format and store it in the ARCHD */ + /* struct. This routine is expected to fill */ + /* all the fields in the ARCHD (including */ + /* stat buf). 0 is returned when a valid */ + /* header is found. -1 when not valid. This */ + /* routine set the skip and pad fields so the */ + /* format independent routines know the */ + /* amount of padding and the number of bytes */ + /* of data which follow the header. This info */ + /* is used to skip to the next file header */ off_t (*end_rd)(void); /* read cleanup. Allows format to clean up */ /* and MUST RETURN THE LENGTH OF THE TRAILER */ /* RECORD (so append knows how many bytes */ @@ -149,103 +207,77 @@ struct fsub { int (*end_wr)(void); /* end write. write the trailer and do any */ /* other format specific functions needed */ /* at the end of an archive write */ - int (*trail_cpio)(ARCHD *); - int (*trail_tar)(char *, int, int *); - /* returns 0 if a valid trailer, -1 if not */ - /* For formats which encode the trailer */ - /* outside of a valid header, a return value */ - /* of 1 indicates that the block passed to */ - /* it can never contain a valid header (skip */ - /* this block, no point in looking at it) */ - int (*rd_data)(ARCHD *, int, off_t *); - /* read/process file data from the archive */ - int (*wr_data)(ARCHD *, int, off_t *); - /* write/process file data to the archive */ + int (*trail) /* returns 0 if a valid trailer, -1 if not */ + (char *, int, int *); /* For formats which encode the */ + /* trailer outside of a valid header, a */ + /* return value of 1 indicates that the block */ + /* passed to it can never contain a valid */ + /* header (skip this block, no point in */ + /* looking at it) */ + int (*subtrail) /* read/process file data from the archive */ + (ARCHD *); /* this function is called for trailers */ + /* inside headers. */ + int (*rd_data) /* read/process file data from the archive */ + (ARCHD *, int, off_t *); + int (*wr_data) /* write/process file data to the archive */ + (ARCHD *, int, off_t *); int (*options)(void); /* process format specific options (-o) */ -}; - -/* - * Pattern matching structure - * - * Used to store command line patterns - */ -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 */ -#define DIR_MTCH 0x2 /* pattern matched a directory */ - struct pattern *fow; /* next pattern */ -}; - -/* - * General Archive Structure (used internal to pax) - * - * This structure is used to pass information about archive members between - * the format independent routines and the format specific routines. When - * new archive formats are added, they must accept requests and supply info - * encoded in a structure of this type. The name fields are declared statically - * here, as there is only ONE of these floating around, size is not a major - * consideration. Eventually converting the name fields to a dynamic length - * may be required if and when the supporting operating system removes all - * restrictions on the length of pathnames it will resolve. - */ -struct archd { - int nlen; /* file name length */ - char name[PAXPATHLEN+1]; /* file name */ - int ln_nlen; /* link name length */ - char ln_name[PAXPATHLEN+1]; /* name to link to (if any) */ - char *org_name; /* orig name in file system */ - PATTERN *pat; /* ptr to pattern match (if any) */ - struct stat sb; /* stat buffer see stat(2) */ - off_t pad; /* bytes of padding after file xfer */ - off_t skip; /* bytes of real data after header */ - /* IMPORTANT. The st_size field does */ - /* not always indicate the amount of */ - /* data following the header. */ - u_long crc; /* file crc */ - int type; /* type of file node */ -#define PAX_DIR 1 /* directory */ -#define PAX_CHR 2 /* character device */ -#define PAX_BLK 3 /* block device */ -#define PAX_REG 4 /* regular file */ -#define PAX_SLK 5 /* symbolic link */ -#define PAX_SCK 6 /* socket */ -#define PAX_FIF 7 /* fifo */ -#define PAX_HLK 8 /* hard link */ -#define PAX_HRG 9 /* hard link to a regular file */ -#define PAX_CTG 10 /* high performance file */ -}; +} FSUB; /* * Format Specific Options List * * Used to pass format options to the format options handler */ -struct oplist { +typedef struct oplist { char *name; /* option variable name e.g. name= */ char *value; /* value for option variable */ struct oplist *fow; /* next option */ -}; +} OPLIST; /* * General Macros */ #ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifdef HOSTPROG +# include "pack_dev.h" /* explicitly use NetBSD's macros */ +# define MAJOR(x) major_netbsd(x) +# define MINOR(x) minor_netbsd(x) +# define TODEV(x, y) makedev_netbsd((x), (y)) +#else +# define MAJOR(x) major(x) +# define MINOR(x) minor(x) +# define TODEV(x, y) makedev((x), (y)) #endif -#define TODEV(x, y) makedev((x), (y)) /* * General Defines */ -#define HEX 16 -#define OCT 8 -#define _PAX_ 1 +#define HEX 16 +#define OCT 8 +#define _PAX_ 1 + +/* + * Pathname base component of the temporary file template, to be created in + * ${TMPDIR} or, as a fall-back, _PATH_TMP. + */ #define _TFILE_BASE "paxXXXXXXXXXX" -#define err(c, str) { perror(str); exit(c); } -#define setpassent(a) setpwent() -#define setgroupent(a) setgrent() +/* + * Macros to manipulate off_t as uintmax_t + */ +#define OFFT_F "%" PRIuMAX +#define OFFT_FP(x) "%" x PRIuMAX +#define OFFT_T uintmax_t +#define ASC_OFFT(x,y,z) asc_umax(x,y,z) +#define OFFT_ASC(w,x,y,z) umax_asc((uintmax_t)w,x,y,z) +#define OFFT_OCT(w,x,y,z) umax_oct((uintmax_t)w,x,y,z) +#define STRTOOFFT(x,y,z) strtoimax(x,y,z) +#define OFFT_MAX INTMAX_MAX + +#define TOP_HALF 0xffffffff00000000ULL +#define BOTTOM_HALF 0x00000000ffffffffULL + diff --git a/commands/pax/sel_subs.c b/bin/pax/sel_subs.c similarity index 78% rename from commands/pax/sel_subs.c rename to bin/pax/sel_subs.c index 3746a00b5..87f1e797f 100644 --- a/commands/pax/sel_subs.c +++ b/bin/pax/sel_subs.c @@ -1,3 +1,5 @@ +/* $NetBSD: sel_subs.c,v 1.24 2011/08/31 16:24:54 plunky Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,28 +33,40 @@ * SUCH DAMAGE. */ -#ifndef lint +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) #if 0 static char sccsid[] = "@(#)sel_subs.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: sel_subs.c,v 1.24 2011/08/31 16:24:54 plunky Exp $"); #endif #endif /* not lint */ #include #include #include +#include + #include -#include #include #include +#include #include #include +#include #include #include +#include + #include "pax.h" #include "sel_subs.h" #include "extern.h" -static int str_sec(char *, time_t *); +static int str_sec(const char *, time_t *); static int usr_match(ARCHD *); static int grp_match(ARCHD *); static int trng_match(ARCHD *); @@ -79,15 +93,15 @@ sel_chk(ARCHD *arcn) if (((usrtb != NULL) && usr_match(arcn)) || ((grptb != NULL) && grp_match(arcn)) || ((trhead != NULL) && trng_match(arcn))) - return(1); - return(0); + return 1; + return 0; } /* * User/group selection routines * * Routines to handle user selection of files based on the file uid/gid. To - * add an entry, the user supplies either then name or the uid/gid starting with + * add an entry, the user supplies either the name or the uid/gid starting with * a # on the command line. A \# will escape the #. */ @@ -110,11 +124,12 @@ usr_add(char *str) * create the table if it doesn't exist */ if ((str == NULL) || (*str == '\0')) - return(-1); + return -1; if ((usrtb == NULL) && - ((usrtb = (USRT **)calloc(USR_TB_SZ, sizeof(USRT *))) == NULL)) { - paxwarn(1, "Unable to allocate memory for user selection table"); - return(-1); + ((usrtb = (USRT **)calloc(USR_TB_SZ, sizeof(USRT *))) == NULL)) { + tty_warn(1, + "Unable to allocate memory for user selection table"); + return -1; } /* @@ -127,16 +142,12 @@ usr_add(char *str) if ((str[0] == '\\') && (str[1] == '#')) ++str; if ((pw = getpwnam(str)) == NULL) { - paxwarn(1, "Unable to find uid for user: %s", str); - return(-1); + tty_warn(1, "Unable to find uid for user: %s", str); + return -1; } uid = (uid_t)pw->pw_uid; } else -# ifdef NET2_STAT - uid = (uid_t)atoi(str+1); -# else uid = (uid_t)strtoul(str+1, NULL, 10); -# endif endpwent(); /* @@ -146,7 +157,7 @@ usr_add(char *str) if ((pt = usrtb[indx]) != NULL) { while (pt != NULL) { if (pt->uid == uid) - return(0); + return 0; pt = pt->fow; } } @@ -158,10 +169,10 @@ usr_add(char *str) pt->uid = uid; pt->fow = usrtb[indx]; usrtb[indx] = pt; - return(0); + return 0; } - paxwarn(1, "User selection table out of memory"); - return(-1); + tty_warn(1, "User selection table out of memory"); + return -1; } /* @@ -182,14 +193,14 @@ usr_match(ARCHD *arcn) pt = usrtb[((unsigned)arcn->sb.st_uid) % USR_TB_SZ]; while (pt != NULL) { if (pt->uid == arcn->sb.st_uid) - return(0); + return 0; pt = pt->fow; } /* * not found */ - return(1); + return 1; } /* @@ -211,11 +222,12 @@ grp_add(char *str) * create the table if it doesn't exist */ if ((str == NULL) || (*str == '\0')) - return(-1); + return -1; if ((grptb == NULL) && - ((grptb = (GRPT **)calloc(GRP_TB_SZ, sizeof(GRPT *))) == NULL)) { - paxwarn(1, "Unable to allocate memory fo group selection table"); - return(-1); + ((grptb = (GRPT **)calloc(GRP_TB_SZ, sizeof(GRPT *))) == NULL)) { + tty_warn(1, + "Unable to allocate memory fo group selection table"); + return -1; } /* @@ -228,16 +240,13 @@ grp_add(char *str) if ((str[0] == '\\') && (str[1] == '#')) ++str; if ((gr = getgrnam(str)) == NULL) { - paxwarn(1,"Cannot determine gid for group name: %s", str); - return(-1); + tty_warn(1, + "Cannot determine gid for group name: %s", str); + return -1; } - gid = gr->gr_gid; + gid = (gid_t)gr->gr_gid; } else -# ifdef NET2_STAT - gid = (gid_t)atoi(str+1); -# else gid = (gid_t)strtoul(str+1, NULL, 10); -# endif endgrent(); /* @@ -247,7 +256,7 @@ grp_add(char *str) if ((pt = grptb[indx]) != NULL) { while (pt != NULL) { if (pt->gid == gid) - return(0); + return 0; pt = pt->fow; } } @@ -259,10 +268,10 @@ grp_add(char *str) pt->gid = gid; pt->fow = grptb[indx]; grptb[indx] = pt; - return(0); + return 0; } - paxwarn(1, "Group selection table out of memory"); - return(-1); + tty_warn(1, "Group selection table out of memory"); + return -1; } /* @@ -283,14 +292,14 @@ grp_match(ARCHD *arcn) pt = grptb[((unsigned)arcn->sb.st_gid) % GRP_TB_SZ]; while (pt != NULL) { if (pt->gid == arcn->sb.st_gid) - return(0); + return 0; pt = pt->fow; } /* * not found */ - return(1); + return 1; } /* @@ -301,11 +310,11 @@ grp_match(ARCHD *arcn) * -T flag). The user may specify any number of different file time ranges. * Time ranges are checked one at a time until a match is found (if at all). * If the file has a mtime (and/or ctime) which lies within one of the time - * ranges, the file is selected. Time ranges may have a lower and/or an upper + * ranges, the file is selected. Time ranges may have a lower and/or a upper * value. These ranges are inclusive. When no time ranges are supplied to pax * with the -T option, all members in the archive will be selected by the time * range routines. When only a lower range is supplied, only files with a - * mtime (and/or ctime) equal to or younger are selected. When only an upper + * mtime (and/or ctime) equal to or younger are selected. When only a upper * range is supplied, only files with a mtime (and/or ctime) equal to or older * are selected. When the lower time range is equal to the upper time range, * only files with a mtime (or ctime) of exactly that time are selected. @@ -335,8 +344,8 @@ trng_add(char *str) * throw out the badly formed time ranges */ if ((str == NULL) || (*str == '\0')) { - paxwarn(1, "Empty time range string"); - return(-1); + tty_warn(1, "Empty time range string"); + return -1; } /* @@ -362,20 +371,20 @@ trng_add(char *str) ++dot; continue; } - paxwarn(1, "Improperly specified time range: %s", str); + tty_warn(1, "Improperly specified time range: %s", str); goto out; } /* * allocate space for the time range and store the limits */ - if ((pt = (TIME_RNG *)malloc(sizeof(TIME_RNG))) == NULL) { - paxwarn(1, "Unable to allocate memory for time range"); - return(-1); + if ((pt = malloc(sizeof(TIME_RNG))) == NULL) { + tty_warn(1, "Unable to allocate memory for time range"); + return -1; } /* - * by default we only will check file mtime, but usee can specify + * by default we only will check file mtime, but user can specify * mtime, ctime (inode change time) or both. */ if ((flgpt == NULL) || (*flgpt == '\0')) @@ -393,8 +402,9 @@ trng_add(char *str) pt->flgs |= CMPCTME; break; default: - paxwarn(1, "Bad option %c with time range %s", + tty_warn(1, "Bad option %c with time range %s", *flgpt, str); + free(pt); goto out; } ++flgpt; @@ -410,8 +420,8 @@ trng_add(char *str) * add lower limit */ if (str_sec(str, &(pt->low_time)) < 0) { - paxwarn(1, "Illegal lower time range %s", str); - (void)free((char *)pt); + tty_warn(1, "Illegal lower time range %s", str); + free(pt); goto out; } pt->flgs |= HASLOW; @@ -422,8 +432,8 @@ trng_add(char *str) * add upper limit */ if (str_sec(up_pt, &(pt->high_time)) < 0) { - paxwarn(1, "Illegal upper time range %s", up_pt); - (void)free((char *)pt); + tty_warn(1, "Illegal upper time range %s", up_pt); + free(pt); goto out; } pt->flgs |= HASHIGH; @@ -433,10 +443,11 @@ trng_add(char *str) */ if (pt->flgs & HASLOW) { if (pt->low_time > pt->high_time) { - paxwarn(1, "Upper %s and lower %s time overlap", - up_pt, str); - (void)free((char *)pt); - return(-1); + tty_warn(1, + "Upper %s and lower %s time overlap", + up_pt, str); + free(pt); + return -1; } } } @@ -444,15 +455,15 @@ trng_add(char *str) pt->fow = NULL; if (trhead == NULL) { trtail = trhead = pt; - return(0); + return 0; } trtail->fow = pt; trtail = pt; - return(0); + return 0; out: - paxwarn(1, "Time range format is: [yy[mm[dd[hh]]]]mm[.ss][/[c][m]]"); - return(-1); + tty_warn(1, "Time range format is: [yy[mm[dd[hh]]]]mm[.ss][/[c][m]]"); + return -1; } /* @@ -519,8 +530,8 @@ trng_match(ARCHD *arcn) } if (pt == NULL) - return(1); - return(0); + return 1; + return 0; } /* @@ -531,75 +542,76 @@ trng_match(ARCHD *arcn) * 0 if converted ok, -1 otherwise */ +#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0')) + static int -str_sec(char *str, time_t *tval) +str_sec(const char *p, time_t *tval) { struct tm *lt; - char *dot = NULL; + const char *dot, *t; + int yearset, len; + + for (t = p, dot = NULL; *t; ++t) { + if (isdigit((unsigned char)*t)) + continue; + if (*t == '.' && dot == NULL) { + dot = t; + continue; + } + return -1; + } lt = localtime(tval); - if ((dot = strchr(str, '.')) != NULL) { - /* - * seconds (.ss) - */ - *dot++ = '\0'; - if (strlen(dot) != 2) - return(-1); - if ((lt->tm_sec = ATOI2(dot)) > 61) - return(-1); - } else + + if (dot != NULL) { + len = strlen(dot); + if (len != 3) + return -1; + ++dot; + lt->tm_sec = ATOI2(dot); + } else { + len = 0; lt->tm_sec = 0; + } - switch (strlen(str)) { + yearset = 0; + switch (strlen(p) - len) { + case 12: + lt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE; + yearset = 1; + /* FALLTHROUGH */ case 10: - /* - * year (yy) - * watch out for year 2000 - */ - if ((lt->tm_year = ATOI2(str)) < 69) - lt->tm_year += 100; - str += 2; + if (yearset) { + lt->tm_year += ATOI2(p); + } else { + yearset = ATOI2(p); + if (yearset < 69) + lt->tm_year = yearset + 2000 - TM_YEAR_BASE; + else + lt->tm_year = yearset + 1900 - TM_YEAR_BASE; + } /* FALLTHROUGH */ case 8: - /* - * month (mm) - * watch out months are from 0 - 11 internally - */ - if ((lt->tm_mon = ATOI2(str)) > 12) - return(-1); + lt->tm_mon = ATOI2(p); --lt->tm_mon; - str += 2; /* FALLTHROUGH */ case 6: - /* - * day (dd) - */ - if ((lt->tm_mday = ATOI2(str)) > 31) - return(-1); - str += 2; + lt->tm_mday = ATOI2(p); /* FALLTHROUGH */ case 4: - /* - * hour (hh) - */ - if ((lt->tm_hour = ATOI2(str)) > 23) - return(-1); - str += 2; + lt->tm_hour = ATOI2(p); /* FALLTHROUGH */ case 2: - /* - * minute (mm) - */ - if ((lt->tm_min = ATOI2(str)) > 59) - return(-1); + lt->tm_min = ATOI2(p); break; default: - return(-1); + return -1; } + /* * convert broken-down time to GMT clock time seconds */ if ((*tval = mktime(lt)) == -1) - return(-1); - return(0); + return -1; + return 0; } diff --git a/commands/pax/sel_subs.h b/bin/pax/sel_subs.h similarity index 93% rename from commands/pax/sel_subs.h rename to bin/pax/sel_subs.h index 32c07b7df..c91f3eaec 100644 --- a/commands/pax/sel_subs.h +++ b/bin/pax/sel_subs.h @@ -1,3 +1,5 @@ +/* $NetBSD: sel_subs.h,v 1.6 2003/10/13 07:41:22 agc Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,7 +33,6 @@ * SUCH DAMAGE. * * @(#)sel_subs.h 8.1 (Berkeley) 5/31/93 - * $FreeBSD: src/bin/pax/sel_subs.h,v 1.6 2004/04/06 20:06:48 markm Exp $ */ /* @@ -55,8 +56,6 @@ typedef struct grpt { * data structure for storing user supplied time ranges (-T option) */ -#define ATOI2(s) ((((s)[0] - '0') * 10) + ((s)[1] - '0')) - typedef struct time_rng { time_t low_time; /* lower inclusive time limit */ time_t high_time; /* higher inclusive time limit */ diff --git a/commands/pax/tables.c b/bin/pax/tables.c similarity index 84% rename from commands/pax/tables.c rename to bin/pax/tables.c index 41db2934a..7325bf762 100644 --- a/commands/pax/tables.c +++ b/bin/pax/tables.c @@ -1,3 +1,5 @@ +/* $NetBSD: tables.c,v 1.30 2008/01/10 04:24:51 tls Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,21 +33,31 @@ * SUCH DAMAGE. */ -#ifndef lint +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) #if 0 static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: tables.c,v 1.30 2008/01/10 04:24:51 tls Exp $"); #endif #endif /* not lint */ #include #include #include -#include -#include +#include #include -#include +#include +#include +#include #include #include +#include +#include #include "pax.h" #include "tables.h" #include "extern.h" @@ -61,7 +73,7 @@ static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 5/31/93"; * large archives. These database routines carefully combine memory usage and * temporary file storage in ways which will not significantly impact runtime * performance while allowing the largest possible archives to be handled. - * Trying to force the fit to the POSIX databases routines was not considered + * Trying to force the fit to the POSIX database routines was not considered * time well spent. */ @@ -70,8 +82,10 @@ static FTM **ftab = NULL; /* file time table for updating arch */ static NAMT **ntab = NULL; /* interactive rename storage table */ static DEVT **dtab = NULL; /* device/inode mapping tables */ static ATDIR **atab = NULL; /* file tree directory time reset table */ +#ifdef DIRS_USE_FILE static int dirfd = -1; /* storage for setting created dir time/mode */ static u_long dircnt; /* entries in dir time/mode storage */ +#endif static int ffd = -1; /* tmp file for file time table name storage */ static DEVT *chk_dev(dev_t, int); @@ -103,12 +117,12 @@ int lnk_start(void) { if (ltab != NULL) - return(0); - if ((ltab = (HRDLNK **)calloc(L_TAB_SZ, sizeof(HRDLNK *))) == NULL) { - paxwarn(1, "Cannot allocate memory for hard link table"); - return(-1); + return 0; + if ((ltab = (HRDLNK **)calloc(L_TAB_SZ, sizeof(HRDLNK *))) == NULL) { + tty_warn(1, "Cannot allocate memory for hard link table"); + return -1; } - return(0); + return 0; } /* @@ -131,12 +145,12 @@ chk_lnk(ARCHD *arcn) u_int indx; if (ltab == NULL) - return(-1); + return -1; /* * ignore those nodes that cannot have hard links */ if ((arcn->type == PAX_DIR) || (arcn->sb.st_nlink <= 1)) - return(0); + return 0; /* * hash inode number and look for this file @@ -144,7 +158,7 @@ chk_lnk(ARCHD *arcn) indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ; if ((pt = ltab[indx]) != NULL) { /* - * it's hash chain in not empty, walk down looking for it + * its hash chain is not empty, walk down looking for it */ ppt = &(ltab[indx]); while (pt != NULL) { @@ -162,9 +176,8 @@ chk_lnk(ARCHD *arcn) * handle hardlinks to regular files differently than * other links. */ - arcn->ln_nlen = l_strncpy(arcn->ln_name, pt->name, - sizeof(arcn->ln_name) - 1); - arcn->ln_name[arcn->ln_nlen] = '\0'; + arcn->ln_nlen = strlcpy(arcn->ln_name, pt->name, + sizeof(arcn->ln_name)); if (arcn->type == PAX_REG) arcn->type = PAX_HRG; else @@ -179,7 +192,7 @@ chk_lnk(ARCHD *arcn) (void)free((char *)pt->name); (void)free((char *)pt); } - return(1); + return 1; } } @@ -194,20 +207,20 @@ chk_lnk(ARCHD *arcn) pt->nlink = arcn->sb.st_nlink; pt->fow = ltab[indx]; ltab[indx] = pt; - return(0); + return 0; } (void)free((char *)pt); } - paxwarn(1, "Hard link table out of memory"); - return(-1); + tty_warn(1, "Hard link table out of memory"); + return -1; } /* * purg_lnk * remove reference for a file that we may have added to the data base as * a potential source for hard links. We ended up not using the file, so - * we do not want to accidently point another file at it later on. + * we do not want to accidentally point another file at it later on. */ void @@ -258,10 +271,10 @@ purg_lnk(ARCHD *arcn) /* * lnk_end() - * Pull apart an existing link table so we can reuse it. We do this between + * pull apart a existing link table so we can reuse it. We do this between * read and write phases of append with update. (The format may have * used the link table, and we need to start with a fresh table for the - * write phase). + * write phase */ void @@ -304,14 +317,14 @@ lnk_end(void) * An append with an -u must read the archive and store the modification time * for every file on that archive before starting the write phase. It is clear * that this is one HUGE database. To save memory space, the actual file names - * are stored in a scatch file and indexed by an in memory hash table. The + * are stored in a scratch file and indexed by an in-memory hash table. The * hash table is indexed by hashing the file path. The nodes in the table store * the length of the filename and the lseek offset within the scratch file - * where the actual name is stored. Since there are never any deletions to this - * table, fragmentation of the scratch file is never an issue. Lookups seem to + * where the actual name is stored. Since there are never any deletions from this + * table, fragmentation of the scratch file is never a issue. Lookups seem to * not exhibit any locality at all (files in the database are rarely - * looked up more than once...). So caching is just a waste of memory. The - * only limitation is the amount of scatch file space available to store the + * looked up more than once...), so caching is just a waste of memory. The + * only limitation is the amount of scratch file space available to store the * path names. */ @@ -327,12 +340,11 @@ lnk_end(void) int ftime_start(void) { - if (ftab != NULL) - return(0); - if ((ftab = (FTM **)calloc(F_TAB_SZ, sizeof(FTM *))) == NULL) { - paxwarn(1, "Cannot allocate memory for file time table"); - return(-1); + return 0; + if ((ftab = (FTM **)calloc(F_TAB_SZ, sizeof(FTM *))) == NULL) { + tty_warn(1, "Cannot allocate memory for file time table"); + return -1; } /* @@ -340,14 +352,14 @@ ftime_start(void) * so it will get removed on exit */ memcpy(tempbase, _TFILE_BASE, sizeof(_TFILE_BASE)); - if ((ffd = mkstemp(tempfile)) < 0) { + if ((ffd = mkstemp(tempfile)) == -1) { syswarn(1, errno, "Unable to create temporary file: %s", tempfile); - return(-1); + return -1; } - (void)unlink(tempfile); - return(0); + (void)unlink(tempfile); + return 0; } /* @@ -374,7 +386,7 @@ chk_ftime(ARCHD *arcn) * no info, go ahead and add to archive */ if (ftab == NULL) - return(0); + return 0; /* * hash the pathname and look up in table @@ -396,12 +408,12 @@ chk_ftime(ARCHD *arcn) if (lseek(ffd,pt->seek,SEEK_SET) != pt->seek) { syswarn(1, errno, "Failed ftime table seek"); - return(-1); + return -1; } - if (read(ffd, ckname, namelen) != namelen) { + if (xread(ffd, ckname, namelen) != namelen) { syswarn(1, errno, "Failed ftime table read"); - return(-1); + return -1; } /* @@ -426,12 +438,12 @@ chk_ftime(ARCHD *arcn) * file is newer */ pt->mtime = arcn->sb.st_mtime; - return(0); + return 0; } /* * file is older */ - return(1); + return 1; } } @@ -444,22 +456,22 @@ chk_ftime(ARCHD *arcn) * offset. add the file to the head of the hash chain */ if ((pt->seek = lseek(ffd, (off_t)0, SEEK_END)) >= 0) { - if (write(ffd, arcn->name, namelen) == namelen) { + if (xwrite(ffd, arcn->name, namelen) == namelen) { pt->mtime = arcn->sb.st_mtime; pt->namelen = namelen; pt->fow = ftab[indx]; ftab[indx] = pt; - return(0); + return 0; } syswarn(1, errno, "Failed write to file time table"); } else syswarn(1, errno, "Failed seek on file time table"); } else - paxwarn(1, "File time table ran out of memory"); + tty_warn(1, "File time table ran out of memory"); if (pt != NULL) (void)free((char *)pt); - return(-1); + return -1; } /* @@ -485,12 +497,13 @@ int name_start(void) { if (ntab != NULL) - return(0); - if ((ntab = (NAMT **)calloc(N_TAB_SZ, sizeof(NAMT *))) == NULL) { - paxwarn(1, "Cannot allocate memory for interactive rename table"); - return(-1); + return 0; + if ((ntab = (NAMT **)calloc(N_TAB_SZ, sizeof(NAMT *))) == NULL) { + tty_warn(1, + "Cannot allocate memory for interactive rename table"); + return -1; } - return(0); + return 0; } /* @@ -512,8 +525,8 @@ add_name(char *oname, int onamelen, char *nname) /* * should never happen */ - paxwarn(0, "No interactive rename table, links may fail\n"); - return(0); + tty_warn(0, "No interactive rename table, links may fail\n"); + return 0; } /* @@ -534,14 +547,14 @@ add_name(char *oname, int onamelen, char *nname) * the user just input (if it is different) */ if (strcmp(nname, pt->nname) == 0) - return(0); + return 0; (void)free((char *)pt->nname); if ((pt->nname = strdup(nname)) == NULL) { - paxwarn(1, "Cannot update rename table"); - return(-1); + tty_warn(1, "Cannot update rename table"); + return -1; } - return(0); + return 0; } } @@ -553,14 +566,14 @@ add_name(char *oname, int onamelen, char *nname) if ((pt->nname = strdup(nname)) != NULL) { pt->fow = ntab[indx]; ntab[indx] = pt; - return(0); + return 0; } (void)free((char *)pt->oname); } (void)free((char *)pt); } - paxwarn(1, "Interactive rename table out of memory"); - return(-1); + tty_warn(1, "Interactive rename table out of memory"); + return -1; } /* @@ -594,8 +607,7 @@ sub_name(char *oname, int *onamelen, size_t onamesize) * found it, replace it with the new name * and return (we know that oname has enough space) */ - *onamelen = l_strncpy(oname, pt->nname, onamesize - 1); - oname[*onamelen] = '\0'; + *onamelen = strlcpy(oname, pt->nname, onamesize); return; } pt = pt->fow; @@ -658,12 +670,12 @@ int dev_start(void) { if (dtab != NULL) - return(0); - if ((dtab = (DEVT **)calloc(D_TAB_SZ, sizeof(DEVT *))) == NULL) { - paxwarn(1, "Cannot allocate memory for device mapping table"); - return(-1); + return 0; + if ((dtab = (DEVT **)calloc(D_TAB_SZ, sizeof(DEVT *))) == NULL) { + tty_warn(1, "Cannot allocate memory for device mapping table"); + return -1; } - return(0); + return 0; } /* @@ -680,8 +692,8 @@ int add_dev(ARCHD *arcn) { if (chk_dev(arcn->sb.st_dev, 1) == NULL) - return(-1); - return(0); + return -1; + return 0; } /* @@ -704,7 +716,7 @@ chk_dev(dev_t dev, int add) u_int indx; if (dtab == NULL) - return(NULL); + return NULL; /* * look to see if this device is already in the table */ @@ -717,7 +729,7 @@ chk_dev(dev_t dev, int add) * found it, return a pointer to it */ if (pt != NULL) - return(pt); + return pt; } /* @@ -725,7 +737,7 @@ chk_dev(dev_t dev, int add) * to see if a device number is being used. */ if (add == 0) - return(NULL); + return NULL; /* * allocate a node for this device and add it to the front of the hash @@ -733,14 +745,14 @@ chk_dev(dev_t dev, int add) * list must be NULL. */ if ((pt = (DEVT *)malloc(sizeof(DEVT))) == NULL) { - paxwarn(1, "Device map table out of memory"); - return(NULL); + tty_warn(1, "Device map table out of memory"); + return NULL; } pt->dev = dev; pt->list = NULL; pt->fow = dtab[indx]; dtab[indx] = pt; - return(pt); + return pt; } /* * map_dev() @@ -767,7 +779,7 @@ map_dev(ARCHD *arcn, u_long dev_mask, u_long ino_mask) ino_t nino; if (dtab == NULL) - return(0); + return 0; /* * check for device and inode truncation, and extract the truncated * bit pattern. @@ -798,7 +810,7 @@ map_dev(ARCHD *arcn, u_long dev_mask, u_long ino_mask) */ arcn->sb.st_dev = dpt->dev; arcn->sb.st_ino = nino; - return(0); + return 0; } } else { /* @@ -806,7 +818,7 @@ map_dev(ARCHD *arcn, u_long dev_mask, u_long ino_mask) * form of truncation, we do not need a remap */ if (!trc_ino && !trc_dev) - return(0); + return 0; /* * we have truncation, have to add this as a device to remap @@ -864,20 +876,21 @@ map_dev(ARCHD *arcn, u_long dev_mask, u_long ino_mask) pt->list = dpt; arcn->sb.st_dev = lastdev; arcn->sb.st_ino = nino; - return(0); + return 0; bad: - paxwarn(1, "Unable to fix truncated inode/device field when storing %s", + tty_warn(1, + "Unable to fix truncated inode/device field when storing %s", arcn->name); - paxwarn(0, "Archive may create improper hard links when extracted"); - return(0); + tty_warn(0, "Archive may create improper hard links when extracted"); + return 0; } /* * directory access/mod time reset table routines (for directories READ by pax) * * The pax -t flag requires that access times of archive files to be the same - * before being read by pax. For regular files, access time is restored after + * as before being read by pax. For regular files, access time is restored after * the file has been copied. This database provides the same functionality for * directories read during file tree traversal. Restoring directory access time * is more complex than files since directories may be read several times until @@ -901,12 +914,13 @@ int atdir_start(void) { if (atab != NULL) - return(0); - if ((atab = (ATDIR **)calloc(A_TAB_SZ, sizeof(ATDIR *))) == NULL) { - paxwarn(1,"Cannot allocate space for directory access time table"); - return(-1); + return 0; + if ((atab = (ATDIR **)calloc(A_TAB_SZ, sizeof(ATDIR *))) == NULL) { + tty_warn(1, + "Cannot allocate space for directory access time table"); + return -1; } - return(0); + return 0; } @@ -938,7 +952,7 @@ atdir_end(void) * not read by pax. Read time reset is controlled by -t. */ for (; pt != NULL; pt = pt->fow) - set_ftime(pt->name, pt->mtime, pt->atime, 1); + set_ftime(pt->name, pt->mtime, pt->atime, 1, 0); } } @@ -962,7 +976,7 @@ add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime) * return (the older entry always has the correct time). The only * way this will happen is when the same subtree can be traversed by * different args to pax and the -n option is aborting fts out of a - * subtree before all the post-order visits have been made). + * subtree before all the post-order visits have been made. */ indx = ((unsigned)ino) % A_TAB_SZ; if ((pt = atab[indx]) != NULL) { @@ -995,7 +1009,7 @@ add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime) (void)free((char *)pt); } - paxwarn(1, "Directory access time reset table ran out of memory"); + tty_warn(1, "Directory access time reset table ran out of memory"); return; } @@ -1018,13 +1032,13 @@ get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) u_int indx; if (atab == NULL) - return(-1); + return -1; /* * hash by inode and search the chain for an inode and device match */ indx = ((unsigned)ino) % A_TAB_SZ; if ((pt = atab[indx]) == NULL) - return(-1); + return -1; ppt = &(atab[indx]); while (pt != NULL) { @@ -1041,7 +1055,7 @@ get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) * return if we did not find it. */ if (pt == NULL) - return(-1); + return -1; /* * found it. return the times and remove the entry from the table. @@ -1051,7 +1065,7 @@ get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) *atime = pt->atime; (void)free((char *)pt->name); (void)free((char *)pt); - return(0); + return 0; } /* @@ -1077,6 +1091,10 @@ get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) * then the file name. */ +#ifndef DIRS_USE_FILE +static DIRDATA *dirdata_head; +#endif + /* * dir_start() * set up the directory time and file mode storage for directories CREATED @@ -1088,9 +1106,9 @@ get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) int dir_start(void) { - +#ifdef DIRS_USE_FILE if (dirfd != -1) - return(0); + return 0; /* * unlink the file so it goes away at termination by itself @@ -1098,11 +1116,14 @@ dir_start(void) memcpy(tempbase, _TFILE_BASE, sizeof(_TFILE_BASE)); if ((dirfd = mkstemp(tempfile)) >= 0) { (void)unlink(tempfile); - return(0); + return 0; } - paxwarn(1, "Unable to create temporary file for directory times: %s", + tty_warn(1, "Unable to create temporary file for directory times: %s", tempfile); - return(-1); + return -1; +#else + return (0); +#endif /* DIRS_USE_FILE */ } /* @@ -1112,7 +1133,7 @@ dir_start(void) * frc_mode is a flag that says whether to force the setting of the mode * (ignoring the user set values for preserving file mode). Frc_mode is * for the case where we created a file and found that the resulting - * directory was not writeable and the user asked for file modes to NOT + * directory was not writable and the user asked for file modes to NOT * be preserved. (we have to preserve what was created by default, so we * have to force the setting at the end. this is stated explicitly in the * pax spec) @@ -1121,8 +1142,23 @@ dir_start(void) void add_dir(char *name, int nlen, struct stat *psb, int frc_mode) { +#ifdef DIRS_USE_FILE DIRDATA dblk; +#else + DIRDATA *dblk; +#endif + char realname[MAXPATHLEN], *rp; + if (havechd && *name != '/') { + if ((rp = realpath(name, realname)) == NULL) { + tty_warn(1, "Cannot canonicalize %s", name); + return; + } + name = rp; + nlen = strlen(name); + } + +#ifdef DIRS_USE_FILE if (dirfd < 0) return; @@ -1131,7 +1167,8 @@ add_dir(char *name, int nlen, struct stat *psb, int frc_mode) * in the trailer */ if ((dblk.npos = lseek(dirfd, 0L, SEEK_CUR)) < 0) { - paxwarn(1,"Unable to store mode and times for directory: %s",name); + tty_warn(1, + "Unable to store mode and times for directory: %s",name); return; } @@ -1142,15 +1179,46 @@ add_dir(char *name, int nlen, struct stat *psb, int frc_mode) dblk.mode = psb->st_mode & 0xffff; dblk.mtime = psb->st_mtime; dblk.atime = psb->st_atime; +#if HAVE_STRUCT_STAT_ST_FLAGS + dblk.fflags = psb->st_flags; +#else + dblk.fflags = 0; +#endif dblk.frc_mode = frc_mode; - if ((write(dirfd, name, dblk.nlen) == dblk.nlen) && - (write(dirfd, (char *)&dblk, sizeof(dblk)) == sizeof(dblk))) { + if ((xwrite(dirfd, name, dblk.nlen) == dblk.nlen) && + (xwrite(dirfd, (char *)&dblk, sizeof(dblk)) == sizeof(dblk))) { ++dircnt; return; } - paxwarn(1,"Unable to store mode and times for created directory: %s",name); + tty_warn(1, + "Unable to store mode and times for created directory: %s",name); + return; +#else + + if ((dblk = malloc(sizeof(*dblk))) == NULL || + (dblk->name = strdup(name)) == NULL) { + tty_warn(1, + "Unable to store mode and times for directory: %s",name); + if (dblk != NULL) + free(dblk); + return; + } + + dblk->mode = psb->st_mode & 0xffff; + dblk->mtime = psb->st_mtime; + dblk->atime = psb->st_atime; +#if HAVE_STRUCT_STAT_ST_FLAGS + dblk->fflags = psb->st_flags; +#else + dblk->fflags = 0; +#endif + dblk->frc_mode = frc_mode; + + dblk->next = dirdata_head; + dirdata_head = dblk; return; +#endif /* DIRS_USE_FILE */ } /* @@ -1162,6 +1230,7 @@ add_dir(char *name, int nlen, struct stat *psb, int frc_mode) void proc_dir(void) { +#ifdef DIRS_USE_FILE char name[PAXPATHLEN+1]; DIRDATA dblk; u_long cnt; @@ -1178,11 +1247,11 @@ proc_dir(void) */ if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0) break; - if (read(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk)) + if (xread(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk)) break; if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) break; - if (read(dirfd, name, dblk.nlen) != dblk.nlen) + if (xread(dirfd, name, dblk.nlen) != dblk.nlen) break; if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) break; @@ -1194,14 +1263,38 @@ proc_dir(void) if (pmode || dblk.frc_mode) set_pmode(name, dblk.mode); if (patime || pmtime) - set_ftime(name, dblk.mtime, dblk.atime, 0); + set_ftime(name, dblk.mtime, dblk.atime, 0, 0); + if (pfflags) + set_chflags(name, dblk.fflags); } (void)close(dirfd); dirfd = -1; if (cnt != dircnt) - paxwarn(1,"Unable to set mode and times for created directories"); + tty_warn(1, + "Unable to set mode and times for created directories"); return; +#else + DIRDATA *dblk; + + for (dblk = dirdata_head; dblk != NULL; dblk = dirdata_head) { + dirdata_head = dblk->next; + + /* + * frc_mode set, make sure we set the file modes even if + * the user didn't ask for it (see file_subs.c for more info) + */ + if (pmode || dblk->frc_mode) + set_pmode(dblk->name, dblk->mode); + if (patime || pmtime) + set_ftime(dblk->name, dblk->mtime, dblk->atime, 0, 0); + if (pfflags) + set_chflags(dblk->name, dblk->fflags); + + free(dblk->name); + free(dblk); + } +#endif /* DIRS_USE_FILE */ } /* @@ -1280,5 +1373,5 @@ st_hash(char *name, int len, int tabsz) /* * return the result mod the table size */ - return(key % tabsz); + return key % tabsz; } diff --git a/commands/pax/tables.h b/bin/pax/tables.h similarity index 96% rename from commands/pax/tables.h rename to bin/pax/tables.h index 9d0c5d8d7..1038589f3 100644 --- a/commands/pax/tables.h +++ b/bin/pax/tables.h @@ -1,3 +1,5 @@ +/* $NetBSD: tables.h,v 1.10 2007/04/29 20:23:34 msaitoh Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,7 +33,6 @@ * SUCH DAMAGE. * * @(#)tables.h 8.1 (Berkeley) 5/31/93 - * $FreeBSD: src/bin/pax/tables.h,v 1.10 2004/04/06 20:06:48 markm Exp $ */ /* @@ -132,7 +133,7 @@ typedef struct dlist { } DLIST; /* - * ftree directory access time reset table. When we are done with with a + * ftree directory access time reset table. When we are done with a * subtree we reset the access and mod time of the directory when the tflag is * set. Not really explicitly specified in the pax spec, but easy and fast to * do (and this may have even been intended in the spec, it is not clear). @@ -160,10 +161,16 @@ typedef struct atdir { */ typedef struct dirdata { +#ifdef DIRS_USE_FILE int nlen; /* length of the directory name (includes \0) */ off_t npos; /* position in file where this dir name starts */ +#else + char *name; /* file name */ + struct dirdata *next; +#endif mode_t mode; /* file mode to restore */ time_t mtime; /* mtime to set */ time_t atime; /* atime to set */ + long fflags; /* file flags to set */ int frc_mode; /* do we force mode settings? */ } DIRDATA; diff --git a/commands/pax/tar.1 b/bin/pax/tar.1 similarity index 56% rename from commands/pax/tar.1 rename to bin/pax/tar.1 index ff66ccbef..02363f7dc 100644 --- a/commands/pax/tar.1 +++ b/bin/pax/tar.1 @@ -1,4 +1,5 @@ -.\"- +.\" $NetBSD: tar.1,v 1.33 2012/03/22 07:58:17 wiz Exp $ +.\" .\" Copyright (c) 1996 SigmaSoft, Th. Lockert .\" All rights reserved. .\" @@ -10,11 +11,6 @@ .\" 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 @@ -27,58 +23,53 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: tar.1,v 1.33 2001/05/01 17:58:01 aaron Exp $ -.\" $FreeBSD$ +.\" OpenBSD: tar.1,v 1.28 2000/11/09 23:58:56 aaron Exp .\" -.Dd February 7, 2001 +.Dd June 18, 2011 .Dt TAR 1 .Os .Sh NAME .Nm tar .Nd tape archiver .Sh SYNOPSIS -.Nm +.Nm tar .Sm off -.Op Fl -.Brq Cm crtux -.Op Cm befhjmopqsvwyzHLOPXZ014578 +.Oo \&- Oc {crtux} Op Fl 014578befHhjklmOoPpqSvwXZz .Sm on -.Op Ar blocksize .Op Ar archive -.Op Ar replstr +.Op Ar blocksize .\" XXX how to do this right? .Op Fl C Ar directory -.Op Fl I Ar file -.Op Ar +.Op Fl s Ar replstr +.Op Fl T Ar file +.Op Ar file ... .Sh DESCRIPTION The .Nm command creates, adds files to, or extracts files from an archive file in -.Nm +.Dq tar format. -A -.Nm -archive is often stored on a magnetic tape, but can be +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 indent -.It Fl c +.Bl -tag -width Ar +.It Fl c , Fl Fl create Create new archive, or overwrite an existing archive, adding the specified files to it. -.It Fl r +.It Fl r , Fl Fl append 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 +.It Fl t , Fl Fl list List contents of archive. If any files are named on the command line, only those files will be listed. -.It Fl u +.It Fl u , Fl Fl update Alias for .Fl r . -.It Fl x +.It Fl x , Fl Fl extract , Fl Fl get Extract files from archive. If any files are named on the command line, only those files will be extracted from the @@ -94,39 +85,51 @@ The file mode is subject to modification by the .Pp In addition to the flags mentioned above, any of the following flags may be used: -.Bl -tag -width indent -.It Fl b Ar "blocking factor" -Set blocking factor to use for the archive, with 512 byte blocks. +.Bl -tag -width Ar +.It Fl b Ar "blocking factor" , Fl Fl block-size 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 +.It Fl f Ar archive , Fl Fl file Ar archive Filename where the archive is stored. Defaults to -.Pa /dev/sa0 . -.It Fl h +.Pa /dev/rst0 . +If the archive is of the form: +.Ar [[user@]host:]file +then the archive will be processed using +.Xr rmt 8 . +.It Fl h , Fl Fl dereference Follow symbolic links as if they were normal files or directories. -.It Fl j -Compress archives using -.Xr bzip2 1 . -.It Fl m +.It Fl j, Fl Fl bzip2, Fl Fl bunzip2 +Use +.Xr bzip2 1 +for compression of the archive. +This option is a GNU extension. +.It Fl k , Fl Fl keep-old-files +Keep existing files; don't overwrite them from archive. +.It Fl l , Fl Fl one-file-system +Do not descend across mount points. +.\" should be '-X' +.It Fl m , Fl Fl modification-time Do not preserve modification time. .It Fl O -Write old-style -.Pq non- Ns Tn POSIX -archives. -.It Fl o -Do not write directory information that the older (V7) style +When creating and appending to an archive, write old-style (non-POSIX) archives. +When extracting from an archive, extract to standard output. +.It Fl o , Fl Fl portability , Fl Fl old-archive +Don't write directory information that the older (V7) style .Nm is unable to decode. This implies the .Fl O flag. -.It Fl p +.It Fl p , Fl Fl preserve-permissions , Fl Fl preserve Preserve user and group ID as well as file mode regardless of the current .Xr umask 2 . @@ -135,7 +138,7 @@ the superuser. Only meaningful in conjunction with the .Fl x flag. -.It Fl q +.It Fl q , Fl Fl fast-read Select the first archive member that matches each .Ar pattern operand. @@ -143,6 +146,10 @@ 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 , Fl Fl sparse +This flag has no effect as +.Nm +always generates sparse files. .It Fl s Ar replstr Modify the file or archive member names specified by the .Ar pattern @@ -154,25 +161,20 @@ using the syntax of the .Xr ed 1 utility regular expressions. The format of these regular expressions are: -.Dl /old/new/[gp] +.Dl /old/new/[gps] As in .Xr ed 1 , .Cm old is a basic regular expression and .Cm new -can contain an ampersand -.Pq Ql & , -.Li \e Ns Ar n -(where -.Ar n -is a digit) back-references, +can contain an ampersand (\*[Am]), \en (where n is a digit) back-references, or subexpression matching. The .Cm old -string may also contain newline characters. -Any non-null character can be used as a delimiter -.Ql ( / -is shown here). +string may also contain +.Aq Dv newline +characters. +Any non-null character can be used as a delimiter (/ is shown here). Multiple .Fl s expressions can be specified. @@ -189,73 +191,126 @@ option. The optional trailing .Cm p will cause the final result of a successful substitution to be written to -standard error +.Dv standard error in the following format: -.Pp -.Dl >> -.Pp +.Dl \*[Lt]original pathname\*[Gt] \*[Gt]\*[Gt] \*[Lt]new pathname\*[Gt] File or archive member names that substitute to the empty string are not selected and will be skipped. +The substitutions are applied by default to the destination hard and symbolic +links. +The optional trailing +.Cm s +prevents the substitutions from being performed on symbolic link destinations. .It Fl v Verbose operation mode. -.It Fl w +.It Fl w , Fl Fl interactive , Fl Fl confirmation 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 -.Xr bzip2 1 . -.It Fl z -Compress archive using +.It Fl Fl xz +Compress/decompress archive using +.Xr xz 1 . +.It Fl z , Fl Fl gzip , Fl Fl gunzip +Compress/decompress archive using .Xr gzip 1 . -.It Fl C Ar directory +.It Fl B , Fl Fl read-full-blocks +Reassemble small reads into full blocks (For reading from 4.2BSD pipes). +.It Fl C Ar directory , Fl Fl directory 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. +This argument and its parameter may also appear in a file list specified by +.Fl T . .It Fl H -Follow symlinks given on command line only. -.It Fl L -Follow all symlinks. -.It Fl P +Only follow symlinks given on command line. +.Pp +Note SysVr3/i386 picked up ISC/SCO UNIX compatibility which implemented +.Dq Fl F Ar file +which was defined as obtaining a list of command line switches and files +on which to operate from the specified file, +but SunOS-5 uses +.Dq Fl I Ar file +because they use +.Sq Fl F +to mean something else. +We might someday provide SunOS-5 compatibility +but it makes little sense to confuse things with ISC/SCO compatibility. +.\".It Fl L +.\"Do not follow any symlinks (do the opposite of +.\".Fl h ). +.It Fl P , Fl Fl absolute-paths Do not strip leading slashes -.Pq Ql / +.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 -.Xr compress 1 . +.It Fl T Ar file , Fl Fl files-from Ar file +Read the names of files to archive or extract from the given file, one +per line. +A line may also specify the positional argument +.Dq Fl C Ar directory . +.It Fl X Ar file , Fl Fl exclude-from Ar file +Exclude files matching the shell glob patterns listed in the given file. +.\" exclude should be '-E' and '-X' should be one-file-system +.Pp +Note that it would be more standard to use this option to mean ``do not +cross filesystem mount points.'' +.It Fl Z , Fl Fl compress , Fl Fl uncompress +Compress archive using compress. +.It Fl Fl strict +Do not enable GNU tar extensions such as long filenames and long link names. +.It Fl Fl atime-preserve +Preserve file access times. +.It Fl Fl chroot +.Fn chroot +to the current directory before extracting files. +Use with +.Fl x +and +.Fl h +to make absolute symlinks relative to the current directory. +.It Fl Fl unlink +Ignored, only accepted for compatibility with other +.Nm +implementations. +.Nm +always unlinks files before creating them. +.It Fl Fl use-compress-program Ar program +Use the named program as the program to decompress the input. +.It Fl Fl force-local +Do not interpret filenames that contain a +.Sq \&: +as remote files. +.It Fl Fl insecure +Normally +.Nm +ignores filenames that contain +.Dq .. +as a path component. +With this option, files that contain +.Dq .. +can be processed. +.It Fl Fl no-recursion +Cause files of type directory being copied or archived, or archive members of +type directory being extracted, to match only the directory file or archive +member and not the file hierarchy rooted at the directory. .El .Pp The options .Op Fl 014578 can be used to select one of the compiled-in backup devices, -.Pa /dev/rst Ns Ar N . -.Sh ENVIRONMENT -.Bl -tag -width TMPDIR -.It Ev TMPDIR -Path in which to store temporary files. -.It Ev TAPE -Default tape device to use instead of -.Pa /dev/sa0 . -.El +.Pa /dev/rstN . .Sh FILES -.Bl -tag -width "/dev/sa0" -.It Pa /dev/sa0 +.Bl -tag -width "/dev/rst0" +.It Pa /dev/rst0 default archive name .El -.Sh EXIT STATUS -The +.Sh DIAGNOSTICS .Nm -utility will exit with one of the following values: +will exit with one of the following values: .Bl -tag -width 2n .It 0 All files were processed successfully. @@ -291,12 +346,6 @@ or error, .Nm may have only partially created the archive which may violate the specific archive format specification. -.Sh COMPATIBILITY -The -.Fl L -flag is not portable to other versions of -.Nm -where it may have a different meaning. .Sh SEE ALSO .Xr cpio 1 , .Xr pax 1 @@ -306,5 +355,4 @@ A command first appeared in .At v7 . .Sh AUTHORS -.An Keith Muller -at the University of California, San Diego. +Keith Muller at the University of California, San Diego. diff --git a/commands/pax/tar.c b/bin/pax/tar.c similarity index 54% rename from commands/pax/tar.c rename to bin/pax/tar.c index 3ec4e6649..483349fa6 100644 --- a/commands/pax/tar.c +++ b/bin/pax/tar.c @@ -1,3 +1,5 @@ +/* $NetBSD: tar.c,v 1.70 2012/08/09 08:09:22 christos Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,19 +33,33 @@ * SUCH DAMAGE. */ -#ifndef lint +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) #if 0 static char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94"; +#else +__RCSID("$NetBSD: tar.c,v 1.70 2012/08/09 08:09:22 christos Exp $"); #endif #endif /* not lint */ #include #include #include -#include +#include + +#include +#include +#include +#include #include -#include #include +#include +#include + #include "pax.h" #include "extern.h" #include "tar.h" @@ -52,18 +68,61 @@ static char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94"; * Routines for reading, writing and header identify of various versions of tar */ -static u_long tar_chksm(char *, int); +static int expandname(char *, size_t, char **, size_t *, const char *, size_t); +static void longlink(ARCHD *, int); +static uint32_t tar_chksm(char *, int); static char *name_split(char *, int); -static int ul_oct(u_long, char *, int, int); -#ifndef NET2_STAT -static int uqd_oct(u_quad_t, char *, int, int); -#endif +static int u32_oct(uintmax_t, char *, int, int); +static int umax_oct(uintmax_t, char *, int, int); +static int tar_gnutar_exclude_one(const char *, size_t); +static int check_sum(char *, size_t, char *, size_t, int); /* * Routines common to all versions of tar */ static int tar_nodir; /* do not write dirs under old tar */ +int is_gnutar; /* behave like gnu tar; enable gnu + * extensions and skip end-of-volume + * checks + */ +static int seen_gnu_warning; /* Have we warned yet? */ +static char *gnu_hack_string; /* ././@LongLink hackery */ +static int gnu_hack_len; /* len of gnu_hack_string */ +char *gnu_name_string; /* ././@LongLink hackery name */ +char *gnu_link_string; /* ././@LongLink hackery link */ +size_t gnu_name_length; /* ././@LongLink hackery name */ +size_t gnu_link_length; /* ././@LongLink hackery link */ +static int gnu_short_trailer; /* gnu short trailer */ + +static const char LONG_LINK[] = "././@LongLink"; + +#ifdef _PAX_ +char DEV_0[] = "/dev/rst0"; +char DEV_1[] = "/dev/rst1"; +char DEV_4[] = "/dev/rst4"; +char DEV_5[] = "/dev/rst5"; +char DEV_7[] = "/dev/rst7"; +char DEV_8[] = "/dev/rst8"; +#endif + +static int +check_sum(char *hd, size_t hdlen, char *bl, size_t bllen, int quiet) +{ + uint32_t hdck, blck; + + hdck = asc_u32(hd, hdlen, OCT); + blck = tar_chksm(bl, bllen); + + if (hdck != blck) { + if (!quiet) + tty_warn(0, "Header checksum %o does not match %o", + hdck, blck); + return -1; + } + return 0; +} + /* * tar_endwr() @@ -75,20 +134,20 @@ static int tar_nodir; /* do not write dirs under old tar */ int tar_endwr(void) { - return(wr_skip((off_t)(NULLCNT*BLKMULT))); + return wr_skip((off_t)(NULLCNT * BLKMULT)); } /* * tar_endrd() * no cleanup needed here, just return size of trailer (for append) * Return: - * size of trailer (2 * BLKMULT) + * size of trailer BLKMULT */ off_t tar_endrd(void) { - return((off_t)(NULLCNT*BLKMULT)); + return (off_t)((gnu_short_trailer ? 1 : NULLCNT) * BLKMULT); } /* @@ -107,6 +166,7 @@ tar_trail(char *buf, int in_resync, int *cnt) { int i; + gnu_short_trailer = 0; /* * look for all zero, trailer is two consecutive blocks of zero */ @@ -119,7 +179,7 @@ tar_trail(char *buf, int in_resync, int *cnt) * if not all zero it is not a trailer, but MIGHT be a header. */ if (i != BLKMULT) - return(-1); + return -1; /* * When given a zero block, we must be careful! @@ -129,14 +189,25 @@ tar_trail(char *buf, int in_resync, int *cnt) * might as well throw this block out since a valid header can NEVER be * a block of all 0 (we must have a valid file name). */ - if (!in_resync && (++*cnt >= NULLCNT)) - return(0); - return(1); + if (!in_resync) { + ++*cnt; + /* + * old GNU tar (up through 1.13) only writes one block of + * trailers, so we pretend we got another + */ + if (is_gnutar) { + gnu_short_trailer = 1; + ++*cnt; + } + if (*cnt >= NULLCNT) + return 0; + } + return 1; } /* - * ul_oct() - * convert an unsigned long to an octal string. many oddball field + * u32_oct() + * convert an uintmax_t 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 '0' padded * at the front to len. we are unable to use only one format as many old @@ -146,9 +217,16 @@ tar_trail(char *buf, int in_resync, int *cnt) */ static int -ul_oct(u_long val, char *str, int len, int term) +u32_oct(uintmax_t val, char *str, int len, int term) { char *pt; + uint64_t p; + + p = val & TOP_HALF; + if (p && p != TOP_HALF) + return -1; + + val &= BOTTOM_HALF; /* * term selects the appropriate character(s) for the end of the string @@ -177,31 +255,30 @@ ul_oct(u_long val, char *str, int len, int term) */ while (pt >= str) { *pt-- = '0' + (char)(val & 0x7); - if ((val = val >> 3) == (u_long)0) + if ((val = val >> 3) == 0) break; } while (pt >= str) *pt-- = '0'; - if (val != (u_long)0) - return(-1); - return(0); + if (val != 0) + return -1; + return 0; } -#ifndef NET2_STAT /* - * 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 '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. + * umax_oct() + * convert an unsigned long long 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 '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: * 0 if the number fit into the string, -1 otherwise */ static int -uqd_oct(u_quad_t val, char *str, int len, int term) +umax_oct(uintmax_t val, char *str, int len, int term) { char *pt; @@ -238,11 +315,10 @@ uqd_oct(u_quad_t val, char *str, int len, int term) while (pt >= str) *pt-- = '0'; - if (val != (u_quad_t)0) - return(-1); - return(0); + if (val != 0) + return -1; + return 0; } -#endif /* * tar_chksm() @@ -254,12 +330,12 @@ uqd_oct(u_quad_t val, char *str, int len, int term) * unsigned long checksum */ -static u_long +static uint32_t tar_chksm(char *blk, int len) { char *stop; char *pt; - u_long chksm = BLNKSUM; /* initial value is checksum field sum */ + uint32_t chksm = BLNKSUM; /* initial value is checksum field sum */ /* * add the part of the block before the checksum field @@ -267,7 +343,7 @@ tar_chksm(char *blk, int len) pt = blk; stop = blk + CHK_OFFSET; while (pt < stop) - chksm += (u_long)(*pt++ & 0xff); + chksm += (uint32_t)(*pt++ & 0xff); /* * move past the checksum field and keep going, spec counts the * checksum field as the sum of 8 blanks (which is pre-computed as @@ -278,8 +354,8 @@ tar_chksm(char *blk, int len) pt += CHK_LEN; stop = blk + len; while (pt < stop) - chksm += (u_long)(*pt++ & 0xff); - return(chksm); + chksm += (uint32_t)(*pt++ & 0xff); + return chksm; } /* @@ -300,9 +376,10 @@ tar_id(char *blk, int size) { HD_TAR *hd; HD_USTAR *uhd; + static int is_ustar = -1; if (size < BLKMULT) - return(-1); + return -1; hd = (HD_TAR *)blk; uhd = (HD_USTAR *)blk; @@ -314,12 +391,18 @@ tar_id(char *blk, int size) * checksum. If this is ok we have to assume it is a valid header. */ if (hd->name[0] == '\0') - return(-1); - if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0) - return(-1); - if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) - return(-1); - return(0); + return -1; + if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0) { + if (is_ustar == -1) { + is_ustar = 1; + return -1; + } else + tty_warn(0, + "Busted tar archive: has both ustar and old tar " + "records"); + } else + is_ustar = 0; + return check_sum(hd->chksum, sizeof(hd->chksum), blk, BLKMULT, 1); } /* @@ -337,24 +420,26 @@ tar_opt(void) while ((opt = opt_next()) != NULL) { if (strcmp(opt->name, TAR_OPTION) || strcmp(opt->value, TAR_NODIR)) { - paxwarn(1, "Unknown tar format -o option/value pair %s=%s", + tty_warn(1, + "Unknown tar format -o option/value pair %s=%s", opt->name, opt->value); - paxwarn(1,"%s=%s is the only supported tar format option", + tty_warn(1, + "%s=%s is the only supported tar format option", TAR_OPTION, TAR_NODIR); - return(-1); + return -1; } /* * we only support one option, and only when writing */ if ((act != APPND) && (act != ARCHIVE)) { - paxwarn(1, "%s=%s is only supported when writing.", + tty_warn(1, "%s=%s is only supported when writing.", opt->name, opt->value); - return(-1); + return -1; } tar_nodir = 1; } - return(0); + return 0; } @@ -376,34 +461,30 @@ tar_rd(ARCHD *arcn, char *buf) * we only get proper sized buffers passed to us */ if (tar_id(buf, BLKMULT) < 0) - return(-1); + return -1; + memset(arcn, 0, sizeof(*arcn)); arcn->org_name = arcn->name; - arcn->sb.st_nlink = 1; arcn->pat = NULL; + arcn->sb.st_nlink = 1; /* * copy out the name and values in the stat buffer */ hd = (HD_TAR *)buf; - /* - * old tar format specifies the name always be null-terminated, - * but let's be robust to broken archives. - * the same applies to handling links below. - */ - arcn->nlen = l_strncpy(arcn->name, hd->name, - MIN(sizeof(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) & + if (hd->linkflag != LONGLINKTYPE && hd->linkflag != LONGNAMETYPE) { + arcn->nlen = expandname(arcn->name, sizeof(arcn->name), + &gnu_name_string, &gnu_name_length, hd->name, + sizeof(hd->name)); + arcn->ln_nlen = expandname(arcn->ln_name, sizeof(arcn->ln_name), + &gnu_link_string, &gnu_link_length, hd->linkname, + sizeof(hd->linkname)); + } + arcn->sb.st_mode = (mode_t)(asc_u32(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); -#ifdef NET2_STAT - arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); - arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); -#else - arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); - arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT); -#endif + arcn->sb.st_uid = (uid_t)asc_u32(hd->uid, sizeof(hd->uid), OCT); + arcn->sb.st_gid = (gid_t)asc_u32(hd->gid, sizeof(hd->gid), OCT); + arcn->sb.st_size = (off_t)ASC_OFFT(hd->size, sizeof(hd->size), OCT); + arcn->sb.st_mtime = (time_t)(int32_t)asc_u32(hd->mtime, sizeof(hd->mtime), OCT); arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; /* @@ -420,9 +501,6 @@ tar_rd(ARCHD *arcn, char *buf) * the st_mode so -v printing will look correct. */ arcn->type = PAX_SLK; - arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, - MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1); - arcn->ln_name[arcn->ln_nlen] = '\0'; arcn->sb.st_mode |= S_IFLNK; break; case LNKTYPE: @@ -432,9 +510,6 @@ tar_rd(ARCHD *arcn, char *buf) */ arcn->type = PAX_HLK; arcn->sb.st_nlink = 2; - arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, - MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1); - arcn->ln_name[arcn->ln_nlen] = '\0'; /* * no idea of what type this thing really points at, but @@ -442,25 +517,29 @@ tar_rd(ARCHD *arcn, char *buf) */ arcn->sb.st_mode |= S_IFREG; break; - case DIRTYPE: + case LONGLINKTYPE: + case LONGNAMETYPE: /* - * It is a directory, set the mode for -v printing + * GNU long link/file; we tag these here and let the + * pax internals deal with it -- too ugly otherwise. */ - arcn->type = PAX_DIR; - arcn->sb.st_mode |= S_IFDIR; - arcn->sb.st_nlink = 2; - arcn->ln_name[0] = '\0'; - arcn->ln_nlen = 0; + if (hd->linkflag != LONGLINKTYPE) + arcn->type = PAX_GLF; + else + arcn->type = PAX_GLL; + arcn->pad = TAR_PAD(arcn->sb.st_size); + arcn->skip = arcn->sb.st_size; break; case AREGTYPE: case REGTYPE: + case DIRTYPE: /* see below */ default: /* * If we have a trailing / this is a directory and NOT a file. + * Note: V7 tar doesn't actually have DIRTYPE, but it was + * reported that V7 archives using USTAR directories do exist. */ - arcn->ln_name[0] = '\0'; - arcn->ln_nlen = 0; - if (*pt == '/') { + if (*pt == '/' || hd->linkflag == DIRTYPE) { /* * it is a directory, set the mode for -v printing */ @@ -488,14 +567,14 @@ tar_rd(ARCHD *arcn, char *buf) *pt = '\0'; --arcn->nlen; } - return(0); + return 0; } /* * tar_wr() * write a tar header for the file specified in the ARCHD to the archive. * Have to check for file types that cannot be stored and file names that - * are too long. Be careful of the term (last arg) to ul_oct, each field + * are too long. Be careful of the term (last arg) to u32_oct, each field * of tar has it own spec for the termination character(s). * ASSUMED: space after header in header block is zero filled * Return: @@ -519,27 +598,29 @@ tar_wr(ARCHD *arcn) * user asked that dirs not be written to the archive */ if (tar_nodir) - return(1); + return 1; break; case PAX_CHR: - paxwarn(1, "Tar cannot archive a character device %s", + tty_warn(1, "Tar cannot archive a character device %s", arcn->org_name); - return(1); + return 1; case PAX_BLK: - paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name); - return(1); + tty_warn(1, + "Tar cannot archive a block device %s", arcn->org_name); + return 1; case PAX_SCK: - paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name); - return(1); + tty_warn(1, "Tar cannot archive a socket %s", arcn->org_name); + return 1; case PAX_FIF: - paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name); - return(1); + tty_warn(1, "Tar cannot archive a fifo %s", arcn->org_name); + return 1; case PAX_SLK: case PAX_HLK: case PAX_HRG: - if (arcn->ln_nlen >= (int)sizeof(hd->linkname)) { - paxwarn(1,"Link name too long for tar %s", arcn->ln_name); - return(1); + if (arcn->ln_nlen > (int)sizeof(hd->linkname)) { + tty_warn(1,"Link name too long for tar %s", + arcn->ln_name); + return 1; } break; case PAX_REG: @@ -555,8 +636,8 @@ tar_wr(ARCHD *arcn) if (arcn->type == PAX_DIR) ++len; if (len >= (int)sizeof(hd->name)) { - paxwarn(1, "File name too long for tar %s", arcn->name); - return(1); + tty_warn(1, "File name too long for tar %s", arcn->name); + return 1; } /* @@ -567,9 +648,9 @@ tar_wr(ARCHD *arcn) * added after the file data (0 for all other types, as they only have * a header) */ + memset(hdblk, 0, sizeof(hdblk)); hd = (HD_TAR *)hdblk; - l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1); - hd->name[sizeof(hd->name) - 1] = '\0'; + strlcpy(hd->name, arcn->name, sizeof(hd->name)); arcn->pad = 0; if (arcn->type == PAX_DIR) { @@ -579,43 +660,34 @@ tar_wr(ARCHD *arcn) * dirs, so no pad. */ hd->linkflag = AREGTYPE; - memset(hd->linkname, 0, sizeof(hd->linkname)); hd->name[len-1] = '/'; - if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) + if (u32_oct((uintmax_t)0L, hd->size, sizeof(hd->size), 1)) goto out; } else if (arcn->type == PAX_SLK) { /* * no data follows this file, so no pad */ hd->linkflag = SYMTYPE; - 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)) + strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname)); + if (u32_oct((uintmax_t)0L, hd->size, sizeof(hd->size), 1)) goto out; } else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) { /* * no data follows this file, so no pad */ hd->linkflag = LNKTYPE; - 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)) + strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname)); + if (u32_oct((uintmax_t)0L, hd->size, sizeof(hd->size), 1)) goto out; } else { /* * data follows this file, so set the pad */ hd->linkflag = AREGTYPE; - memset(hd->linkname, 0, sizeof(hd->linkname)); -# ifdef NET2_STAT - if (ul_oct((u_long)arcn->sb.st_size, hd->size, - sizeof(hd->size), 1)) { -# else - if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, - sizeof(hd->size), 1)) { -# endif - paxwarn(1,"File is too large for tar %s", arcn->org_name); - return(1); + if (OFFT_OCT(arcn->sb.st_size, hd->size, sizeof(hd->size), 1)) { + tty_warn(1,"File is too large for tar %s", + arcn->org_name); + return 1; } arcn->pad = TAR_PAD(arcn->sb.st_size); } @@ -623,10 +695,10 @@ tar_wr(ARCHD *arcn) /* * copy those fields that are independent of the type */ - if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) || - ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) || - ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) || - ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1)) + if (u32_oct((uintmax_t)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) || + u32_oct((uintmax_t)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) || + u32_oct((uintmax_t)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) || + u32_oct((uintmax_t)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1)) goto out; /* @@ -634,23 +706,28 @@ tar_wr(ARCHD *arcn) * 0 tells the caller to now write the file data, 1 says no data needs * to be written */ - if (ul_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum, + if (u32_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum, sizeof(hd->chksum), 3)) - goto out; + goto out; /* XXX Something's wrong here + * because a zero-byte file can + * cause this to be done and + * yet the resulting warning + * seems incorrect */ + if (wr_rdbuf(hdblk, sizeof(HD_TAR)) < 0) - return(-1); + return -1; if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0) - return(-1); + return -1; if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) - return(0); - return(1); + return 0; + return 1; out: /* * header field is out of range */ - paxwarn(1, "Tar header field is too small for %s", arcn->org_name); - return(1); + tty_warn(1, "Tar header field is too small for %s", arcn->org_name); + return 1; } /* @@ -667,9 +744,7 @@ tar_wr(ARCHD *arcn) int ustar_strd(void) { - if ((usrtb_start() < 0) || (grptb_start() < 0)) - return(-1); - return(0); + return 0; } /* @@ -682,9 +757,7 @@ ustar_strd(void) int ustar_stwr(void) { - if ((uidtb_start() < 0) || (gidtb_start() < 0)) - return(-1); - return(0); + return 0; } /* @@ -701,7 +774,7 @@ ustar_id(char *blk, int size) HD_USTAR *hd; if (size < BLKMULT) - return(-1); + return -1; hd = (HD_USTAR *)blk; /* @@ -711,12 +784,17 @@ ustar_id(char *blk, int size) * check the checksum. If ok we have to assume it is a valid header. */ if (hd->name[0] == '\0') - return(-1); + return -1; if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0) - return(-1); - if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) - return(-1); - return(0); + return -1; + /* This is GNU tar */ + if (strncmp(hd->magic, "ustar ", 8) == 0 && !is_gnutar && + !seen_gnu_warning) { + seen_gnu_warning = 1; + tty_warn(0, + "Trying to read GNU tar archive with GNU extensions and end-of-volume checks off"); + } + return check_sum(hd->chksum, sizeof(hd->chksum), blk, BLKMULT, 0); } /* @@ -732,7 +810,7 @@ ustar_rd(ARCHD *arcn, char *buf) { HD_USTAR *hd; char *dest; - int cnt = 0; + int cnt; dev_t devmajor; dev_t devminor; @@ -740,11 +818,12 @@ ustar_rd(ARCHD *arcn, char *buf) * we only get proper sized buffers */ if (ustar_id(buf, BLKMULT) < 0) - return(-1); + return -1; + + memset(arcn, 0, sizeof(*arcn)); arcn->org_name = arcn->name; - arcn->sb.st_nlink = 1; arcn->pat = NULL; - arcn->nlen = 0; + arcn->sb.st_nlink = 1; hd = (HD_USTAR *)buf; /* @@ -753,54 +832,49 @@ ustar_rd(ARCHD *arcn, char *buf) */ dest = arcn->name; if (*(hd->prefix) != '\0') { - cnt = l_strncpy(dest, hd->prefix, - MIN(sizeof(hd->prefix), sizeof(arcn->name) - 2)); + cnt = strlcpy(arcn->name, hd->prefix, sizeof(arcn->name)); dest += cnt; *dest++ = '/'; cnt++; + } else { + cnt = 0; + } + + if (hd->typeflag != LONGLINKTYPE && hd->typeflag != LONGNAMETYPE) { + arcn->nlen = expandname(dest, sizeof(arcn->name) - cnt, + &gnu_name_string, &gnu_name_length, hd->name, + sizeof(hd->name)) + cnt; + arcn->ln_nlen = expandname(arcn->ln_name, + sizeof(arcn->ln_name), &gnu_link_string, &gnu_link_length, + hd->linkname, sizeof(hd->linkname)); } - /* - * ustar format specifies the name may be unterminated - * if it fills the entire field. this also applies to - * the prefix and the linkname. - */ - arcn->nlen = cnt + l_strncpy(dest, hd->name, - MIN(sizeof(hd->name), sizeof(arcn->name) - cnt - 1)); - arcn->name[arcn->nlen] = '\0'; /* * follow the spec to the letter. we should only have mode bits, strip * off all other crud we may be passed. */ - arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) & + arcn->sb.st_mode = (mode_t)(asc_u32(hd->mode, sizeof(hd->mode), OCT) & 0xfff); -#ifdef NET2_STAT - arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); - arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); -#else - arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); - arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT); -#endif + arcn->sb.st_size = (off_t)ASC_OFFT(hd->size, sizeof(hd->size), OCT); + arcn->sb.st_mtime = (time_t)(int32_t)asc_u32(hd->mtime, sizeof(hd->mtime), OCT); arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; /* * If we can find the ascii names for gname and uname in the password * and group files we will use the uid's and gid they bind. Otherwise * we use the uid and gid values stored in the header. (This is what - * the POSIX spec wants). + * the posix spec wants). */ hd->gname[sizeof(hd->gname) - 1] = '\0'; - if (gid_name((char *) hd->gname, (gid_t *) &(arcn->sb.st_gid)) < 0) - arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); + if (gid_from_group(hd->gname, &(arcn->sb.st_gid)) < 0) + arcn->sb.st_gid = (gid_t)asc_u32(hd->gid, sizeof(hd->gid), OCT); hd->uname[sizeof(hd->uname) - 1] = '\0'; - if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0) - arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); + if (uid_from_user(hd->uname, &(arcn->sb.st_uid)) < 0) + arcn->sb.st_uid = (uid_t)asc_u32(hd->uid, sizeof(hd->uid), OCT); /* * set the defaults, these may be changed depending on the file type */ - arcn->ln_name[0] = '\0'; - arcn->ln_nlen = 0; arcn->pad = 0; arcn->skip = 0; arcn->sb.st_rdev = (dev_t)0; @@ -838,8 +912,8 @@ ustar_rd(ARCHD *arcn, char *buf) arcn->type = PAX_CHR; arcn->sb.st_mode |= S_IFCHR; } - devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT); - devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT); + devmajor = (dev_t)asc_u32(hd->devmajor,sizeof(hd->devmajor),OCT); + devminor = (dev_t)asc_u32(hd->devminor,sizeof(hd->devminor),OCT); arcn->sb.st_rdev = TODEV(devmajor, devminor); break; case SYMTYPE: @@ -855,12 +929,24 @@ ustar_rd(ARCHD *arcn, char *buf) arcn->sb.st_mode |= S_IFREG; arcn->sb.st_nlink = 2; } - /* - * copy the link name - */ - arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, - MIN(sizeof(hd->linkname), sizeof(arcn->ln_name) - 1)); - arcn->ln_name[arcn->ln_nlen] = '\0'; + break; + case LONGLINKTYPE: + case LONGNAMETYPE: + if (is_gnutar) { + /* + * GNU long link/file; we tag these here and let the + * pax internals deal with it -- too ugly otherwise. + */ + if (hd->typeflag != LONGLINKTYPE) + arcn->type = PAX_GLF; + else + arcn->type = PAX_GLL; + arcn->pad = TAR_PAD(arcn->sb.st_size); + arcn->skip = arcn->sb.st_size; + } else { + tty_warn(1, "GNU Long %s found in posix ustar archive.", + hd->typeflag == LONGLINKTYPE ? "Link" : "File"); + } break; case CONTTYPE: case AREGTYPE: @@ -876,14 +962,60 @@ ustar_rd(ARCHD *arcn, char *buf) arcn->sb.st_mode |= S_IFREG; break; } - return(0); + return 0; +} + +static int +expandname(char *buf, size_t len, char **gnu_name, size_t *gnu_length, + const char *name, size_t nlen) +{ + if (*gnu_name) { + len = strlcpy(buf, *gnu_name, len); + free(*gnu_name); + *gnu_name = NULL; + *gnu_length = 0; + } else { + if (len > ++nlen) + len = nlen; + len = strlcpy(buf, name, len); + } + return len; +} + +static void +longlink(ARCHD *arcn, int type) +{ + ARCHD larc; + + (void)memset(&larc, 0, sizeof(larc)); + + larc.type = type; + larc.nlen = strlcpy(larc.name, LONG_LINK, sizeof(larc.name)); + + switch (type) { + case PAX_GLL: + gnu_hack_string = arcn->ln_name; + gnu_hack_len = arcn->ln_nlen + 1; + break; + case PAX_GLF: + gnu_hack_string = arcn->name; + gnu_hack_len = arcn->nlen + 1; + break; + default: + errx(1, "Invalid type in GNU longlink %d\n", type); + } + + /* + * We need a longlink now. + */ + ustar_wr(&larc); } /* * ustar_wr() * write a ustar header for the file specified in the ARCHD to the archive * Have to check for file types that cannot be stored and file names that - * are too long. Be careful of the term (last arg) to ul_oct, we only use + * are too long. Be careful of the term (last arg) to u32_oct, we only use * '\0' for the termination character (this is different than picky tar) * ASSUMED: space after header in header block is zero filled * Return: @@ -891,29 +1023,53 @@ ustar_rd(ARCHD *arcn, char *buf) * data to write after the header, -1 if archive write failed */ +static int +size_err(const char *what, ARCHD *arcn) +{ + /* + * header field is out of range + */ + tty_warn(1, "Ustar %s header field is too small for %s", + what, arcn->org_name); + return 1; +} + int ustar_wr(ARCHD *arcn) { HD_USTAR *hd; char *pt; char hdblk[sizeof(HD_USTAR)]; + const char *user, *group; - /* - * check for those file system types ustar cannot store - */ - if (arcn->type == PAX_SCK) { - paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name); - return(1); - } + switch (arcn->type) { + case PAX_SCK: + /* + * check for those file system types ustar cannot store + */ + if (!is_gnutar) + tty_warn(1, "Ustar cannot archive a socket %s", + arcn->org_name); + return 1; - /* - * check the length of the linkname - */ - if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || - (arcn->type == PAX_HRG)) && - (arcn->ln_nlen > (int)sizeof(hd->linkname))) { - paxwarn(1, "Link name too long for ustar %s", arcn->ln_name); - return(1); + case PAX_SLK: + case PAX_HLK: + case PAX_HRG: + /* + * check the length of the linkname + */ + if (arcn->ln_nlen >= (int)sizeof(hd->linkname)) { + if (is_gnutar) { + longlink(arcn, PAX_GLL); + } else { + tty_warn(1, "Link name too long for ustar %s", + arcn->ln_name); + return 1; + } + } + break; + default: + break; } /* @@ -921,9 +1077,20 @@ ustar_wr(ARCHD *arcn) * pt != arcn->name, the name has to be split */ if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) { - paxwarn(1, "File name too long for ustar %s", arcn->name); - return(1); + if (is_gnutar) { + longlink(arcn, PAX_GLF); + pt = arcn->name; + } else { + tty_warn(1, "File name too long for ustar %s", + arcn->name); + return 1; + } } + + /* + * zero out the header so we don't have to worry about zero fill below + */ + memset(hdblk, 0, sizeof(hdblk)); hd = (HD_USTAR *)hdblk; arcn->pad = 0L; @@ -936,16 +1103,15 @@ ustar_wr(ARCHD *arcn) * occur, we remove the / and copy the first part to the prefix */ *pt = '\0'; - l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix)); + strlcpy(hd->prefix, arcn->name, sizeof(hd->prefix)); *pt++ = '/'; - } else - memset(hd->prefix, 0, sizeof(hd->prefix)); + } /* * copy the name part. this may be the whole path or the part after - * the prefix. both the name and prefix may fill the entire field. + * the prefix */ - l_strncpy(hd->name, pt, sizeof(hd->name)); + strlcpy(hd->name, pt, sizeof(hd->name)); /* * set the fields in the header that are type dependent @@ -953,11 +1119,8 @@ ustar_wr(ARCHD *arcn) switch(arcn->type) { case PAX_DIR: hd->typeflag = DIRTYPE; - memset(hd->linkname, 0, sizeof(hd->linkname)); - 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)) - goto out; + if (u32_oct((uintmax_t)0L, hd->size, sizeof(hd->size), 3)) + return size_err("DIRTYPE", arcn); break; case PAX_CHR: case PAX_BLK: @@ -965,100 +1128,113 @@ ustar_wr(ARCHD *arcn) hd->typeflag = CHRTYPE; else hd->typeflag = BLKTYPE; - memset(hd->linkname, 0, sizeof(hd->linkname)); - if (ul_oct((u_long)major(arcn->sb.st_rdev), hd->devmajor, + if (u32_oct((uintmax_t)MAJOR(arcn->sb.st_rdev), hd->devmajor, sizeof(hd->devmajor), 3) || - ul_oct((u_long)minor(arcn->sb.st_rdev), hd->devminor, + u32_oct((uintmax_t)MINOR(arcn->sb.st_rdev), hd->devminor, sizeof(hd->devminor), 3) || - ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) - goto out; + u32_oct((uintmax_t)0L, hd->size, sizeof(hd->size), 3)) + return size_err("DEVTYPE", arcn); break; case PAX_FIF: hd->typeflag = FIFOTYPE; - memset(hd->linkname, 0, sizeof(hd->linkname)); - 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)) - goto out; + if (u32_oct((uintmax_t)0L, hd->size, sizeof(hd->size), 3)) + return size_err("FIFOTYPE", arcn); break; + case PAX_GLL: case PAX_SLK: case PAX_HLK: case PAX_HRG: if (arcn->type == PAX_SLK) hd->typeflag = SYMTYPE; + else if (arcn->type == PAX_GLL) + hd->typeflag = LONGLINKTYPE; else hd->typeflag = LNKTYPE; - /* the link name may occupy the entire field in ustar */ - l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname)); - 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)) - goto out; + strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname)); + if (u32_oct((uintmax_t)gnu_hack_len, hd->size, + sizeof(hd->size), 3)) + return size_err("LINKTYPE", arcn); break; + case PAX_GLF: case PAX_REG: case PAX_CTG: default: /* * file data with this type, set the padding */ - if (arcn->type == PAX_CTG) - hd->typeflag = CONTTYPE; - else - hd->typeflag = REGTYPE; - memset(hd->linkname, 0, sizeof(hd->linkname)); - memset(hd->devmajor, 0, sizeof(hd->devmajor)); - memset(hd->devminor, 0, sizeof(hd->devminor)); - arcn->pad = TAR_PAD(arcn->sb.st_size); -# ifdef NET2_STAT - if (ul_oct((u_long)arcn->sb.st_size, hd->size, - sizeof(hd->size), 3)) { -# else - if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, - sizeof(hd->size), 3)) { -# endif - paxwarn(1,"File is too long for ustar %s",arcn->org_name); - return(1); + if (arcn->type == PAX_GLF) { + hd->typeflag = LONGNAMETYPE; + arcn->pad = TAR_PAD(gnu_hack_len); + if (OFFT_OCT((uint32_t)gnu_hack_len, hd->size, + sizeof(hd->size), 3)) { + tty_warn(1,"File is too long for ustar %s", + arcn->org_name); + return 1; + } + } else { + if (arcn->type == PAX_CTG) + hd->typeflag = CONTTYPE; + else + hd->typeflag = REGTYPE; + arcn->pad = TAR_PAD(arcn->sb.st_size); + if (OFFT_OCT(arcn->sb.st_size, hd->size, + sizeof(hd->size), 3)) { + tty_warn(1,"File is too long for ustar %s", + arcn->org_name); + return 1; + } } break; } - l_strncpy(hd->magic, TMAGIC, TMAGLEN); - l_strncpy(hd->version, TVERSION, TVERSLEN); + strncpy(hd->magic, TMAGIC, TMAGLEN); + if (is_gnutar) + hd->magic[TMAGLEN - 1] = hd->version[0] = ' '; + else + strncpy(hd->version, TVERSION, TVERSLEN); /* * set the remaining fields. Some versions want all 16 bits of mode * we better humor them (they really do not meet spec though).... */ - if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) || - ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3) || - 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; - 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)); + if (u32_oct((uintmax_t)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3)) + return size_err("MODE", arcn); + if (u32_oct((uintmax_t)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3)) + return size_err("UID", arcn); + if (u32_oct((uintmax_t)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3)) + return size_err("GID", arcn); + if (u32_oct((uintmax_t)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3)) + return size_err("MTIME", arcn); + user = user_from_uid(arcn->sb.st_uid, 1); + group = group_from_gid(arcn->sb.st_gid, 1); + strncpy(hd->uname, user ? user : "", sizeof(hd->uname)); + strncpy(hd->gname, group ? group : "", sizeof(hd->gname)); /* * calculate and store the checksum write the header to the archive * return 0 tells the caller to now write the file data, 1 says no data * needs to be written */ - if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum, + if (u32_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum, sizeof(hd->chksum), 3)) - goto out; + return size_err("CHKSUM", arcn); if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0) - return(-1); + return -1; if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0) - return(-1); + return -1; + if (gnu_hack_string) { + int res = wr_rdbuf(gnu_hack_string, gnu_hack_len); + int pad = gnu_hack_len; + gnu_hack_string = NULL; + gnu_hack_len = 0; + if (res < 0) + return -1; + if (wr_skip((off_t)(BLKMULT - (pad % BLKMULT))) < 0) + return -1; + } if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) - return(0); - return(1); - - out: - /* - * header field is out of range - */ - paxwarn(1, "Ustar header field is too small for %s", arcn->org_name); - return(1); + return 0; + return 1; } /* @@ -1082,23 +1258,27 @@ name_split(char *name, int 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) - return(name); - if (len > (TPFSZ + TNMSZ + 1)) - return(NULL); + if (len < TNMSZ) + return name; + /* + * GNU tar does not honor the prefix+name mode if the magic + * is not "ustar\0". So in GNU tar compatibility mode, we don't + * split the filename into prefix+name because we are setting + * the magic to "ustar " as GNU tar does. This of course will + * end up creating a LongLink record in cases where it does not + * really need do, but we are behaving like GNU tar after all. + */ + if (is_gnutar || len > (TPFSZ + TNMSZ)) + return NULL; /* * we start looking at the biggest sized piece that fits in the name * field. We walk forward looking for a slash to split at. The idea is * to find the biggest piece to fit in the name field (or the smallest - * prefix we can find) + * prefix we can find) (the -1 is correct the biggest piece would + * include the slash between the two parts that gets thrown away) */ - start = name + len - TNMSZ - 1; - - /* Don't split at first '/'. */ - if (start == name && *start == '/') - ++start; - + start = name + len - TNMSZ; while ((*start != '\0') && (*start != '/')) ++start; @@ -1107,20 +1287,127 @@ name_split(char *name, int len) * cannot store this file. */ if (*start == '\0') - return(NULL); + return NULL; len = start - name; /* - * NOTE: /str where the length of str == TNMSZ can not be stored under + * NOTE: /str where the length of str == TNMSZ cannot be stored under * the p1003.1-1990 spec for ustar. We could force a prefix of / and * the file would then expand on extract to //str. The len == 0 below * makes this special case follow the spec to the letter. */ - if ((len > TPFSZ) || (len == 0)) - return(NULL); + if ((len >= TPFSZ) || (len == 0)) + return NULL; /* * ok have a split point, return it to the caller */ - return(start); + return start; +} + +/* + * convert a glob into a RE, and add it to the list. we convert to + * four different RE's (because we're using BRE's and can't use | + * alternation :-() with this padding: + * .*\/ and $ + * .*\/ and \/.* + * ^ and $ + * ^ and \/.* + */ +static int +tar_gnutar_exclude_one(const char *line, size_t len) +{ + /* 2 * buffer len + nul */ + char sbuf[MAXPATHLEN * 2 + 1]; + /* + / + // + .*""/\/ + \/.* */ + char rabuf[MAXPATHLEN * 2 + 1 + 1 + 2 + 4 + 4]; + size_t i; + int j = 0; + + if (line[len - 1] == '\n') + len--; + for (i = 0; i < len; i++) { + /* + * convert glob to regexp, escaping everything + */ + if (line[i] == '*') + sbuf[j++] = '.'; + else if (line[i] == '?') { + sbuf[j++] = '.'; + continue; + } else if (!isalnum((unsigned char)line[i]) && + !isblank((unsigned char)line[i])) + sbuf[j++] = '\\'; + sbuf[j++] = line[i]; + } + sbuf[j] = '\0'; + /* don't need the .*\/ ones if we start with /, i guess */ + if (line[0] != '/') { + (void)snprintf(rabuf, sizeof rabuf, "/.*\\/%s$//", sbuf); + if (rep_add(rabuf) < 0) + return (-1); + (void)snprintf(rabuf, sizeof rabuf, "/.*\\/%s\\/.*//", sbuf); + if (rep_add(rabuf) < 0) + return (-1); + } + + (void)snprintf(rabuf, sizeof rabuf, "/^%s$//", sbuf); + if (rep_add(rabuf) < 0) + return (-1); + (void)snprintf(rabuf, sizeof rabuf, "/^%s\\/.*//", sbuf); + if (rep_add(rabuf) < 0) + return (-1); + + return (0); +} + +/* + * deal with GNU tar -X/--exclude-from & --exclude switchs. basically, + * we go through each line of the file, building a string from the "glob" + * lines in the file into RE lines, of the form `/^RE$//', which we pass + * to rep_add(), which will add a empty replacement (exclusion), for the + * named files. + */ +int +tar_gnutar_minus_minus_exclude(const char *path) +{ + size_t len = strlen(path); + + if (len > MAXPATHLEN) + tty_warn(0, "pathname too long: %s", path); + + return (tar_gnutar_exclude_one(path, len)); +} + +int +tar_gnutar_X_compat(const char *path) +{ + char *line; + FILE *fp; + int lineno = 0; + size_t len; + + if (path[0] == '-' && path[1] == '\0') + fp = stdin; + else { + fp = fopen(path, "r"); + if (fp == NULL) { + tty_warn(1, "cannot open %s: %s", path, + strerror(errno)); + return -1; + } + } + + while ((line = fgetln(fp, &len))) { + lineno++; + if (len > MAXPATHLEN) { + tty_warn(0, "pathname too long, line %d of %s", + lineno, path); + } + if (tar_gnutar_exclude_one(line, len)) + return -1; + } + if (fp != stdin) + fclose(fp); + return 0; } diff --git a/commands/pax/tar.h b/bin/pax/tar.h similarity index 88% rename from commands/pax/tar.h rename to bin/pax/tar.h index ae767ba2a..6d26cb69c 100644 --- a/commands/pax/tar.h +++ b/bin/pax/tar.h @@ -1,3 +1,5 @@ +/* $NetBSD: tar.h,v 1.9 2004/05/11 17:12:26 christos Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,7 +33,6 @@ * SUCH DAMAGE. * * @(#)tar.h 8.2 (Berkeley) 4/18/94 - * $FreeBSD: src/bin/pax/tar.h,v 1.7 2004/04/06 20:06:49 markm Exp $ */ /* @@ -41,13 +42,13 @@ #define TNMSZ 100 /* size of name field */ #ifdef _PAX_ #define NULLCNT 2 /* number of null blocks in trailer */ -#define CHK_OFFSET 148 /* start of checksum field */ +#define CHK_OFFSET 148 /* start of chksum field */ #define BLNKSUM 256L /* sum of checksum field using ' ' */ #endif /* _PAX_ */ /* * Values used in typeflag field in all tar formats - * (only REGTYPE, LNKTYPE and SYMTYPE are used in old BSD tar headers) + * (only REGTYPE, LNKTYPE and SYMTYPE are used in old bsd tar headers) */ #define REGTYPE '0' /* Regular File */ #define AREGTYPE '\0' /* Regular File */ @@ -59,6 +60,12 @@ #define FIFOTYPE '6' /* FIFO */ #define CONTTYPE '7' /* high perf file */ +/* + * GNU tar compatibility; + */ +#define LONGLINKTYPE 'K' /* Long Symlink */ +#define LONGNAMETYPE 'L' /* Long File */ + /* * Mode field encoding of the different file types - values in octal */ @@ -88,8 +95,8 @@ */ typedef struct { char name[TNMSZ]; /* name of entry */ - char mode[8]; /* mode */ - char uid[8]; /* uid */ + char mode[8]; /* mode */ + char uid[8]; /* uid */ char gid[8]; /* gid */ char size[12]; /* size */ char mtime[12]; /* modification time */ @@ -108,12 +115,12 @@ typedef struct { /* * default device names */ -#define DEV_0 "/dev/rmt0" -#define DEV_1 "/dev/rmt1" -#define DEV_4 "/dev/rmt4" -#define DEV_5 "/dev/rmt5" -#define DEV_7 "/dev/rmt7" -#define DEV_8 "/dev/rmt8" +extern char DEV_0[]; +extern char DEV_1[]; +extern char DEV_4[]; +extern char DEV_5[]; +extern char DEV_7[]; +extern char DEV_8[]; #endif /* _PAX_ */ /* @@ -127,8 +134,8 @@ typedef struct { typedef struct { char name[TNMSZ]; /* name of entry */ - char mode[8]; /* mode */ - char uid[8]; /* uid */ + char mode[8]; /* mode */ + char uid[8]; /* uid */ char gid[8]; /* gid */ char size[12]; /* size */ char mtime[12]; /* modification time */ diff --git a/commands/pax/tty_subs.c b/bin/pax/tty_subs.c similarity index 83% rename from commands/pax/tty_subs.c rename to bin/pax/tty_subs.c index 3a3565440..595687783 100644 --- a/commands/pax/tty_subs.c +++ b/bin/pax/tty_subs.c @@ -1,3 +1,5 @@ +/* $NetBSD: tty_subs.c,v 1.19 2007/04/23 18:40:22 christos Exp $ */ + /*- * Copyright (c) 1992 Keith Muller. * Copyright (c) 1992, 1993 @@ -14,7 +16,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -31,16 +33,27 @@ * SUCH DAMAGE. */ -#ifndef lint +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#if !defined(lint) #if 0 static char sccsid[] = "@(#)tty_subs.c 8.2 (Berkeley) 4/18/94"; +#else +__RCSID("$NetBSD: tty_subs.c,v 1.19 2007/04/23 18:40:22 christos Exp $"); #endif #endif /* not lint */ #include +#include #include +#include #include #include +#include +#include #include #include #include @@ -52,14 +65,14 @@ static char sccsid[] = "@(#)tty_subs.c 8.2 (Berkeley) 4/18/94"; * routines that deal with I/O to and from the user */ -#define DEVTTY "/dev/tty" /* device for interactive i/o */ +#define DEVTTY "/dev/tty" /* device for interactive i/o */ static FILE *ttyoutf = NULL; /* output pointing at control tty */ static FILE *ttyinf = NULL; /* input pointing at control tty */ /* * tty_init() - * try to open the controlling terminal (if any) for this process. if the - * open fails, future ops that require user input will get an EOF + * Try to open the controlling terminal (if any) for this process. If the + * open fails, future ops that require user input will get an EOF. */ int @@ -70,17 +83,17 @@ tty_init(void) if ((ttyfd = open(DEVTTY, O_RDWR)) >= 0) { if ((ttyoutf = fdopen(ttyfd, "w")) != NULL) { if ((ttyinf = fdopen(ttyfd, "r")) != NULL) - return(0); + return 0; (void)fclose(ttyoutf); } (void)close(ttyfd); } if (iflag) { - paxwarn(1, "Fatal error, cannot open %s", DEVTTY); - return(-1); + tty_warn(1, "Fatal error, cannot open %s", DEVTTY); + return -1; } - return(0); + return 0; } /* @@ -115,7 +128,7 @@ tty_read(char *str, int len) char *pt; if ((--len <= 0) || (ttyinf == NULL) || (fgets(str,len,ttyinf) == NULL)) - return(-1); + return -1; *(str + len) = '\0'; /* @@ -123,17 +136,17 @@ tty_read(char *str, int len) */ if ((pt = strchr(str, '\n')) != NULL) *pt = '\0'; - return(0); + return 0; } /* - * paxwarn() + * tty_warn() * write a warning message to stderr. if "set" the exit value of pax * will be non-zero. */ void -paxwarn(int set, const char *fmt, ...) +tty_warn(int set, const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -143,8 +156,7 @@ paxwarn(int set, const char *fmt, ...) * when vflag we better ship out an extra \n to get this message on a * line by itself */ - if (vflag && vfpart) { - (void)fflush(listf); + if ((Vflag || vflag) && vfpart) { (void)fputc('\n', stderr); vfpart = 0; } @@ -171,9 +183,8 @@ syswarn(int set, int errnum, const char *fmt, ...) * when vflag we better ship out an extra \n to get this message on a * line by itself */ - if (vflag && vfpart) { - (void)fflush(listf); - (void)fputc('\n', stderr); + if ((Vflag || vflag) && vfpart) { + (void)fputc('\n', stdout); vfpart = 0; } (void)fprintf(stderr, "%s: ", argv0); @@ -184,6 +195,6 @@ syswarn(int set, int errnum, const char *fmt, ...) * format and print the errno */ if (errnum > 0) - (void)fprintf(stderr, " <%s>", strerror(errnum)); + (void)fprintf(stderr, " (%s)", strerror(errnum)); (void)fputc('\n', stderr); } diff --git a/commands/Makefile b/commands/Makefile index 8a697d888..8c0d4c955 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -17,7 +17,7 @@ SUBDIR= add_route arp ash at backup banner basename btrace cal \ lpd ls lspci mail MAKEDEV \ mesg mined mkfifo \ mkproto mount mt netconf nice acknm nohup \ - nonamed od paste patch pax \ + nonamed od paste patch \ ping postinstall poweroff pr prep printf printroot \ profile progressbar pr_routes ps pwd pwdauth \ ramdisk rarpd rawspeed rcp rdate readclock \ diff --git a/commands/pax/Makefile b/commands/pax/Makefile deleted file mode 100644 index e1adb6e94..000000000 --- a/commands/pax/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# @(#)Makefile 8.1 (Berkeley) 5/31/93 -# $FreeBSD$ - -# To install on versions prior to BSD 4.4 the following may have to be -# defined with CFLAGS += -# -# -DNET2_STAT Use NET2 or older stat structure. The version of the -# stat structure is easily determined by looking at the -# basic type of an off_t (often defined in the file: -# /usr/include/sys/types.h). If off_t is a long (and is -# NOT A quad) then you must define NET2_STAT. -# This define is important, as if you do have a quad_t -# off_t and define NET2_STAT, pax will compile but will -# NOT RUN PROPERLY. -# -# -DNET2_FTS Use the older NET2 fts. To identify the version, -# examine the file: /usr/include/fts.h. If FTS_COMFOLLOW -# is not defined then you must define NET2_FTS. -# Pax may not compile if this not (un)defined properly. -# -# -DNET2_REGEX Use the older regexp.h not regex.h. The regex version -# is determined by looking at the value returned by -# regexec() (man 3 regexec). If regexec return a 1 for -# success (and NOT a 0 for success) you have the older -# regex routines and must define NET2_REGEX. -# 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 getoldopt.c options.c pat_rep.c pax.c sel_subs.c \ - tables.c tar.c tty_subs.c fgetln.c - -MAN= pax.1 cpio.1 -BINDIR=/bin -SYMLINKS+= $(BINDIR)/$(PROG) /usr/bin/$(PROG) -LINKS+= ${BINDIR}/pax ${BINDIR}/cpio - -CPPFLAGS+= -DNET2_STAT=1 - -.include diff --git a/commands/pax/cache.c b/commands/pax/cache.c deleted file mode 100644 index 25dfd9ec5..000000000 --- a/commands/pax/cache.c +++ /dev/null @@ -1,430 +0,0 @@ -/*- - * Copyright (c) 1992 Keith Muller. - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Keith Muller of the University of California, San Diego. - * - * 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. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93"; -#endif -#endif /* not lint */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "pax.h" -#include "cache.h" -#include "extern.h" - -/* - * routines that control user, group, uid and gid caches (for the archive - * member print routine). - * IMPORTANT: - * these routines cache BOTH hits and misses, a major performance improvement - */ - -static int pwopn = 0; /* is password file open */ -static int gropn = 0; /* is group file open */ -static UIDC **uidtb = NULL; /* uid to name cache */ -static GIDC **gidtb = NULL; /* gid to name cache */ -static UIDC **usrtb = NULL; /* user name to uid cache */ -static GIDC **grptb = NULL; /* group name to gid cache */ - -/* - * uidtb_start - * creates an an empty uidtb - * Return: - * 0 if ok, -1 otherwise - */ - -int -uidtb_start(void) -{ - static int fail = 0; - - if (uidtb != NULL) - return(0); - if (fail) - return(-1); - if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) { - ++fail; - paxwarn(1, "Unable to allocate memory for user id cache table"); - return(-1); - } - return(0); -} - -/* - * gidtb_start - * creates an an empty gidtb - * Return: - * 0 if ok, -1 otherwise - */ - -int -gidtb_start(void) -{ - static int fail = 0; - - if (gidtb != NULL) - return(0); - if (fail) - return(-1); - if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) { - ++fail; - paxwarn(1, "Unable to allocate memory for group id cache table"); - return(-1); - } - return(0); -} - -/* - * usrtb_start - * creates an an empty usrtb - * Return: - * 0 if ok, -1 otherwise - */ - -int -usrtb_start(void) -{ - static int fail = 0; - - if (usrtb != NULL) - return(0); - if (fail) - return(-1); - if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) { - ++fail; - paxwarn(1, "Unable to allocate memory for user name cache table"); - return(-1); - } - return(0); -} - -/* - * grptb_start - * creates an an empty grptb - * Return: - * 0 if ok, -1 otherwise - */ - -int -grptb_start(void) -{ - static int fail = 0; - - if (grptb != NULL) - return(0); - if (fail) - return(-1); - if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) { - ++fail; - paxwarn(1,"Unable to allocate memory for group name cache table"); - return(-1); - } - return(0); -} - -/* - * name_uid() - * caches the name (if any) for the uid. If frc set, we always return the - * the stored name (if valid or invalid match). We use a simple hash table. - * Return - * Pointer to stored name (or an empty string). - */ - -const char * -name_uid(uid_t uid, int frc) -{ - struct passwd *pw; - UIDC *ptr; - - if ((uidtb == NULL) && (uidtb_start() < 0)) - return(""); - - /* - * see if we have this uid cached - */ - ptr = uidtb[uid % UID_SZ]; - if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) { - /* - * have an entry for this uid - */ - if (frc || (ptr->valid == VALID)) - return(ptr->name); - return(""); - } - - /* - * No entry for this uid, we will add it - */ - if (!pwopn) { - setpassent(1); - ++pwopn; - } - if (ptr == NULL) - ptr = uidtb[uid % UID_SZ] = (UIDC *)malloc(sizeof(UIDC)); - - if ((pw = getpwuid(uid)) == NULL) { - /* - * no match for this uid in the local password file - * a string that is the uid in numeric format - */ - if (ptr == NULL) - return(""); - ptr->uid = uid; - ptr->valid = INVALID; -# ifdef NET2_STAT - (void)snprintf(ptr->name, sizeof(ptr->name), "%u", uid); -# else - (void)snprintf(ptr->name, sizeof(ptr->name), "%lu", - (unsigned long)uid); -# endif - if (frc == 0) - return(""); - } else { - /* - * there is an entry for this uid in the password file - */ - if (ptr == NULL) - return(pw->pw_name); - ptr->uid = uid; - (void)strncpy(ptr->name, pw->pw_name, UNMLEN - 1); - ptr->name[UNMLEN-1] = '\0'; - ptr->valid = VALID; - } - return(ptr->name); -} - -/* - * name_gid() - * caches the name (if any) for the gid. If frc set, we always return the - * the stored name (if valid or invalid match). We use a simple hash table. - * Return - * Pointer to stored name (or an empty string). - */ - -const char * -name_gid(gid_t gid, int frc) -{ - struct group *gr; - GIDC *ptr; - - if ((gidtb == NULL) && (gidtb_start() < 0)) - return(""); - - /* - * see if we have this gid cached - */ - ptr = gidtb[gid % GID_SZ]; - if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) { - /* - * have an entry for this gid - */ - if (frc || (ptr->valid == VALID)) - return(ptr->name); - return(""); - } - - /* - * No entry for this gid, we will add it - */ - if (!gropn) { - setgroupent(1); - ++gropn; - } - if (ptr == NULL) - ptr = gidtb[gid % GID_SZ] = (GIDC *)malloc(sizeof(GIDC)); - - if ((gr = getgrgid(gid)) == NULL) { - /* - * no match for this gid in the local group file, put in - * a string that is the gid in numeric format - */ - if (ptr == NULL) - return(""); - ptr->gid = gid; - ptr->valid = INVALID; -# ifdef NET2_STAT - (void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid); -# else - (void)snprintf(ptr->name, sizeof(ptr->name), "%lu", - (unsigned long)gid); -# endif - if (frc == 0) - return(""); - } else { - /* - * there is an entry for this group in the group file - */ - if (ptr == NULL) - return(gr->gr_name); - ptr->gid = gid; - (void)strncpy(ptr->name, gr->gr_name, GNMLEN - 1); - ptr->name[GNMLEN-1] = '\0'; - ptr->valid = VALID; - } - return(ptr->name); -} - -/* - * uid_name() - * caches the uid for a given user name. We use a simple hash table. - * Return - * the uid (if any) for a user name, or a -1 if no match can be found - */ - -int -uid_name(char *name, uid_t *uid) -{ - struct passwd *pw; - UIDC *ptr; - int namelen; - - /* - * return -1 for mangled names - */ - if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) - return(-1); - if ((usrtb == NULL) && (usrtb_start() < 0)) - return(-1); - - /* - * look up in hash table, if found and valid return the uid, - * if found and invalid, return a -1 - */ - ptr = usrtb[st_hash(name, namelen, UNM_SZ)]; - if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { - if (ptr->valid == INVALID) - return(-1); - *uid = ptr->uid; - return(0); - } - - if (!pwopn) { - setpassent(1); - ++pwopn; - } - - if (ptr == NULL) - 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, - * or store the matching uid - */ - if (ptr == NULL) { - if ((pw = getpwnam(name)) == NULL) - return(-1); - *uid = pw->pw_uid; - return(0); - } - (void)strncpy(ptr->name, name, UNMLEN - 1); - ptr->name[UNMLEN-1] = '\0'; - if ((pw = getpwnam(name)) == NULL) { - ptr->valid = INVALID; - return(-1); - } - ptr->valid = VALID; - *uid = ptr->uid = pw->pw_uid; - return(0); -} - -/* - * gid_name() - * caches the gid for a given group name. We use a simple hash table. - * Return - * the gid (if any) for a group name, or a -1 if no match can be found - */ - -int -gid_name(char *name, gid_t *gid) -{ - struct group *gr; - GIDC *ptr; - int namelen; - - /* - * return -1 for mangled names - */ - if (((namelen = strlen(name)) == 0) || (name[0] == '\0')) - return(-1); - if ((grptb == NULL) && (grptb_start() < 0)) - return(-1); - - /* - * look up in hash table, if found and valid return the uid, - * if found and invalid, return a -1 - */ - ptr = grptb[st_hash(name, namelen, GID_SZ)]; - if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { - if (ptr->valid == INVALID) - return(-1); - *gid = ptr->gid; - return(0); - } - - if (!gropn) { - setgroupent(1); - ++gropn; - } - if (ptr == NULL) - 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, - * or store the matching gid - */ - if (ptr == NULL) { - if ((gr = getgrnam(name)) == NULL) - return(-1); - *gid = gr->gr_gid; - return(0); - } - - (void)strncpy(ptr->name, name, GNMLEN - 1); - ptr->name[GNMLEN-1] = '\0'; - if ((gr = getgrnam(name)) == NULL) { - ptr->valid = INVALID; - return(-1); - } - ptr->valid = VALID; - *gid = ptr->gid = gr->gr_gid; - return(0); -} diff --git a/commands/pax/cache.h b/commands/pax/cache.h deleted file mode 100644 index 9d0ddcba0..000000000 --- a/commands/pax/cache.h +++ /dev/null @@ -1,71 +0,0 @@ -/*- - * Copyright (c) 1992 Keith Muller. - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Keith Muller of the University of California, San Diego. - * - * 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. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. - * - * @(#)cache.h 8.1 (Berkeley) 5/31/93 - * $FreeBSD: src/bin/pax/cache.h,v 1.9 2004/04/06 20:06:48 markm Exp $ - */ - -/* - * Constants and data structures used to implement group and password file - * caches. Traditional passwd/group cache routines perform quite poorly with - * archives. The chances of hitting a valid lookup with an archive is quite a - * bit worse than with files already resident on the file system. These misses - * create a MAJOR performance cost. To address this problem, these routines - * cache both hits and misses. - * - * NOTE: name lengths must be as large as those stored in ANY PROTOCOL and - * as stored in the passwd and group files. CACHE SIZES MUST BE PRIME - */ -#define UNMLEN 32 /* >= user name found in any protocol */ -#define GNMLEN 32 /* >= group name found in any protocol */ -#define UID_SZ 317 /* size of user_name/uid cache */ -#define UNM_SZ 317 /* size of user_name/uid cache */ -#define GID_SZ 251 /* size of gid cache */ -#define GNM_SZ 317 /* size of group name cache */ -#define VALID 1 /* entry and name are valid */ -#define INVALID 2 /* entry valid, name NOT valid */ - -/* - * Node structures used in the user, group, uid, and gid caches. - */ - -typedef struct uidc { - int valid; /* is this a valid or a miss entry */ - char name[UNMLEN]; /* uid name */ - uid_t uid; /* cached uid */ -} UIDC; - -typedef struct gidc { - int valid; /* is this a valid or a miss entry */ - char name[GNMLEN]; /* gid name */ - gid_t gid; /* cached gid */ -} GIDC; diff --git a/commands/pax/err.h b/commands/pax/err.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/commands/pax/fgetln.c b/commands/pax/fgetln.c deleted file mode 100644 index f39aa9235..000000000 --- a/commands/pax/fgetln.c +++ /dev/null @@ -1,38 +0,0 @@ - -#include -#include -#include - -char * -fgetln(FILE *fp, size_t *lenp) -{ -#define EXTRA 80 - char *buf = NULL; - int used = 0, len = 0, remain = 0, final = 0; - while(!final) { - char *b; - int r; - if(remain < EXTRA) { - int newlen; - char *newbuf; - newlen = len + EXTRA; - if(!(newbuf = realloc(buf, newlen))) { - if(buf) free(buf); - return NULL; - } - buf = newbuf; - len = newlen; - remain += EXTRA; - } - buf[used] = '\0'; - if(!fgets(buf + used, remain, fp)) - break; - r = strlen(buf+used); - used += r; - remain -= r; - len += r; - } - *lenp = len; - return buf; -} - diff --git a/commands/pax/options.c b/commands/pax/options.c deleted file mode 100644 index 8f5547abc..000000000 --- a/commands/pax/options.c +++ /dev/null @@ -1,1606 +0,0 @@ -/*- - * Copyright (c) 1992 Keith Muller. - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Keith Muller of the University of California, San Diego. - * - * 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. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. - */ - -#define _POSIX_SOURCE 1 -#define _MINIX 1 - -#if 0 -#ifndef lint -static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 4/18/94"; -#endif /* not lint */ -#endif - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -#include "pax.h" -#include "options.h" -#include "cpio.h" -#include "tar.h" -#include "extern.h" - -/* - * Routines which handle command line options - */ - -#ifdef __NBSD_LIBC -#define getline pax_getline -#endif - -static char flgch[] = FLGCH; /* list of all possible flags */ -static OPLIST *ophead = NULL; /* head for format specific options -x */ -static OPLIST *optail = NULL; /* option tail */ - -static int no_op(void); -static void printflg(unsigned int); -static int c_frmt(const void *, const void *); -static off_t str_offt(char *); -static char *getline(FILE *fp); -static void pax_options(int, char **); -static void pax_usage(void); -static void tar_options(int, char **); -static void tar_usage(void); -static void cpio_options(int, char **); -static void cpio_usage(void); - -/* 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 - * (see pax.h for description of each function) - * - * name, blksz, hdsz, udev, hlk, blkagn, inhead, id, st_read, - * read, end_read, st_write, write, end_write, trail, - * rd_data, wr_data, options - */ - -FSUB fsub[] = { -/* 0: OLD BINARY CPIO */ - {"bcpio", 5120, sizeof(HD_BCPIO), 1, 0, 0, 1, bcpio_id, cpio_strd, - bcpio_rd, bcpio_endrd, cpio_stwr, bcpio_wr, cpio_endwr, cpio_trail, - NULL, rd_wrfile, wr_rdfile, bad_opt}, - -/* 1: OLD OCTAL CHARACTER CPIO */ - {"cpio", 5120, sizeof(HD_CPIO), 1, 0, 0, 1, cpio_id, cpio_strd, - cpio_rd, cpio_endrd, cpio_stwr, cpio_wr, cpio_endwr, cpio_trail, - NULL, rd_wrfile, wr_rdfile, bad_opt}, - -/* 2: SVR4 HEX CPIO */ - {"sv4cpio", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, vcpio_id, cpio_strd, - vcpio_rd, vcpio_endrd, cpio_stwr, vcpio_wr, cpio_endwr, cpio_trail, - NULL, rd_wrfile, wr_rdfile, bad_opt}, - -/* 3: SVR4 HEX CPIO WITH CRC */ - {"sv4crc", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd, - vcpio_rd, vcpio_endrd, crc_stwr, vcpio_wr, cpio_endwr, cpio_trail, - NULL, rd_wrfile, wr_rdfile, bad_opt}, - -/* 4: OLD TAR */ - {"tar", 10240, BLKMULT, 0, 1, BLKMULT, 0, tar_id, no_op, - tar_rd, tar_endrd, no_op, tar_wr, tar_endwr, NULL, tar_trail, - rd_wrfile, wr_rdfile, tar_opt}, - -/* 5: POSIX USTAR */ - {"ustar", 10240, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, ustar_strd, - ustar_rd, tar_endrd, ustar_stwr, ustar_wr, tar_endwr, NULL, tar_trail, - rd_wrfile, wr_rdfile, bad_opt}, -}; -#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 */ - -/* - * ford is the archive search order used by get_arc() to determine what kind - * of archive we are dealing with. This helps to properly id archive formats - * some formats may be subsets of others.... - */ -int ford[] = {5, 4, 3, 2, 1, 0, -1 }; - -/* - * options() - * figure out if we are pax, tar or cpio. Call the appropriate options - * parser - */ - -void -options(int argc, char **argv) -{ - - /* - * Are we acting like pax, tar or cpio (based on argv[0]) - */ - if ((argv0 = strrchr(argv[0], '/')) != NULL) - argv0++; - else - argv0 = argv[0]; - - if (strcmp(NM_TAR, argv0) == 0) { - tar_options(argc, argv); - return; - } - else if (strcmp(NM_CPIO, argv0) == 0) { - cpio_options(argc, argv); - return; - } - /* - * assume pax as the default - */ - argv0 = NM_PAX; - pax_options(argc, argv); - return; -} - -/* - * pax_options() - * look at the user specified flags. set globals as required and check if - * the user specified a legal set of flags. If not, complain and exit - */ - -static void -pax_options(int argc, char **argv) -{ - int c; - size_t i; - unsigned int flg = 0; - unsigned int bflg = 0; - char *pt; - FSUB tmp; - - /* - * process option flags - */ - while ((c=getopt(argc,argv,"ab:cdf:iklno:p:rs:tuvwx:zB:DE:G:HLPT:U:XYZ")) - != -1) { - switch (c) { - case 'a': - /* - * append - */ - flg |= AF; - break; - case 'b': - /* - * specify blocksize - */ - flg |= BF; - if ((wrblksz = (int)str_offt(optarg)) <= 0) { - paxwarn(1, "Invalid block size %s", optarg); - pax_usage(); - } - break; - case 'c': - /* - * inverse match on patterns - */ - cflag = 1; - flg |= CF; - break; - case 'd': - /* - * match only dir on extract, not the subtree at dir - */ - dflag = 1; - flg |= DF; - break; - case 'f': - /* - * filename where the archive is stored - */ - arcname = optarg; - flg |= FF; - break; - case 'i': - /* - * interactive file rename - */ - iflag = 1; - flg |= IF; - break; - case 'k': - /* - * do not clobber files that exist - */ - kflag = 1; - flg |= KF; - break; - case 'l': - /* - * try to link src to dest with copy (-rw) - */ - lflag = 1; - flg |= LF; - break; - case 'n': - /* - * select first match for a pattern only - */ - nflag = 1; - flg |= NF; - break; - case 'o': - /* - * pass format specific options - */ - flg |= OF; - if (opt_add(optarg) < 0) - pax_usage(); - break; - case 'p': - /* - * specify file characteristic options - */ - for (pt = optarg; *pt != '\0'; ++pt) { - switch(*pt) { - case 'a': - /* - * do not preserve access time - */ - patime = 0; - break; - case 'e': - /* - * preserve user id, group id, file - * mode, access/modification times - */ - pids = 1; - pmode = 1; - patime = 1; - pmtime = 1; - break; - case 'm': - /* - * do not preserve modification time - */ - pmtime = 0; - break; - case 'o': - /* - * preserve uid/gid - */ - pids = 1; - break; - case 'p': - /* - * preserver file mode bits - */ - pmode = 1; - break; - default: - paxwarn(1, "Invalid -p string: %c", *pt); - pax_usage(); - break; - } - } - flg |= PF; - break; - case 'r': - /* - * read the archive - */ - flg |= RF; - break; - case 's': - /* - * file name substitution name pattern - */ - if (rep_add(optarg) < 0) { - pax_usage(); - break; - } - flg |= SF; - break; - case 't': - /* - * preserve access time on file system nodes we read - */ - tflag = 1; - flg |= TF; - break; - case 'u': - /* - * ignore those older files - */ - uflag = 1; - flg |= UF; - break; - case 'v': - /* - * verbose operation mode - */ - vflag = 1; - flg |= VF; - break; - case 'w': - /* - * write an archive - */ - flg |= WF; - break; - case 'x': - /* - * 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) { - flg |= XF; - break; - } - paxwarn(1, "Unknown -x format: %s", optarg); - (void)fputs("pax: Known -x formats are:", stderr); - for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i) - (void)fprintf(stderr, " %s", fsub[i].name); - (void)fputs("\n\n", stderr); - pax_usage(); - break; - case 'z': - /* - * use gzip. Non standard option. - */ - gzip_program = GZIP_CMD; - break; - case 'B': - /* - * non-standard option on number of bytes written on a - * single archive volume. - */ - if ((wrlimit = str_offt(optarg)) <= 0) { - paxwarn(1, "Invalid write limit %s", optarg); - pax_usage(); - } - if (wrlimit % BLKMULT) { - paxwarn(1, "Write limit is not a %d byte multiple", - BLKMULT); - pax_usage(); - } - flg |= CBF; - break; - case 'D': - /* - * On extraction check file inode change time before the - * modification of the file name. Non standard option. - */ - Dflag = 1; - flg |= CDF; - break; - case 'E': - /* - * non-standard limit on read faults - * 0 indicates stop after first error, values - * indicate a limit, "NONE" try forever - */ - flg |= CEF; - if (strcmp(NONE, optarg) == 0) - maxflt = -1; - else if ((maxflt = atoi(optarg)) < 0) { - paxwarn(1, "Error count value must be positive"); - pax_usage(); - } - break; - case 'G': - /* - * non-standard option for selecting files within an - * archive by group (gid or name) - */ - if (grp_add(optarg) < 0) { - pax_usage(); - break; - } - flg |= CGF; - break; - case 'H': - /* - * follow command line symlinks only - */ - Hflag = 1; - flg |= CHF; - break; - case 'L': - /* - * follow symlinks - */ - Lflag = 1; - flg |= CLF; - break; - case 'P': - /* - * do NOT follow symlinks (default) - */ - Lflag = 0; - flg |= CPF; - break; - case 'T': - /* - * non-standard option for selecting files within an - * archive by modification time range (lower,upper) - */ - if (trng_add(optarg) < 0) { - pax_usage(); - break; - } - flg |= CTF; - break; - case 'U': - /* - * non-standard option for selecting files within an - * archive by user (uid or name) - */ - if (usr_add(optarg) < 0) { - pax_usage(); - break; - } - flg |= CUF; - break; - case 'X': - /* - * do not pass over mount points in the file system - */ - Xflag = 1; - flg |= CXF; - break; - case 'Y': - /* - * On extraction check file inode change time after the - * modification of the file name. Non standard option. - */ - Yflag = 1; - flg |= CYF; - break; - case 'Z': - /* - * On extraction check modification time after the - * modification of the file name. Non standard option. - */ - Zflag = 1; - flg |= CZF; - break; - default: - pax_usage(); - break; - } - } - - /* - * figure out the operation mode of pax read,write,extract,copy,append - * or list. check that we have not been given a bogus set of flags - * for the operation mode. - */ - if (ISLIST(flg)) { - act = LIST; - listf = stdout; - bflg = flg & BDLIST; - } else if (ISEXTRACT(flg)) { - act = EXTRACT; - bflg = flg & BDEXTR; - } else if (ISARCHIVE(flg)) { - act = ARCHIVE; - bflg = flg & BDARCH; - } else if (ISAPPND(flg)) { - act = APPND; - bflg = flg & BDARCH; - } else if (ISCOPY(flg)) { - act = COPY; - bflg = flg & BDCOPY; - } else - pax_usage(); - if (bflg) { - printflg(flg); - pax_usage(); - } - - /* - * if we are writing (ARCHIVE) we use the default format if the user - * did not specify a format. when we write during an APPEND, we will - * adopt the format of the existing archive if none was supplied. - */ - if (!(flg & XF) && (act == ARCHIVE)) - frmt = &(fsub[DEFLT]); - - /* - * process the args as they are interpreted by the operation mode - */ - switch (act) { - case LIST: - case EXTRACT: - for (; optind < argc; optind++) - if (pat_add(argv[optind], NULL) < 0) - pax_usage(); - break; - case COPY: - if (optind >= argc) { - paxwarn(0, "Destination directory was not supplied"); - pax_usage(); - } - --argc; - dirptr = argv[argc]; - /* FALLTHROUGH */ - case ARCHIVE: - case APPND: - for (; optind < argc; optind++) - if (ftree_add(argv[optind], 0) < 0) - pax_usage(); - /* - * no read errors allowed on updates/append operation! - */ - maxflt = 0; - break; - } -} - -static void -tar_set_action(int op) -{ - if (act != ERROR && act != op) - tar_usage(); - act = op; -} - -/* - * tar_options() - * look at the user specified flags. set globals as required and check if - * the user specified a legal set of flags. If not, complain and exit - */ - -static void -tar_options(int argc, char **argv) -{ - 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; - - /* - * process option flags - */ - while ((c = getoldopt(argc, argv, - "b:cef:hjmopqruts:vwxyzBC:HI:LOPXZ014578")) != -1) { - switch(c) { - case 'b': - /* - * specify blocksize in 512-byte blocks - */ - if ((wrblksz = (int)str_offt(optarg)) <= 0) { - paxwarn(1, "Invalid block size %s", optarg); - tar_usage(); - } - wrblksz *= 512; /* XXX - check for int oflow */ - break; - case 'c': - /* - * create an archive - */ - tar_set_action(ARCHIVE); - break; - case 'e': - /* - * stop after first error - */ - maxflt = 0; - break; - case 'f': - /* - * filename where the archive is stored - */ - if ((optarg[0] == '-') && (optarg[1]== '\0')) { - /* - * treat a - as stdin - */ - fstdin = 1; - arcname = NULL; - break; - } - fstdin = 0; - 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': - /* - * do not preserve modification time - */ - pmtime = 0; - break; - case 'o': - if (opt_add("write_opt=nodir") < 0) - tar_usage(); - case 'O': - Oflag = 1; - break; - case 'p': - /* - * preserve uid/gid and file mode, regardless of umask - */ - pmode = 1; - pids = 1; - break; - case 'q': - /* - * select first match for a pattern only - */ - nflag = 1; - break; - case 'r': - case 'u': - /* - * append to the archive - */ - tar_set_action(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 - */ - tar_set_action(LIST); - break; - case 'v': - /* - * verbose operation mode - */ - vflag++; - break; - case 'w': - /* - * interactive file rename - */ - iflag = 1; - break; - case 'x': - /* - * extract an archive, preserving mode, - * and mtime if possible. - */ - tar_set_action(EXTRACT); - pmtime = 1; - break; - case 'z': - /* - * use gzip. Non standard option. - */ - gzip_program = GZIP_CMD; - break; - case 'B': - /* - * 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 - */ - Lflag = 1; - break; - case 'P': - /* - * do not remove leading '/' from pathnames - */ - rmleadslash = 0; - break; - case 'X': - /* - * do not pass over mount points in the file system - */ - Xflag = 1; - break; - case 'Z': - /* - * use compress. - */ - gzip_program = COMPRESS_CMD; - break; - case '0': - arcname = DEV_0; - break; - case '1': - arcname = DEV_1; - break; - case '4': - arcname = DEV_4; - break; - case '5': - arcname = DEV_5; - break; - case '7': - arcname = DEV_7; - break; - case '8': - arcname = DEV_8; - break; - default: - tar_usage(); - break; - } - } - argc -= optind; - argv += optind; - - /* Tar requires an action. */ - if (act == ERROR) - tar_usage(); - - /* 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 || 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 - */ - switch (act) { - case LIST: - case EXTRACT: - default: - { - 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: - 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! - */ - maxflt = 0; - break; - } - if (!fstdin && ((arcname == NULL) || (*arcname == '\0'))) { - arcname = getenv("TAPE"); - if ((arcname == NULL) || (*arcname == '\0')) - arcname = _PATH_DEFTAPE; - } -} - -static int -mkpath(char *path) -{ - struct stat sb; - 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 - * the user specified a legal set of flags. If not, complain and exit - */ - -static void -cpio_options(int argc, char **argv) -{ - int c; - size_t 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; - /* FALLTHROUGH */ - 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, 0); - } - if (getline_error) { - paxwarn(1, "Problem while reading stdin"); - cpio_usage(); - } - break; - default: - cpio_usage(); - break; - } -} - -/* - * printflg() - * print out those invalid flag sets found to the user - */ - -static void -printflg(unsigned int flg) -{ - int nxt; - int pos = 0; - - (void)fprintf(stderr,"%s: Invalid combination of options:", argv0); - while ((nxt = ffs(flg)) != 0) { - flg = flg >> nxt; - pos += nxt; - (void)fprintf(stderr, " -%c", flgch[pos-1]); - } - (void)putc('\n', stderr); -} - -/* - * c_frmt() - * comparison routine used by bsearch to find the format specified - * by the user - */ - -static int -c_frmt(const void *a, const void *b) -{ - return(strcmp(((const FSUB *)a)->name, ((const FSUB *)b)->name)); -} - -/* - * opt_next() - * called by format specific options routines to get each format specific - * flag and value specified with -o - * Return: - * pointer to next OPLIST entry or NULL (end of list). - */ - -OPLIST * -opt_next(void) -{ - OPLIST *opt; - - if ((opt = ophead) != NULL) - ophead = ophead->fow; - return(opt); -} - -/* - * bad_opt() - * generic routine used to complain about a format specific options - * when the format does not support options. - */ - -int -bad_opt(void) -{ - OPLIST *opt; - - if (ophead == NULL) - return(0); - /* - * print all we were given - */ - paxwarn(1,"These format options are not supported"); - while ((opt = opt_next()) != NULL) - (void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value); - pax_usage(); - return(0); -} - -/* - * opt_add() - * breaks the value supplied to -o into an option name and value. Options - * are given to -o in the form -o name-value,name=value - * multiple -o may be specified. - * Return: - * 0 if format in name=value format, -1 if -o is passed junk. - */ - -int -opt_add(const char *str) -{ - OPLIST *opt; - char *frpt; - char *pt; - char *endpt; - char *lstr; - - if ((str == NULL) || (*str == '\0')) { - paxwarn(0, "Invalid option name"); - return(-1); - } - if ((lstr = strdup(str)) == NULL) { - paxwarn(0, "Unable to allocate space for option list"); - return(-1); - } - frpt = endpt = lstr; - - /* - * break into name and values pieces and stuff each one into a - * OPLIST structure. When we know the format, the format specific - * option function will go through this list - */ - while ((frpt != NULL) && (*frpt != '\0')) { - if ((endpt = strchr(frpt, ',')) != NULL) - *endpt = '\0'; - if ((pt = strchr(frpt, '=')) == NULL) { - paxwarn(0, "Invalid options format"); - free(lstr); - return(-1); - } - if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) { - paxwarn(0, "Unable to allocate space for option list"); - free(lstr); - return(-1); - } - *pt++ = '\0'; - opt->name = frpt; - opt->value = pt; - opt->fow = NULL; - if (endpt != NULL) - frpt = endpt + 1; - else - frpt = NULL; - if (ophead == NULL) { - optail = ophead = opt; - continue; - } - optail->fow = opt; - optail = opt; - } - return(0); -} - -/* - * str_offt() - * Convert an expression of the following forms to an off_t > 0. - * 1) A positive decimal number. - * 2) A positive decimal number followed by a b (mult by 512). - * 3) A positive decimal number followed by a k (mult by 1024). - * 4) A positive decimal number followed by a m (mult by 512). - * 5) A positive decimal number followed by a w (mult by sizeof int) - * 6) Two or more positive decimal numbers (with/without k,b or w). - * separated by x (also * for backwards compatibility), specifying - * the product of the indicated values. - * Return: - * 0 for an error, a positive value o.w. - */ - -static off_t -str_offt(char *val) -{ - char *expr; - off_t num, t; - -# ifdef NET2_STAT - num = strtol(val, &expr, 0); - if ((num == LONG_MAX) || (num <= 0) || (expr == val)) -# else - num = strtoq(val, &expr, 0); - if ((num == QUAD_MAX) || (num <= 0) || (expr == val)) -# endif - return(0); - - switch(*expr) { - case 'b': - t = num; - num *= 512; - if (t > num) - return(0); - ++expr; - break; - case 'k': - t = num; - num *= 1024; - if (t > num) - return(0); - ++expr; - break; - case 'm': - t = num; - num *= 1048576; - if (t > num) - return(0); - ++expr; - break; - case 'w': - t = num; - num *= sizeof(int); - if (t > num) - return(0); - ++expr; - break; - } - - switch(*expr) { - case '\0': - break; - case '*': - case 'x': - t = num; - num *= str_offt(expr + 1); - if (t > num) - return(0); - break; - default: - return(0); - } - return(num); -} - -char *fgetln(FILE *f, size_t *); - -static char * -getline(FILE *f) -{ - 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. - * Return: - * 0 - */ - -static int -no_op(void) -{ - return(0); -} - -/* - * pax_usage() - * print the usage summary to the user - */ - -static void -pax_usage(void) -{ - (void)fputs("usage: pax [-cdnvz] [-E limit] [-f archive] ", stderr); - (void)fputs("[-s replstr] ... [-U user] ...", stderr); - (void)fputs("\n [-G group] ... ", stderr); - (void)fputs("[-T [from_date][,to_date]] ... ", stderr); - (void)fputs("[pattern ...]\n", stderr); - (void)fputs(" pax -r [-cdiknuvzDYZ] [-E limit] ", stderr); - (void)fputs("[-f archive] [-o options] ... \n", stderr); - (void)fputs(" [-p string] ... [-s replstr] ... ", stderr); - (void)fputs("[-U user] ... [-G group] ...\n ", stderr); - (void)fputs("[-T [from_date][,to_date]] ... ", stderr); - (void)fputs(" [pattern ...]\n", stderr); - (void)fputs(" pax -w [-dituvzHLPX] [-b blocksize] ", stderr); - (void)fputs("[ [-a] [-f archive] ] [-x format] \n", stderr); - (void)fputs(" [-B bytes] [-s replstr] ... ", stderr); - (void)fputs("[-o options] ... [-U user] ...", stderr); - (void)fputs("\n [-G group] ... ", stderr); - (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr); - (void)fputs("[file ...]\n", stderr); - (void)fputs(" pax -r -w [-diklntuvDHLPXYZ] ", stderr); - (void)fputs("[-p string] ... [-s replstr] ...", stderr); - (void)fputs("\n [-U user] ... [-G group] ... ", stderr); - (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr); - (void)fputs("\n [file ...] directory\n", stderr); - exit(1); -} - -/* - * tar_usage() - * print the usage summary to the user - */ - -static void -tar_usage(void) -{ - (void)fputs("usage: tar [-]{crtux}[-befhjmopqsvwyzHLOPXZ014578] [blocksize] ", - stderr); - (void)fputs("[archive] [replstr] [-C directory] [-I file] [file ...]\n", - stderr); - exit(1); -} - -/* - * cpio_usage() - * print the usage summary to the user - */ - -static void -cpio_usage(void) -{ - (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); -} diff --git a/lib/Makefile b/lib/Makefile index cf2ccbc8e..ffd66a9ec 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,7 +9,7 @@ SUBDIR+= libcompat_minix libc libblockdriver libchardriver \ libz libfetch libvtreefs libaudiodriver libmthread \ libexec libdevman libusb libminlib libasyn \ libddekit libminixfs libbdev libelf libminc libcrypt libterminfo \ - libvassert libutil libbz2 libprop \ + libvassert libutil libbz2 libprop librmt \ libnetsock libpuffs libsffs libhgfs libvboxfs SUBDIR+= ../external/public-domain/xz/lib diff --git a/lib/librmt/Makefile b/lib/librmt/Makefile new file mode 100644 index 000000000..f518f54bd --- /dev/null +++ b/lib/librmt/Makefile @@ -0,0 +1,16 @@ +# $NetBSD: Makefile,v 1.9 2007/05/28 12:06:21 tls Exp $ + +.ifndef __MINIX +USE_FORT?= yes # network protocol library +.endif + +NOPIC= # defined +NOPROFILE= # defined + +LIB= rmt +SRCS= rmtlib.c +MAN= rmtops.3 + +CPPFLAGS+= -D_REENTRANT + +.include diff --git a/lib/librmt/README b/lib/librmt/README new file mode 100644 index 000000000..9191077c7 --- /dev/null +++ b/lib/librmt/README @@ -0,0 +1,20 @@ +# $NetBSD: README,v 1.2 1998/01/09 04:12:19 perry Exp $ + +README + +This is the remote mag tape library. It allows a program that uses +Unix system calls to transparently use a file (usually a tape drive) on +another system via /etc/rmt, simply by including . It is +particularly useful with tar and dd, and is supplied with GNU tar. + +This package has evolved somewhat over the years. My thanks to the +people who did most of the original work, and those who've contributed +bug fixes; appropriate credit is in the man page and source files. + +Enjoy, + +Arnold Robbins +Emory U. Computing Center +arnold@emoryu1.cc.emory.edu +gatech!emoryu1!arnold ++1 404 727 7636 diff --git a/lib/librmt/pathnames.h b/lib/librmt/pathnames.h new file mode 100644 index 000000000..ec1757863 --- /dev/null +++ b/lib/librmt/pathnames.h @@ -0,0 +1,30 @@ +/* $NetBSD: pathnames.h,v 1.2 2008/05/29 14:51:25 mrg Exp $ */ + +/* + * Copyright (c) 1998 Matthew R. Green + * 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. + * + * 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. + */ + +#define _PATH_RSH "/usr/bin/rsh" +#define _PATH_RMT "/etc/rmt" diff --git a/lib/librmt/rmtlib.c b/lib/librmt/rmtlib.c new file mode 100644 index 000000000..cadeab398 --- /dev/null +++ b/lib/librmt/rmtlib.c @@ -0,0 +1,896 @@ +/* $NetBSD: rmtlib.c,v 1.26 2012/03/21 10:10:37 matt Exp $ */ + +/* + * rmt --- remote tape emulator subroutines + * + * Originally written by Jeff Lee, modified some by Arnold Robbins + * + * WARNING: The man page rmt(8) for /etc/rmt documents the remote mag + * tape protocol which rdump and rrestore use. Unfortunately, the man + * page is *WRONG*. The author of the routines I'm including originally + * wrote his code just based on the man page, and it didn't work, so he + * went to the rdump source to figure out why. The only thing he had to + * change was to check for the 'F' return code in addition to the 'E', + * and to separate the various arguments with \n instead of a space. I + * personally don't think that this is much of a problem, but I wanted to + * point it out. + * -- Arnold Robbins + * + * Redone as a library that can replace open, read, write, etc, by + * Fred Fish, with some additional work by Arnold Robbins. + */ + +/* + * MAXUNIT --- Maximum number of remote tape file units + * + * READ --- Return the number of the read side file descriptor + * WRITE --- Return the number of the write side file descriptor + */ + +#include +__RCSID("$NetBSD: rmtlib.c,v 1.26 2012/03/21 10:10:37 matt Exp $"); + +#define RMTIOCTL 1 +/* #define USE_REXEC 1 */ /* rexec code courtesy of Dan Kegel, srs!dan */ + +#include +#include + +#ifdef RMTIOCTL +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_REXEC +#include +#endif + +#define __RMTLIB_PRIVATE +#include /* get prototypes for remapped functions */ + +#include "pathnames.h" + +static int _rmt_close(int); +static int _rmt_ioctl(int, unsigned long, void *); +static off_t _rmt_lseek(int, off_t, int); +static int _rmt_open(const char *, int, int); +static ssize_t _rmt_read(int, void *, size_t); +static ssize_t _rmt_write(int, const void *, size_t); +static int command(int, const char *); +static int remdev(const char *); +static void rmtabort(int); +static int status(int); + + +#define BUFMAGIC 64 /* a magic number for buffer sizes */ +#define MAXUNIT 4 + +#define READ(fd) (Ctp[fd][0]) +#define WRITE(fd) (Ptc[fd][1]) + +static int Ctp[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} }; +static int Ptc[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} }; + + +/* + * rmtabort --- close off a remote tape connection + */ +static void +rmtabort(int fildes) +{ + + close(READ(fildes)); + close(WRITE(fildes)); + READ(fildes) = -1; + WRITE(fildes) = -1; +} + + +/* + * command --- attempt to perform a remote tape command + */ +static int +command(int fildes, const char *buf) +{ + size_t blen; + sig_t pstat; + + _DIAGASSERT(buf != NULL); + +/* + * save current pipe status and try to make the request + */ + + blen = strlen(buf); + pstat = signal(SIGPIPE, SIG_IGN); + if ((size_t)write(WRITE(fildes), buf, blen) == blen) { + signal(SIGPIPE, pstat); + return 0; + } + +/* + * something went wrong. close down and go home + */ + + signal(SIGPIPE, pstat); + rmtabort(fildes); + + errno = EIO; + return -1; +} + + +/* + * status --- retrieve the status from the pipe + */ +static int +status(int fildes) +{ + int i; + char c, *cp; + char buffer[BUFMAGIC]; + +/* + * read the reply command line + */ + + for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++) { + if (read(READ(fildes), cp, 1) != 1) { + rmtabort(fildes); + errno = EIO; + return -1; + } + if (*cp == '\n') { + *cp = 0; + break; + } + } + + if (i == BUFMAGIC) { + rmtabort(fildes); + errno = EIO; + return -1; + } + +/* + * check the return status + */ + + for (cp = buffer; *cp; cp++) + if (*cp != ' ') + break; + + if (*cp == 'E' || *cp == 'F') { + errno = atoi(cp + 1); + while (read(READ(fildes), &c, 1) == 1) + if (c == '\n') + break; + + if (*cp == 'F') + rmtabort(fildes); + + return -1; + } + +/* + * check for mis-synced pipes + */ + + if (*cp != 'A') { + rmtabort(fildes); + errno = EIO; + return -1; + } + + return atoi(cp + 1); +} + + +#ifdef USE_REXEC +/* + * _rmt_rexec + * + * execute /etc/rmt on a remote system using rexec(). + * Return file descriptor of bidirectional socket for stdin and stdout + * If username is NULL, or an empty string, uses current username. + * + * ADR: By default, this code is not used, since it requires that + * the user have a .netrc file in his/her home directory, or that the + * application designer be willing to have rexec prompt for login and + * password info. This may be unacceptable, and .rhosts files for use + * with rsh are much more common on BSD systems. + */ + +static int _rmt_rexec(const char *, const char *); + +static int +_rmt_rexec(const char *host, const char *user) +{ + struct servent *rexecserv; + + _DIAGASSERT(host != NULL); + /* user may be NULL */ + + rexecserv = getservbyname("exec", "tcp"); + if (rexecserv == NULL) + errx(1, "exec/tcp: service not available."); + if ((user != NULL) && *user == '\0') + user = NULL; + return rexec(&host, rexecserv->s_port, user, NULL, + "/etc/rmt", NULL); +} +#endif /* USE_REXEC */ + + +/* + * _rmt_open --- open a magtape device on system specified, as given user + * + * file name has the form [user@]system:/dev/???? +#ifdef COMPAT + * file name has the form system[.user]:/dev/???? +#endif + */ + +#define MAXHOSTLEN 257 /* BSD allows very long host names... */ + +static int +/*ARGSUSED*/ +_rmt_open(const char *path, int oflag, int mode) +{ + int i; + char buffer[BUFMAGIC]; + char host[MAXHOSTLEN]; + char device[BUFMAGIC]; + char login[BUFMAGIC]; + char *sys, *dev, *user; + const char *rshpath, *rsh; + + _DIAGASSERT(path != NULL); + + sys = host; + dev = device; + user = login; + +/* + * first, find an open pair of file descriptors + */ + + for (i = 0; i < MAXUNIT; i++) + if (READ(i) == -1 && WRITE(i) == -1) + break; + + if (i == MAXUNIT) { + errno = EMFILE; + return -1; + } + +/* + * pull apart system and device, and optional user + * don't munge original string + * if COMPAT is defined, also handle old (4.2) style person.site notation. + */ + + while (*path != '@' +#ifdef COMPAT + && *path != '.' +#endif + && *path != ':') { + *sys++ = *path++; + } + *sys = '\0'; + path++; + + if (*(path - 1) == '@') { + (void)strncpy(user, host, sizeof(login) - 1); + /* saw user part of user@host */ + sys = host; /* start over */ + while (*path != ':') { + *sys++ = *path++; + } + *sys = '\0'; + path++; + } +#ifdef COMPAT + else if (*(path - 1) == '.') { + while (*path != ':') { + *user++ = *path++; + } + *user = '\0'; + path++; + } +#endif + else + *user = '\0'; + + while (*path) { + *dev++ = *path++; + } + *dev = '\0'; + +#ifdef USE_REXEC +/* + * Execute the remote command using rexec + */ + READ(i) = WRITE(i) = _rmt_rexec(host, login); + if (READ(i) < 0) + return -1; +#else +/* + * setup the pipes for the 'rsh' command and fork + */ + + if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1) + return -1; + + switch (fork()) { + case -1: + return -1; + + case 0: + close(0); + dup(Ptc[i][0]); + close(Ptc[i][0]); close(Ptc[i][1]); + close(1); + dup(Ctp[i][1]); + close(Ctp[i][0]); close(Ctp[i][1]); + (void) setuid(getuid()); + (void) setgid(getgid()); + + if ((rshpath = getenv("RCMD_CMD")) == NULL) + rshpath = _PATH_RSH; + if ((rsh = strrchr(rshpath, '/')) == NULL) + rsh = rshpath; + else + rsh++; + + if (*login) { + execl(rshpath, rsh, host, "-l", login, _PATH_RMT, NULL); + } else { + execl(rshpath, rsh, host, _PATH_RMT, NULL); + } + +/* + * bad problems if we get here + */ + + err(1, "Cannnot exec %s", rshpath); + /*FALLTHROUGH*/ + default: + break; + } + + close(Ptc[i][0]); close(Ctp[i][1]); +#endif + +/* + * now attempt to open the tape device + */ + + (void)snprintf(buffer, sizeof(buffer), "O%s\n%d\n", device, oflag); + if (command(i, buffer) == -1 || status(i) == -1) + return -1; + + return i; +} + + +/* + * _rmt_close --- close a remote magtape unit and shut down + */ +static int +_rmt_close(int fildes) +{ + int rc; + + if (command(fildes, "C\n") != -1) { + rc = status(fildes); + + rmtabort(fildes); + return rc; + } + + return -1; +} + + +/* + * _rmt_read --- read a buffer from a remote tape + */ +static ssize_t +_rmt_read(int fildes, void *buf, size_t nbyte) +{ + size_t rc; + int rv; + ssize_t nread; + char *p; + char buffer[BUFMAGIC]; + + _DIAGASSERT(buf != NULL); + + (void)snprintf(buffer, sizeof buffer, "R%zu\n", nbyte); + if (command(fildes, buffer) == -1 || (rv = status(fildes)) == -1) + return -1; + + if (rv > (int)nbyte) + rv = (int)nbyte; + + for (rc = rv, p = buf; rc > 0; rc -= nread, p += nread) { + if ((nread = read(READ(fildes), p, rc)) <= 0) { + rmtabort(fildes); + errno = EIO; + return -1; + } + } + + return rv; +} + + +/* + * _rmt_write --- write a buffer to the remote tape + */ +static ssize_t +_rmt_write(int fildes, const void *buf, size_t nbyte) +{ + char buffer[BUFMAGIC]; + sig_t pstat; + + _DIAGASSERT(buf != NULL); + + (void)snprintf(buffer, sizeof buffer, "W%zu\n", nbyte); + if (command(fildes, buffer) == -1) + return -1; + + pstat = signal(SIGPIPE, SIG_IGN); + if ((size_t)write(WRITE(fildes), buf, nbyte) == nbyte) { + signal(SIGPIPE, pstat); + return status(fildes); + } + + signal(SIGPIPE, pstat); + rmtabort(fildes); + errno = EIO; + return -1; +} + + +/* + * _rmt_lseek --- perform an imitation lseek operation remotely + */ +static off_t +_rmt_lseek(int fildes, off_t offset, int whence) +{ + char buffer[BUFMAGIC]; + + /*LONGLONG*/ + (void)snprintf(buffer, sizeof buffer, "L%lld\n%d\n", (long long)offset, + whence); + if (command(fildes, buffer) == -1) + return -1; + + return status(fildes); +} + + +/* + * _rmt_ioctl --- perform raw tape operations remotely + */ +#ifdef RMTIOCTL +static int +_rmt_ioctl(int fildes, unsigned long op, void *arg) +{ + char c; + int rv; + size_t rc; + ssize_t cnt; + char buffer[BUFMAGIC], *p; + struct mtop *mtop = arg; + + _DIAGASSERT(arg != NULL); + +/* + * MTIOCOP is the easy one. nothing is transfered in binary + */ + + if (op == MTIOCTOP) { + (void)snprintf(buffer, sizeof buffer, "I%d\n%d\n", + mtop->mt_op, mtop->mt_count); + if (command(fildes, buffer) == -1) + return -1; + return status(fildes); + } + +/* + * we can only handle 2 ops, if not the other one, punt + */ + + if (op != MTIOCGET) { + errno = EINVAL; + return -1; + } + +/* + * grab the status and read it directly into the structure + * this assumes that the status buffer is (hopefully) not + * padded and that 2 shorts fit in a long without any word + * alignment problems, ie - the whole struct is contiguous + * NOTE - this is probably NOT a good assumption. + */ + + if (command(fildes, "S") == -1 || (rv = status(fildes)) == -1) + return -1; + + memset(arg, 0, sizeof(struct mtget)); + for (rc = rv, p = arg; rc > 0; rc -= cnt, p += cnt) { + if ((cnt = read(READ(fildes), p, rc)) <= 0) { + rmtabort(fildes); + errno = EIO; + return -1; + } + } + +/* + * now we check for byte position. mt_type is a small integer field + * (normally) so we will check its magnitude. if it is larger than + * 256, we will assume that the bytes are swapped and go through + * and reverse all the bytes + */ + + if (((struct mtget *)(void *)p)->mt_type < 256) + return 0; + + for (cnt = 0; cnt < rv; cnt += 2) { + c = p[cnt]; + p[cnt] = p[cnt + 1]; + p[cnt + 1] = c; + } + + return 0; +} +#endif /* RMTIOCTL */ + + +/* + * Added routines to replace open(), close(), lseek(), ioctl(), etc. + * The preprocessor can be used to remap these the rmtopen(), etc + * thus minimizing source changes: + * + * #ifdef + * # define access rmtaccess + * # define close rmtclose + * # define creat rmtcreat + * # define dup rmtdup + * # define fcntl rmtfcntl + * # define fstat rmtfstat + * # define ioctl rmtioctl + * # define isatty rmtisatty + * # define lseek rmtlseek + * # define lstat rmtlstat + * # define open rmtopen + * # define read rmtread + * # define stat rmtstat + * # define write rmtwrite + * #endif + * + * -- Fred Fish + * + * ADR --- I set up a include file for this + * + */ + +/* + * Note that local vs remote file descriptors are distinquished + * by adding a bias to the remote descriptors. This is a quick + * and dirty trick that may not be portable to some systems. + */ + +#define REM_BIAS 128 + + +/* + * Test pathname to see if it is local or remote. A remote device + * is any string that contains ":/dev/". Returns 1 if remote, + * 0 otherwise. + */ + +static int +remdev(const char *path) +{ + + _DIAGASSERT(path != NULL); + + if ((path = strchr(path, ':')) != NULL) { + if (strncmp(path + 1, "/dev/", 5) == 0) { + return 1; + } + } + return 0; +} + + +/* + * Open a local or remote file. Looks just like open(2) to + * caller. + */ +int +rmtopen(const char *path, int oflag, ...) +{ + mode_t mode; + int fd; + va_list ap; + va_start(ap, oflag); + + mode = va_arg(ap, mode_t); + va_end(ap); + + _DIAGASSERT(path != NULL); + + if (remdev(path)) { + fd = _rmt_open(path, oflag, (int)mode); + + return (fd == -1) ? -1 : (fd + REM_BIAS); + } else { + return open(path, oflag, mode); + } +} + +/* + * Test pathname for specified access. Looks just like access(2) + * to caller. + */ + +int +rmtaccess(const char *path, int amode) +{ + + _DIAGASSERT(path != NULL); + + if (remdev(path)) { + return 0; /* Let /etc/rmt find out */ + } else { + return access(path, amode); + } +} + + +/* + * Isrmt. Let a programmer know he has a remote device. + */ +int +isrmt(int fd) +{ + int unbias = fd - REM_BIAS; + + return (fd >= REM_BIAS) && unbias < MAXUNIT && + (WRITE(unbias) != -1 || READ(unbias) != -1); +} + + +/* + * Read from stream. Looks just like read(2) to caller. + */ +ssize_t +rmtread(int fildes, void *buf, size_t nbyte) +{ + + _DIAGASSERT(buf != NULL); + + if (isrmt(fildes)) { + return _rmt_read(fildes - REM_BIAS, buf, nbyte); + } else { + return read(fildes, buf, nbyte); + } +} + + +/* + * Write to stream. Looks just like write(2) to caller. + */ +ssize_t +rmtwrite(int fildes, const void *buf, size_t nbyte) +{ + + _DIAGASSERT(buf != NULL); + + if (isrmt(fildes)) { + return _rmt_write(fildes - REM_BIAS, buf, nbyte); + } else { + return write(fildes, buf, nbyte); + } +} + +/* + * Perform lseek on file. Looks just like lseek(2) to caller. + */ +off_t +rmtlseek(int fildes, off_t offset, int whence) +{ + + if (isrmt(fildes)) { + return _rmt_lseek(fildes - REM_BIAS, offset, whence); + } else { + return lseek(fildes, offset, whence); + } +} + + +/* + * Close a file. Looks just like close(2) to caller. + */ +int +rmtclose(int fildes) +{ + + if (isrmt(fildes)) { + return _rmt_close(fildes - REM_BIAS); + } else { + return close(fildes); + } +} + + +/* + * Do ioctl on file. Looks just like ioctl(2) to caller. + */ +int +rmtioctl(int fildes, unsigned long request, ...) +{ + void *arg; + va_list ap; + va_start(ap, request); + + arg = va_arg(ap, void *); + va_end(ap); + + /* XXX: arg may be NULL ? */ + + if (isrmt(fildes)) { +#ifdef RMTIOCTL + return _rmt_ioctl(fildes - REM_BIAS, request, arg); +#else + errno = EOPNOTSUPP; + return -1; /* For now (fnf) */ +#endif + } else { + return ioctl(fildes, request, arg); + } +} + + +/* + * Duplicate an open file descriptor. Looks just like dup(2) + * to caller. + */ +int +rmtdup(int fildes) +{ + + if (isrmt(fildes)) { + errno = EOPNOTSUPP; + return -1; /* For now (fnf) */ + } else { + return dup(fildes); + } +} + + +/* + * Get file status. Looks just like fstat(2) to caller. + */ +int +rmtfstat(int fildes, struct stat *buf) +{ + + _DIAGASSERT(buf != NULL); + + if (isrmt(fildes)) { + errno = EOPNOTSUPP; + return -1; /* For now (fnf) */ + } else { + return fstat(fildes, buf); + } +} + + +/* + * Get file status. Looks just like stat(2) to caller. + */ +int +rmtstat(const char *path, struct stat *buf) +{ + + _DIAGASSERT(path != NULL); + _DIAGASSERT(buf != NULL); + + if (remdev(path)) { + errno = EOPNOTSUPP; + return -1; /* For now (fnf) */ + } else { + return stat(path, buf); + } +} + + +/* + * Create a file from scratch. Looks just like creat(2) to the caller. + */ +int +rmtcreat(const char *path, mode_t mode) +{ + + _DIAGASSERT(path != NULL); + + if (remdev(path)) { + return rmtopen(path, O_WRONLY | O_CREAT, mode); + } else { + return open(path, O_CREAT | O_TRUNC | O_WRONLY, mode); + } +} + + +/* + * Rmtfcntl. Do a remote fcntl operation. + */ +int +rmtfcntl(int fd, int cmd, ...) +{ + void *arg; + va_list ap; + va_start(ap, cmd); + + arg = va_arg(ap, void *); + va_end(ap); + + /* XXX: arg may be NULL ? */ + + if (isrmt(fd)) { + errno = EOPNOTSUPP; + return -1; + } else { + return fcntl(fd, cmd, arg); + } +} + + +/* + * Rmtisatty. Do the isatty function. + */ +int +rmtisatty(int fd) +{ + + if (isrmt(fd)) + return 0; + else + return isatty(fd); +} + + +/* + * Get file status, even if symlink. Looks just like lstat(2) to caller. + */ +int +rmtlstat(const char *path, struct stat *buf) +{ + + _DIAGASSERT(path != NULL); + _DIAGASSERT(buf != NULL); + + if (remdev(path)) { + errno = EOPNOTSUPP; + return -1; /* For now (fnf) */ + } else { + return lstat(path, buf); + } +} diff --git a/lib/librmt/rmtops.3 b/lib/librmt/rmtops.3 new file mode 100644 index 000000000..390d4527f --- /dev/null +++ b/lib/librmt/rmtops.3 @@ -0,0 +1,182 @@ +.\" $NetBSD: rmtops.3,v 1.14 2010/03/22 22:00:37 joerg Exp $ +.\" +.Dd October 16, 2001 +.Dt RMTOPS 3 +.Os +.Sh NAME +.Nm rmtops +.Nd access tape drives on remote machines +.Sh LIBRARY +Remote Magnetic Tape Library (librmt, -lrmt) +.Sh SYNOPSIS +.In rmt.h +.In sys/stat.h +.Ft int +.Fn isrmt "int fd" +.Ft int +.Fn rmtaccess "char *file" "int mode" +.Ft int +.Fn rmtclose "int fd" +.Ft int +.Fn rmtcreat "char *file" "int mode" +.Ft int +.Fn rmtdup "int fd" +.Ft int +.Fn rmtfcntl "int fd" "int cmd" "int arg" +.Ft int +.Fn rmtfstat "int fd" "struct stat *buf" +.Ft int +.Fn rmtioctl "int fd" "int request" "char *argp" +.Ft int +.Fn rmtisatty "int fd" +.Ft long +.Fn rmtlseek "int fd" "long offset" "int whence" +.Ft int +.Fn rmtlstat "char *file" "struct stat *buf" +.Ft int +.Fn rmtopen "char *file" "int flags" "int mode" +.Ft int +.Fn rmtread "int fd" "char *buf" "int nbytes" +.Ft int +.Fn rmtstat "char *file" "struct stat *buf" +.Ft int +.Fn rmtwrite "int fd" "char *buf" "int nbytes" +.Sh DESCRIPTION +The +.Nm +library provides a simple means of transparently accessing tape drives +on remote machines via +.Xr rsh 1 +and +.Xr rmt 8 . +These routines are used like their corresponding system calls, but +allow the user to open up a tape drive on a remote system on which he +or she has an account and the appropriate remote permissions. +.Pp +A remote tape drive file name has the form +.Dl [user@]hostname:/dev/??? +where +.Em system +is the remote system, +.Em /dev/??? +is the particular drive on the remote system (raw, blocked, rewinding, +non-rewinding, etc.), and the optional +.Em user +is the login name to be used on the remote system, if different from +the current user's login name. +.\" .Pp +.\" The library source code may be optionally compiled to recognize the +.\" old +.\" .Bx 4.2 , +.\" remote syntax +.\" .sp +.\" hostname[.user]:/dev/??? +.\" .sp +.\" By default, only the first form (introduced in +.\" .Bx 4.3 ) +.\" is recognized. +.Pp +For transparency, the user should include the file +.In rmt.h , +which has the following defines in it: +.Bd -literal +#define access rmtaccess +#define close rmtclose +#define creat rmtcreat +#define dup rmtdup +#define fcntl rmtfcntl +#define fstat rmtfstat +#define ioctl rmtioctl +#define isatty rmtisatty +#define lseek rmtlseek +#define lstat rmtlstat +#define open rmtopen +#define read rmtread +#define stat rmtstat +#define write rmtwrite +.Ed +.Pp +This allows the programmer to use +.Xr open 2 , +.Xr close 2 , +.Xr read 2 , +.Xr write 2 , +etc. in their normal fashion, with the +.Nm +routines taking care of differentiating between local and remote files. +This file should be included +.Em before +including the file +.Pa \*[Lt]sys/stat.h\*[Gt] , +since it redefines the identifier ``stat'' which is used to declare +objects of type +.Em "struct stat" . +.Pp +The routines differentiate between local and remote file descriptors +by adding a bias (currently 128) to the file descriptor of the pipe. +The programmer, if he or she must know if a file is remote, should use +.Fn isrmt . +.Sh ENVIRONMENT +The RCMD_CMD environment variable can be set to the name or pathname +of a program to use, instead of +.Pa /usr/bin/rsh , +and must have the same calling conventions as +.Xr rsh 1 . +.Sh FILES +.Bl -tag -width /usr/lib/librmt.a -compact +.It Pa /usr/lib/librmt.a +remote tape library +.El +.Sh DIAGNOSTICS +Several of these routines will return \-1 and set +.Va errno +to EOPNOTSUPP, if they are given a remote file name or a file descriptor +on an open remote file (e.g., +.Fn rmtdup ) . +.Sh SEE ALSO +.Xr rcp 1 , +.Xr rsh 1 , +.Xr rmt 8 +.Pp +And the appropriate system calls in section 2. +.\" .Sh CONFIGURATION OPTIONS +.\" The library may be compiled to allow the use of +.\" .Bx 4.2 -style +.\" remote file names. This is not recommended. +.\" .Pp +.\" By default, the library opens two pipes to +.\" .Xr rsh 1 . +.\" It may optionally be compiled to use +.\" .Xr rexec 3 , +.\" instead. Doing so requires the use of a +.\" .Em .netrc +.\" file in the user's home directory, or that the application designer be +.\" willing to have +.\" .Xr rexec 3 +.\" prompt the user for a login name and password on the remote host. +.Sh AUTHORS +Jeff Lee wrote the original routines for accessing tape drives via +.Xr rmt 8 . +.Pp +Fred Fish redid them into a general purpose library. +.Pp +Arnold Robbins added the ability to specify a user name on the remote +system, the +.Pa \*[Lt]rmt.h\*[Gt] +include file, this man page, cleaned up the library a little, and made +the appropriate changes for +.Bx 4.3 . +.Pp +Dan Kegel contributed the code to use the +.Xr rexec 3 +library routine. +.Sh BUGS +There is no way to use remote tape drives with +.Xr stdio 3 , +short of recompiling it entirely to use these routines. +.Pp +The +.Xr rmt 8 +protocol is not very capable. +In particular, it relies on TCP/IP sockets for error +free transmission, and does no data validation of its own. diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index b3b0ad478..199ea898e 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -2,6 +2,8 @@ # Timestamp in UTC,minixpath,netbsdpath # minixpath: path in Minix source tree (starting from /usr/src/) # netbsdpath: path in BSD source tree (starting from src/) +2012/10/17 12:00:00,lib/librmt +2012/10/17 12:00:00,bin/pax 2012/10/17 12:00:00,tools/mtree 2012/10/17 12:00:00,tools/cksum 2012/10/17 12:00:00,usr.bin/cksum diff --git a/tools/Makefile b/tools/Makefile index e83c4149e..27bafe67e 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -15,6 +15,7 @@ SUBDIR= host-mkdep .WAIT compat .WAIT \ .WAIT awk \ .WAIT tic \ .WAIT lex \ + .WAIT pax \ .WAIT gmake .WAIT gmp .WAIT mpfr .WAIT mpc .WAIT binutils .WAIT gcc \ cat file pwd_mkdb stat zic \ diff --git a/tools/pax/Makefile b/tools/pax/Makefile new file mode 100644 index 000000000..b6777f5a7 --- /dev/null +++ b/tools/pax/Makefile @@ -0,0 +1,6 @@ +# $NetBSD: Makefile,v 1.2 2002/12/08 20:20:04 thorpej Exp $ + +HOSTPROGNAME= ${_TOOL_PREFIX}pax +HOST_SRCDIR= bin/pax + +.include "${.CURDIR}/../Makefile.host" -- 2.44.0