Upgrading pax.

This also means importing librmt.

Change-Id: Ie5b314aeaad28dca46acb64f20f2d70746ea52d0
This commit is contained in:
Lionel Sambuc 2012-10-22 16:10:38 +02:00
parent 6ab1df59f6
commit 85fee539f4
46 changed files with 7804 additions and 4741 deletions

View file

@ -2,6 +2,6 @@
.include <bsd.own.mk>
SUBDIR= cat date ed mkdir rm rmdir
SUBDIR= cat date ed mkdir pax rm rmdir
.include <bsd.subdir.mk>

61
bin/pax/Makefile Normal file
View file

@ -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 <bsd.own.mk>
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 <bsd.prog.mk>

File diff suppressed because it is too large Load diff

View file

@ -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 <sys/cdefs.h>
#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 <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <signal.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#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,10 +440,15 @@ 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;
}

View file

@ -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 <sys/cdefs.h>
#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 <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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,13 +291,13 @@ 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;
}
/*
@ -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;
}

View file

@ -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

View file

@ -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 <sys/cdefs.h>
#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 <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
@ -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,
arcn->sb.st_size = (off_t)ASC_OFFT(hd->c_filesize,
sizeof(hd->c_filesize), HEX);
#else
arcn->sb.st_size = (off_t)asc_uqd(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) ||
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),
HEX) ||
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),
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_gid, hd->c_gid, sizeof(hd->c_gid),
HEX) ||
ul_asc((u_long)minor(arcn->sb.st_dev),hd->c_min, sizeof(hd->c_min),
u32_asc((uintmax_t)arcn->sb.st_mtime, hd->c_mtime, sizeof(hd->c_mtime),
HEX) ||
ul_asc((u_long)major(arcn->sb.st_rdev),hd->c_rmaj,sizeof(hd->c_maj),
u32_asc((uintmax_t)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
HEX) ||
ul_asc((u_long)minor(arcn->sb.st_rdev),hd->c_rmin,sizeof(hd->c_min),
u32_asc((uintmax_t)MAJOR(arcn->sb.st_dev),hd->c_maj, sizeof(hd->c_maj),
HEX) ||
ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), HEX))
u32_asc((uintmax_t)MINOR(arcn->sb.st_dev),hd->c_min, sizeof(hd->c_min),
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;
}

View file

@ -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 $
*/
/*

122
bin/pax/dumptar.c Normal file
View file

@ -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 <stdio.h>
#include <err.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#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 <filename>\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;
}

View file

@ -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 <sys/cdefs.h>
#include <err.h>
/*
* 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)));

File diff suppressed because it is too large Load diff

View file

@ -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 <sys/cdefs.h>
#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 <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/param.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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;
}

View file

@ -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;

View file

@ -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 <sys/cdefs.h>
#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 <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <stdint.h>
#include <sys/param.h>
#include <ctype.h>
#include <grp.h>
#include <pwd.h>
#include <vis.h>
#include <stdio.h>
#include <utmp.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <tzfile.h>
#include <unistd.h>
#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;
char visbuf[5];
const char *cp;
stop = dest + len;
start = dest;
while ((dest < stop) && (*src != '\0'))
*dest++ = *src++;
len = dest - start;
while (dest < stop)
*dest++ = '\0';
return(len);
/*
* 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

View file

@ -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 <sys/types.h>
#include <sys/stat.h>
#include <sys/cdefs.h>
#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 <getopt.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/stat.h>
#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;
}

2161
bin/pax/options.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -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)

View file

@ -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 <sys/cdefs.h>
#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 <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#ifdef NET2_REGEX
#include <regexp.h>
#else
#include <regex.h>
#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 >> <empty string>\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;
const char *p;
/* 1. "..{[/],}" */
if (name[0] == '.' && name[1] == '.' &&
(name[2] == '/' || name[2] == '\0'))
return 1;
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;
/* 2. "*[/]..[/]*" */
if (strstr(name, "/../") != NULL)
return 1;
/*
* 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);
/* 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

View file

@ -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 <regex.h>
/*
* 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;

View file

@ -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 <none>
.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 <EOF>
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 <newline>
.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 <original pathname> >> <new pathname>
.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 <ls -l listing> == <link name>
For pathnames representing a symbolic link, the output has the format:
.Dl <ls -l listing> => <link name>
Where <ls -l listing> 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 <newline>
.Aq Dv newline
as soon as processing begins on that file or
archive member.
The trailing
.Dv <newline> ,
.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,66 +1131,15 @@ 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
.Sh EXAMPLES
The command:
.Dl "pax -w -f /dev/sa0 ."
copies the contents of the current directory to the device
.Pa /dev/sa0 .
.Pp
The command:
.Dl pax -v -f filename
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
will copy the entire
.Pa /tmp/from
directory hierarchy to
.Pa /tmp/to .
.Pp
The command:
.Dl pax -r -s ',^//*usr//*,,' -f a.pax
reads the archive
.Pa a.pax ,
with all files rooted in ``/usr'' into the archive extracted relative to the
current directory.
.Pp
The command:
.Dl pax -rw -i .\ dest_dir
can be used to interactively select the files to copy from the current
directory to
.Pa dest_dir .
.Pp
The command:
.Dl pax -r -pe -U root -G bin -f a.pax
will extract all files from the archive
.Pa a.pax
which are owned by
.Em root
with group
.Em bin
and will preserve all file permissions.
.Pp
The command:
.Dl pax -r -w -v -Y -Z home /backup
will update (and list) only those files in the destination directory
.Pa /backup
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
@ -1145,9 +1175,73 @@ a diagnostic message is written to
and when
.Nm
completes it will exit with a non-zero exit status.
.Sh EXAMPLES
The command:
.Dl pax -w -f /dev/rst0 \&.
copies the contents of the current directory to the device
.Pa /dev/rst0 .
.Pp
The command:
.Dl pax -v -f filename
gives the verbose table of contents for an archive stored in
.Pa filename .
.Pp
The following commands:
.Dl mkdir newdir
.Dl cd olddir
.Dl pax -rw -pp .\ ../newdir
will copy the entire
.Pa olddir
directory hierarchy 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
reads the archive
.Pa a.pax ,
with all files rooted in ``/usr'' into the archive extracted relative to the
current directory.
.Pp
The command:
.Dl pax -rw -i .\ dest_dir
can be used to interactively select the files to copy from the current
directory to
.Pa dest_dir .
.Pp
The command:
.Dl pax -r -pe -U root -G bin -f a.pax
will extract all files from the archive
.Pa a.pax
which are owned by
.Em root
with group
.Em bin
and will preserve all file permissions.
.Pp
The command:
.Dl pax -r -w -v -Y -Z home /backup
will update (and list) only those files in the destination directory
.Pa /backup
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 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 .

View file

@ -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 */
#ifndef lint
static char sccsid[] = "@(#)pax.c 8.2 (Berkeley) 4/18/94";
#endif /* not lint */
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#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";
#else
__RCSID("$NetBSD: pax.c,v 1.47 2011/08/29 14:47:48 joerg Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <errno.h>
#include <fcntl.h>
#include <locale.h>
#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <paths.h>
#include <util.h>
#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)
#endif
) {
paxwarn(1, "Unable to set up signal mask");
return(-1);
(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
#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;
return(0);
#ifdef SIGXFSZ
if (sigaction(SIGXFSZ, &n_hand, &o_hand) < 0)
goto out;
#endif
return 0;
out:
syswarn(1, errno, "Unable to set up signal handler");
return(-1);
return -1;
}

View file

@ -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 <minix/config.h>
#include <minix/const.h>
#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
typedef struct archd ARCHD;
typedef struct fsub FSUB;
typedef struct oplist OPLIST;
typedef struct pattern PATTERN;
/*
* 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;
/*
* 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

View file

@ -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 <sys/cdefs.h>
#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 <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <pwd.h>
#include <time.h>
#include <grp.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <tzfile.h>
#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
lt->tm_sec = 0;
switch (strlen(str)) {
if (dot != NULL) {
len = strlen(dot);
if (len != 3)
return -1;
++dot;
lt->tm_sec = ATOI2(dot);
} else {
len = 0;
lt->tm_sec = 0;
}
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;
}

View file

@ -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 */

View file

@ -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 <sys/cdefs.h>
#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 <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <paths.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#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;
}

