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