View file

@ -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;

View file

@ -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 <original pathname> >> <new pathname>
.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.

File diff suppressed because it is too large Load diff

View file

@ -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 */

View file

@ -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 <sys/cdefs.h>
#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 <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
@ -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);
}

View file

@ -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 \

View file

@ -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 <bsd.prog.mk>

View file

@ -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 <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <stdlib.h>
#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);
}

View file

@ -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;

View file

View file

@ -1,38 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}

File diff suppressed because it is too large Load diff

View file

@ -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

16
lib/librmt/Makefile Normal file
View file

@ -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 <bsd.lib.mk>

20
lib/librmt/README Normal file
View file

@ -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 <rmt.h>. 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

30
lib/librmt/pathnames.h Normal file
View file

@ -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"

896
lib/librmt/rmtlib.c Normal file
View file

@ -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 <sys/cdefs.h>
__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 <sys/types.h>
#include <sys/stat.h>
#ifdef RMTIOCTL
#include <sys/ioctl.h>
#include <sys/mtio.h>
#endif
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <err.h>
#ifdef USE_REXEC
#include <netdb.h>
#endif
#define __RMTLIB_PRIVATE
#include <rmt.h> /* 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 <something>
* # 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 <rmt.h> 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);
}
}

182
lib/librmt/rmtops.3 Normal file
View file

@ -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.

View file

@ -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

View file

@ -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 \

6
tools/pax/Makefile Normal file
View file

@ -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"