From 864a4b6e4495e8bb9744303352b4f19fccc90738 Mon Sep 17 00:00:00 2001 From: Apple Date: Sat, 14 Jul 2007 22:31:12 +0000 Subject: [PATCH] file_cmds-184.tar.gz --- Makefile | 4 +- chflags/Makefile | 1 + chflags/chflags.1 | 80 +- chflags/chflags.c | 62 +- chmod/chmod.1 | 43 +- chmod/chmod.c | 30 +- chmod/chmod_acl.c | 137 +-- chmod/chmod_acl.h | 3 +- chown/chgrp.1 | 29 +- chown/chown.8 | 52 +- chown/chown.c | 45 +- {tcopy => cksum}/Makefile | 13 +- cksum/Makefile.postamble | 5 + {tcopy => cksum}/Makefile.preamble | 0 {tcopy => cksum}/PB.project | 11 +- cksum/cksum.1 | 182 ++++ mkfifo/mkfifo.c => cksum/cksum.c | 146 ++- cksum/crc.c | 31 +- cksum/crc32.c | 122 +++ {mtree => cksum}/extern.h | 25 +- mtree/extern.h => cksum/print.c | 55 +- mtree/extern.h => cksum/sum1.c | 56 +- mtree/extern.h => cksum/sum2.c | 58 +- compress/Makefile | 2 +- compress/compress.c | 6 +- cp/Makefile | 1 + cp/cp.1 | 200 ++-- cp/cp.c | 87 +- cp/extern.h | 16 +- cp/utils.c | 276 +++-- dd/conv.c | 6 +- df/Makefile | 4 +- df/Makefile.postamble | 2 - df/df.1 | 68 +- df/df.c | 261 ++--- df/vfslist.c | 9 +- du/Makefile | 3 +- du/du.1 | 79 +- du/du.c | 220 ++-- install/install.1 | 56 +- install/xinstall.c | 27 +- ipcrm/ipcrm.1 | 39 +- ipcrm/ipcrm.c | 25 +- ipcs/Makefile | 6 +- ipcs/Makefile.postamble | 3 + ipcs/ipcs.1 | 30 +- ipcs/ipcs.c | 247 +++-- ln/Makefile | 1 + ln/ln.1 | 115 +- ln/ln.c | 44 +- ln/symlink.7 | 26 +- ls/Makefile | 4 +- ls/extern.h | 2 + ls/humanize_number.c | 148 +++ ls/ls.1 | 281 +++-- ls/ls.c | 88 +- ls/ls.h | 11 + ls/print.c | 197 ++-- ls/util.c | 202 ++-- mkdir/mkdir.c | 2 +- mkfifo/mkfifo.1 | 35 +- mkfifo/mkfifo.c | 17 +- mknod/mknod.8 | 7 +- mknod/mknod.c | 14 +- mtree/Makefile | 5 +- mtree/compare.c | 132 ++- mtree/create.c | 221 ++-- mtree/excludes.c | 11 +- mtree/extern.h | 45 +- mtree/misc.c | 43 +- mtree/mtree.8 | 221 ++-- mtree/mtree.c | 57 +- mtree/mtree.h | 10 +- mtree/spec.c | 67 +- mtree/specspec.c | 257 +++++ mtree/verify.c | 92 +- mv/mv.1 | 35 +- mv/mv.c | 75 +- pax/Makefile | 2 +- pax/ar_io.c | 297 ++---- pax/ar_subs.c | 260 +++-- pax/buf_subs.c | 215 +--- pax/cache.c | 143 +-- pax/cache.h | 10 +- pax/cpio.1 | 193 ++-- pax/cpio.c | 242 +---- pax/cpio.h | 16 +- pax/extern.h | 630 +++++------ pax/file_subs.c | 451 ++++---- pax/ftree.c | 179 ++-- pax/ftree.h | 8 +- pax/gen_subs.c | 245 ++--- pax/getoldopt.c | 30 +- pax/options.c | 613 +++++++---- pax/options.h | 15 +- pax/pat_rep.c | 377 ++----- pax/pat_rep.h | 14 +- pax/pax.1 | 1041 ++++++++++--------- pax/pax.c | 108 +- pax/pax.h | 178 ++-- pax/pax_format.c | 2024 ++++++++++++++++++++++++++++++++++++ pax/sel_subs.c | 252 ++--- pax/sel_subs.h | 10 +- pax/tables.c | 396 +++---- pax/tables.h | 25 +- pax/tar.c | 461 ++++---- pax/tar.h | 17 +- pax/tty_subs.c | 87 +- rm/rm.c | 6 + shar/shar.1 | 4 +- stat/Makefile | 1 + stat/stat.1 | 60 +- stat/stat.c | 17 +- tcopy/Makefile.postamble | 1 - tcopy/tcopy.1 | 115 -- tcopy/tcopy.c | 343 ------ touch/touch.c | 11 +- 117 files changed, 8629 insertions(+), 5796 deletions(-) rename {tcopy => cksum}/Makefile (75%) create mode 100644 cksum/Makefile.postamble rename {tcopy => cksum}/Makefile.preamble (100%) rename {tcopy => cksum}/PB.project (75%) create mode 100644 cksum/cksum.1 copy mkfifo/mkfifo.c => cksum/cksum.c (53%) create mode 100644 cksum/crc32.c copy {mtree => cksum}/extern.h (78%) copy mtree/extern.h => cksum/print.c (68%) copy mtree/extern.h => cksum/sum1.c (70%) copy mtree/extern.h => cksum/sum2.c (68%) create mode 100644 ls/humanize_number.c create mode 100644 mtree/specspec.c rewrite pax/extern.h (65%) create mode 100644 pax/pax_format.c delete mode 100644 tcopy/Makefile.postamble delete mode 100644 tcopy/tcopy.1 delete mode 100644 tcopy/tcopy.c diff --git a/Makefile b/Makefile index 20e69e6..30a7cc9 100644 --- a/Makefile +++ b/Makefile @@ -12,8 +12,8 @@ NAME = file_cmds PROJECTVERSION = 2.8 PROJECT_TYPE = Aggregate -TOOLS = chflags chmod chown compress cp dd df du install ipcrm ipcs ln ls\ - mkdir mkfifo mknod mtree mv pathchk pax rm rmdir rmt shar stat tcopy\ +TOOLS = chflags chmod chown cksum compress cp dd df du install ipcrm ipcs ln ls\ + mkdir mkfifo mknod mtree mv pathchk pax rm rmdir rmt shar stat\ touch OTHERSRCS = PROJECT Makefile.preamble Makefile Makefile.postamble diff --git a/chflags/Makefile b/chflags/Makefile index 4f99118..aeeabe4 100644 --- a/chflags/Makefile +++ b/chflags/Makefile @@ -16,6 +16,7 @@ CFILES = chflags.c OTHERSRCS = Makefile Makefile.preamble Makefile.postamble chflags.1 +OTHER_CFLAGS = -D__FBSDID=__RCSID MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC diff --git a/chflags/chflags.1 b/chflags/chflags.1 index 3205110..45d65a4 100644 --- a/chflags/chflags.1 +++ b/chflags/chflags.1 @@ -1,3 +1,4 @@ +.\"- .\" Copyright (c) 1989, 1990, 1993, 1994 .\" The Regents of the University of California. All rights reserved. .\" @@ -12,10 +13,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 the University of -.\" California, Berkeley and its contributors. .\" 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. @@ -33,9 +30,9 @@ .\" SUCH DAMAGE. .\" .\" @(#)chflags.1 8.4 (Berkeley) 5/2/95 -.\" $FreeBSD: src/usr.bin/chflags/chflags.1,v 1.14 2001/08/15 09:09:39 ru Exp $ +.\" $FreeBSD: src/bin/chflags/chflags.1,v 1.25 2005/06/14 08:25:54 ru Exp $ .\" -.Dd May 2, 1995 +.Dd May 14, 2005 .Dt CHFLAGS 1 .Os .Sh NAME @@ -82,46 +79,54 @@ The flags are specified as an octal number or a comma separated list of keywords. The following keywords are currently defined: .Pp -.Bl -tag -offset indent -width "opaque" -compact -.It Ar arch +.Bl -tag -offset indent -width ".Ar opaque" +.It Ar arch , archived set the archived flag (super-user only) .It Ar opaque -set the opaque flag (owner or super-user only) +set the opaque flag (owner or super-user only). +[Directory is opaque when viewed through a union mount] .It Ar nodump set the nodump flag (owner or super-user only) -.It Ar sappnd +.It Ar sappnd , sappend set the system append-only flag (super-user only) -.It Ar schg +.It Ar schg , schange , simmutable set the system immutable flag (super-user only) -.It Ar sunlnk -set the system undeletable flag (super-user only) -.It Ar uappnd +.It Ar uappnd , uappend set the user append-only flag (owner or super-user only) -.It Ar uchg +.It Ar uchg , uchange , uimmutable set the user immutable flag (owner or super-user only) -.It Ar uunlnk -set the user undeletable flag (owner or super-user only) -.It Ar archived , sappend , schange , Xo -.Ar simmutable , uappend , uchange , uimmutable , -.Ar sunlink , uunlink -.Xc -aliases for the above +.It Ar hidden +set the hidden flag +[Hide item from GUI] .El .Pp +As discussed in +.Xr chflags 2 , +the +.Ar sappnd +and +.Ar schg +flags may only be unset when the system is in single-user mode. +.Pp Putting the letters .Dq Ar no -before an option causes the flag to be turned off. +before or removing the letters +.Dq Ar no +from a keyword causes the flag to be cleared. For example: -.Bl -tag -offset indent -width "nouchg" +.Pp +.Bl -tag -offset indent -width "nouchg" -compact .It Ar nouchg -the immutable bit should be cleared +clear the user immutable flag (owner or super-user only) +.It Ar dump +clear the nodump flag (owner or super-user only) .El .Pp -Symbolic links do not have flags, so unless the +Unless the .Fl H or .Fl L -option is set, +options are given, .Nm on a symbolic link always succeeds and has no effect. The @@ -135,8 +140,8 @@ option is specified. In addition, these options override each other and the command's actions are determined by the last one specified. .Pp -You can use "ls -lo" to see the flags of existing files. -.Sh DIAGNOSTICS +You can use "ls -lO" to see the flags of existing files. +.Sh EXIT STATUS .Ex -std .Sh SEE ALSO .Xr ls 1 , @@ -149,3 +154,20 @@ The .Nm command first appeared in .Bx 4.4 . +.Sh BUGS +Only a limited number of utilities are +.Nm +aware. +Some of these tools include +.Xr ls 1 , +.Xr cp 1 , +.Xr find 1 , +.Xr install 1 , +.Xr dump 8 , +and +.Xr restore 8 . +In particular a tool which is not currently +.Nm +aware is the +.Xr pax 1 +utility. diff --git a/chflags/chflags.c b/chflags/chflags.c index a7777cb..d90a339 100644 --- a/chflags/chflags.c +++ b/chflags/chflags.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -10,10 +10,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 the University of - * California, Berkeley and its contributors. * 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. @@ -31,20 +27,20 @@ * SUCH DAMAGE. */ +#if 0 #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1992, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif -#if 0 #ifndef lint static char sccsid[] = "@(#)chflags.c 8.5 (Berkeley) 4/1/94"; #endif #endif #include -__RCSID("$FreeBSD: src/usr.bin/chflags/chflags.c,v 1.16 2002/09/04 23:28:58 dwmalone Exp $"); +__FBSDID("$FreeBSD: src/bin/chflags/chflags.c,v 1.23 2005/05/14 23:23:10 dd Exp $"); #include #include @@ -66,27 +62,36 @@ main(int argc, char *argv[]) FTSENT *p; u_long clear, set; long val; - int Hflag, Lflag, Pflag, Rflag, ch, fts_options, oct, rval; + int Hflag, Lflag, Rflag, hflag, ch, fts_options, oct, rval; char *flags, *ep; + int (*change_flags)(const char *, unsigned long); - Hflag = Lflag = Pflag = Rflag = 0; + Hflag = Lflag = Rflag = hflag = 0; +#ifdef __APPLE__ while ((ch = getopt(argc, argv, "HLPR")) != -1) +#else /* !__APPLE__ */ + while ((ch = getopt(argc, argv, "HLPRh")) != -1) +#endif /* __APPLE__ */ switch (ch) { case 'H': Hflag = 1; - Lflag = Pflag = 0; + Lflag = 0; break; case 'L': Lflag = 1; - Hflag = Pflag = 0; + Hflag = 0; break; case 'P': - Pflag = 1; Hflag = Lflag = 0; break; case 'R': Rflag = 1; break; +#ifndef __APPLE__ + case 'h': + hflag = 1; + break; +#endif /* !__APPLE__ */ case '?': default: usage(); @@ -99,6 +104,9 @@ main(int argc, char *argv[]) if (Rflag) { fts_options = FTS_PHYSICAL; + if (hflag) + errx(1, "the -R and -h options " + "may not be specified together"); if (Hflag) fts_options |= FTS_COMFOLLOW; if (Lflag) { @@ -108,6 +116,14 @@ main(int argc, char *argv[]) } else fts_options = FTS_LOGICAL; + /* XXX: Why don't chflags and lchflags have compatible prototypes? */ +#ifndef __APPLE__ + if (hflag) + change_flags = (int (*)(const char *, unsigned long))lchflags; + else +#endif /* !__APPLE__ */ + change_flags = chflags; + flags = *argv; if (*flags >= '0' && *flags <= '7') { errno = 0; @@ -132,11 +148,10 @@ main(int argc, char *argv[]) for (rval = 0; (p = fts_read(ftsp)) != NULL;) { switch (p->fts_info) { - case FTS_D: - if (Rflag) /* Change it at FTS_DP. */ - continue; - fts_set(ftsp, p, FTS_SKIP); - break; + case FTS_D: /* Change it at FTS_DP if we're recursive. */ + if (!Rflag) + fts_set(ftsp, p, FTS_SKIP); + continue; case FTS_DNR: /* Warn, chflag, continue. */ warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; @@ -153,17 +168,20 @@ main(int argc, char *argv[]) * don't point to anything and ones that we found * doing a physical walk. */ - continue; + if (!hflag) + continue; + /* FALLTHROUGH */ default: break; } if (oct) { - if (!chflags(p->fts_accpath, set)) + if (!(*change_flags)(p->fts_accpath, set)) continue; } else { p->fts_statp->st_flags |= set; p->fts_statp->st_flags &= clear; - if (!chflags(p->fts_accpath, (u_long)p->fts_statp->st_flags)) + if (!(*change_flags)(p->fts_accpath, + (u_long)p->fts_statp->st_flags)) continue; } warn("%s", p->fts_path); @@ -178,6 +196,10 @@ void usage(void) { (void)fprintf(stderr, +#ifdef __APPLE__ "usage: chflags [-R [-H | -L | -P]] flags file ...\n"); +#else /* !__APPLE__ */ + "usage: chflags [-h] [-R [-H | -L | -P]] flags file ...\n"); +#endif /* __APPLE__ */ exit(1); } diff --git a/chmod/chmod.1 b/chmod/chmod.1 index 9cafe9c..ec6e2fd 100644 --- a/chmod/chmod.1 +++ b/chmod/chmod.1 @@ -42,35 +42,35 @@ .Nm chmod .Nd change file modes or Access Control Lists .Sh SYNOPSIS -.Nm +.Nm chmod .Op Fl fv .Op Fl R Op Fl H | L | P .Ar mode .Ar -.Nm +.Nm chmod .Op Fl fv .Op Fl R Op Fl H | L | P .Op -a | +a | =a .Ar ACE .Ar -.Nm -.Op Fl fv +.Nm chmod +.Op Fl fhv .Op Fl R Op Fl H | L | P .Op Fl E .Ar -.Nm -.Op Fl fv +.Nm chmod +.Op Fl fhv .Op Fl R Op Fl H | L | P .Op Fl C .Ar .Nm chmod -.Op Fl fv -.Op Fl R Op Fl H | L | P +.Op Fl fhv +.Op Fl R Op Fl H | L | P .Op Fl N .Ar .Sh DESCRIPTION The -.Nm +.Nm chmod utility modifies the file mode bits of the listed files as specified by the .Ar mode @@ -79,12 +79,20 @@ Lists (ACLs) associated with the listed files. .Pp The generic options are as follows: .Bl -tag -width Ds +.It Fl f +Do not display a diagnostic message if +.Nm chmod +could not modify the mode for +.Va file . .It Fl H If the .Fl R option is specified, symbolic links on the command line are followed. (Symbolic links encountered in the tree traversal are not followed by default.) +.It Fl h +If the file is a symbolic link, change the mode of the link itself +rather than the file that the link points to. .It Fl L If the .Fl R @@ -97,14 +105,9 @@ This is the default. .It Fl R Change the modes of the file hierarchies rooted in the files instead of just the files themselves. -.It Fl f -Do not display a diagnostic message if -.Nm -could not modify the mode for -.Va file . .It Fl v Cause -.Nm +.Nm chmod to be verbose, showing filenames as the mode is modified. If the .Fl v @@ -328,6 +331,9 @@ ACLs are manipulated using extensions to the symbolic mode grammar. Each file has one ACL, containing an ordered list of entries. Each entry refers to a user or group, and grants or denies a set of permissions. +In cases where a user and a group exist with the same name, the +user/group name can be prefixed with "user:" or "group:" in order to +specify the type of name. .Pp The following permissions are applicable to all filesystem objects: .Bl -tag -width 6n -compact -offset indent @@ -443,7 +449,7 @@ allow lists. Inherited entries are added by using the +ai mode. 4: admin inherited allow delete 5: backup inherited deny read 6: admin inherited allow write-security - # chmod +ai "others allow write" file1 + # chmod +ai "others allow read" file1 # ls -le -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1 owner: juser @@ -534,6 +540,7 @@ The option is non-standard and its use in scripts is not recommended. .Sh SEE ALSO .Xr chflags 1 , +.Xr fsaclctl 1 , .Xr install 1 , .Xr chmod 2 , .Xr stat 2 , @@ -546,7 +553,7 @@ option is non-standard and its use in scripts is not recommended. .Xr sticky 8 .Sh STANDARDS The -.Nm +.Nm chmod utility is expected to be .St -p1003.2 compatible with the exception of the @@ -556,6 +563,6 @@ symbol which is not included in that standard. .Sh HISTORY A -.Nm +.Nm chmod command appeared in .At v1 . diff --git a/chmod/chmod.c b/chmod/chmod.c index c256ecd..7801340 100644 --- a/chmod/chmod.c +++ b/chmod/chmod.c @@ -93,7 +93,7 @@ main(int argc, char *argv[]) #ifndef __APPLE__ while ((ch = getopt(argc, argv, "HLPRXfghorstuvwx")) != -1) #else - while ((ch = getopt(argc, argv, "ACEHILNPRVXafginorstuvwx")) != -1) + while ((ch = getopt(argc, argv, "ACEHILNPRVXafghinorstuvwx")) != -1) #endif switch (ch) { case 'H': @@ -113,7 +113,6 @@ main(int argc, char *argv[]) case 'f': fflag = 1; break; -#ifndef __APPLE__ case 'h': /* * In System V (and probably POSIX.2) the -h option @@ -125,12 +124,17 @@ main(int argc, char *argv[]) */ hflag = 1; break; -#else +#ifdef __APPLE__ case 'a': if (argv[optind - 1][0] == '-' && argv[optind - 1][1] == ch) --optind; goto done; + case 'A': + acloptflags |= ACL_FLAG | ACL_TO_STDOUT; + ace_arg_not_required = 1; + errx(1, "-A not implemented"); + goto done; case 'E': acloptflags |= ACL_FLAG | ACL_FROM_STDIN; goto done; @@ -156,6 +160,7 @@ main(int argc, char *argv[]) case 'V': acloptflags |= ACL_FLAG | ACL_INVOKE_EDITOR; ace_arg_not_required = 1; + errx(1, "-V not implemented"); goto done; #endif /* __APPLE__ */ /* @@ -272,14 +277,10 @@ apnoacl: } else fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL; -#ifndef __APPLE__ if (hflag) change_mode = lchmod; else change_mode = chmod; -#else - change_mode = chmod; -#endif /* __APPLE__ */ #ifdef __APPLE__ if (acloptflags & ACL_FROM_STDIN) { int readval = 0, readtotal = 0; @@ -350,16 +351,20 @@ apnoacl: err(1, "fts_open"); for (rval = 0; (p = fts_read(ftsp)) != NULL;) { switch (p->fts_info) { - case FTS_D: /* Change it at FTS_DP. */ + case FTS_D: if (!Rflag) - fts_set(ftsp, p, FTS_SKIP); - continue; + (void)fts_set(ftsp, p, FTS_SKIP); + break; case FTS_DNR: /* Warn, chmod, continue. */ warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; break; - case FTS_ERR: /* Warn, continue. */ + case FTS_DP: /* Already changed at FTS_D. */ + continue; case FTS_NS: + if (acloptflags & ACL_FLAG) /* don't need stat for -N */ + break; + case FTS_ERR: /* Warn, continue. */ warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; continue; @@ -434,7 +439,8 @@ usage(void) { #ifdef __APPLE__ (void)fprintf(stderr, - "usage: chmod [-fv] [-R [-H | -L | -P]] [-a | +a | =a [i][# [ n]]] mode|entry file ...\n"); + "usage:\tchmod [-fhv] [-R [-H | -L | -P]] [-a | +a | =a [i][# [ n]]] mode|entry file ...\n" + "\tchmod [-fhv] [-R [-H | -L | -P]] [-E | -C | -i | -I] file ...\n"); /* add -A and -V when implemented */ #else (void)fprintf(stderr, "usage: chmod [-fhv] [-R [-H | -L | -P]] mode file ...\n"); diff --git a/chmod/chmod_acl.c b/chmod/chmod_acl.c index effc4c0..f09f304 100644 --- a/chmod/chmod_acl.c +++ b/chmod/chmod_acl.c @@ -92,40 +92,37 @@ static struct { * or use err_set_exit() and make various structures globals. */ +#define NAME_USER (1) +#define NAME_GROUP (2) +#define NAME_EITHER (NAME_USER | NAME_GROUP) + /* Perform a name to uuid mapping - calls through to memberd */ uuid_t * -name_to_uuid(char *tok) { +name_to_uuid(char *tok, int nametype) { struct passwd *tpass = NULL; struct group *tgrp = NULL; uuid_t *entryg = NULL; - char is_uid = 1; if ((entryg = (uuid_t *) calloc(1,sizeof(uuid_t))) == NULL) err(1, "Unable to allocate a uuid"); - - tpass = getpwnam(tok); - if (tpass == NULL) { + if (nametype & NAME_USER) + tpass = getpwnam(tok); + + if (NULL == tpass && (nametype & NAME_GROUP)) tgrp = getgrnam(tok); - if (tgrp == NULL) { - errno = EINVAL; - err(1, "Unable to translate %s to a UID/GID", tok); - } - is_uid = 0; - } - + if (tpass) { - if (0 != mbr_uid_to_uuid(tpass->pw_uid, entryg)) { - errno = EINVAL; - err(1, "mbr_uid_to_uuid(): Unable to translate"); + if (0 != mbr_uid_to_uuid(tpass->pw_uid, *entryg)) { + errx(1, "mbr_uid_to_uuid(): Unable to translate uid %d", tpass->pw_uid); } - } - else { - if (0 != mbr_gid_to_uuid(tgrp->gr_gid, entryg)) { - errno = EINVAL; - err(1, "mbr_gid_to_uuid(): Unable to translate"); + } else if (tgrp) { + if (0 != mbr_gid_to_uuid(tgrp->gr_gid, *entryg)) { + errx(1, "mbr_gid_to_uuid(): Unable to translate gid %d", tgrp->gr_gid); } + } else { + errx(1, "Unable to translate '%s' to a UID/GID", tok); } return entryg; } @@ -142,26 +139,36 @@ parse_entry(char *entrybuf, acl_entry_t newent) { acl_flagset_t flags; unsigned permcount = 0; unsigned pindex = 0; + char *delimiter = " "; + int nametype = NAME_EITHER; acl_get_permset(newent, &perms); acl_get_flagset_np(newent, &flags); pebuf = entrybuf; - tok = strsep(&pebuf, " "); + if (0 == strncmp(entrybuf, "user:", 5)) { + nametype = NAME_USER; + pebuf += 5; + } else if (0 == strncmp(entrybuf, "group:", 6)) { + nametype = NAME_GROUP; + pebuf += 6; + } + + if (strchr(pebuf, ':')) /* User/Group names can have spaces */ + delimiter = ":"; + tok = strsep(&pebuf, delimiter); if ((tok == NULL) || *tok == '\0') { - errno = EINVAL; - err(1, "Invalid entry format"); + errx(1, "Invalid entry format -- expected user or group name"); } /* parse the name into a qualifier */ - entryg = name_to_uuid(tok); + entryg = name_to_uuid(tok, nametype); - tok = strsep(&pebuf, " "); + tok = strsep(&pebuf, ": "); /* Stick with delimiter? */ if ((tok == NULL) || *tok == '\0') { - errno = EINVAL; - err(1, "Invalid entry format"); + errx(1, "Invalid entry format -- expected allow or deny"); } /* is the verb 'allow' or 'deny'? */ @@ -170,8 +177,7 @@ parse_entry(char *entrybuf, acl_entry_t newent) { } else if (!strcmp(tok, "deny")) { tag = ACL_EXTENDED_DENY; } else { - errno = EINVAL; - err(1, "Unknown tag type '%s'", tok); + errx(1, "Unknown tag type '%s'", tok); } /* parse permissions */ @@ -195,15 +201,13 @@ parse_entry(char *entrybuf, acl_entry_t newent) { goto found; } } - errno = EINVAL; - err(1,"Invalid permission type %s", tok); + errx(1,"Invalid permission type '%s'", tok); found: continue; } } if (0 == permcount) { - errno = EINVAL; - err(1, "No permissions specified"); + errx(1, "No permissions specified"); } acl_set_tag_type(newent, tag); acl_set_qualifier(newent, entryg); @@ -248,12 +252,10 @@ parse_acl_entries(const char *input) { if (0 != acl_create_entry(&acl_input, &newent)) err(1, "acl_create_entry() failed"); if (0 != parse_entry(*bufp, newent)) { - errno = EINVAL; - err(1, "Failed parsing entry %s", *bufp); + errx(1, "Failed parsing entry '%s'", *bufp); } if (++bufp >= &entryv[ACL_MAX_ENTRIES - 1]) { - errno = ERANGE; - err(1, "Too many entries"); + errx(1, "Too many entries"); } } @@ -302,8 +304,7 @@ score_acl_entry(acl_entry_t entry) { score++; break; default: - errno = EINVAL; - err(1, "Unknown tag type present in ACL entry"); + errx(1, "Unknown tag type %d present in ACL entry", tag); /* NOTREACHED */ } @@ -476,15 +477,14 @@ find_matching_entry (acl_t acl, acl_entry_t modifier, acl_entry_t *rentryp, if ((cmp == MATCH_EXACT) || (cmp == MATCH_PARTIAL)) { if (match_inherited) { acl_flagset_t eflags, mflags; - + if (0 != acl_get_flagset_np(modifier, &mflags)) err(1, "Unable to get flagset"); if (0 != acl_get_flagset_np(entry, &eflags)) err(1, "Unable to get flagset"); - if (acl_get_flag_np(mflags, ACL_ENTRY_INHERITED) == - acl_get_flag_np(eflags, ACL_ENTRY_INHERITED)) { + if (compare_acl_flagsets(mflags, eflags) == MATCH_EXACT) { *rentryp = entry; fcmp = cmp; } @@ -609,8 +609,7 @@ modify_acl(acl_t *oaclp, acl_entry_t modifier, unsigned int optflags, if (optflags & ACL_DELETE_FLAG) { if (flag_new_acl) { - errno = EINVAL; - err(1, "No ACL present"); + errx(1, "No ACL present"); } if (position != -1 ) { if (0 != acl_get_entry(oacl, position, &rentry)) @@ -639,8 +638,7 @@ modify_acl(acl_t *oaclp, acl_entry_t modifier, unsigned int optflags, } } if (0 == match_found) { - errno = EINVAL; - warn("Entry not found when attempting delete"); + warnx("Entry not found when attempting delete"); retval = 1; } } @@ -759,40 +757,43 @@ modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int pos if (oacl) acl_free(oacl); oacl = facl; - } - else - if (optflags & ACL_CHECK_CANONICITY) { + } else if (optflags & ACL_TO_STDOUT) { + ssize_t len; /* need to get printacl() from ls(1) */ + char *text = acl_to_text(oacl, &len); + puts(text); + acl_free(text); + } else if (optflags & ACL_CHECK_CANONICITY) { if (flag_new_acl) { - errno = EINVAL; - warn("No ACL currently associated with file %s", path); + warnx("No ACL currently associated with file '%s'", path); } - return(is_canonical(oacl)); - } - else - if ((optflags & ACL_SET_FLAG) && (position == -1) && + retval = is_canonical(oacl); + } else if ((optflags & ACL_SET_FLAG) && (position == -1) && (!is_canonical(oacl))) { - errno = EINVAL; - warn("The specified file %s does not have an ACL in canonical order, please specify a position with +a# ", path); + warnx("The specified file '%s' does not have an ACL in canonical order, please specify a position with +a# ", path); retval = 1; - } - else - if (((optflags & ACL_DELETE_FLAG) && (position != -1)) + } else if (((optflags & ACL_DELETE_FLAG) && (position != -1)) || (optflags & ACL_CHECK_CANONICITY)) { retval = modify_acl(&oacl, NULL, optflags, position, inheritance_level, flag_new_acl); - } - else + } else if ((optflags & (ACL_REMOVE_INHERIT_FLAG|ACL_REMOVE_INHERITED_ENTRIES)) && flag_new_acl) { + warnx("No ACL currently associated with file '%s'", path); + retval = 1; + } else { + if (!modifier) { /* avoid bus error in acl_get_entry */ + errx(1, "Internal error: modifier should not be NULL"); + } for (aindex = 0; acl_get_entry(modifier, (entry == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY), &entry) == 0; aindex++) { - retval += modify_acl(&oacl, entry, optflags, - position, inheritance_level, - flag_new_acl); - } + retval += modify_acl(&oacl, entry, optflags, + position, inheritance_level, + flag_new_acl); } + } + } /* XXX Potential race here, since someone else could've modified or * read the ACL on this file (with the intention of modifying it) in @@ -802,10 +803,10 @@ modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int pos * "changeset" mechanism, common locking strategy, or kernel * supplied reservation mechanism to prevent this race. */ - if (!(optflags & ACL_CHECK_CANONICITY) && + if (!(optflags & (ACL_TO_STDOUT|ACL_CHECK_CANONICITY)) && (0 != acl_set_file(path, ACL_TYPE_EXTENDED, oacl))){ if (!fflag) - warn("Failed to set ACL on file %s", path); + warn("Failed to set ACL on file '%s'", path); retval = 1; } diff --git a/chmod/chmod_acl.h b/chmod/chmod_acl.h index 8ca16be..0833be4 100644 --- a/chmod/chmod_acl.h +++ b/chmod/chmod_acl.h @@ -52,6 +52,7 @@ #define ACL_REMOVE_INHERITED_ENTRIES (1<<10) #define ACL_NO_TRANSLATE (1<<11) #define ACL_INVOKE_EDITOR (1<<12) +#define ACL_TO_STDOUT (1<<13) #define ACL_CLEAR_FLAG (1<<14) #define INHERITANCE_TIER (-5) @@ -80,5 +81,5 @@ extern unsigned find_canonical_position(acl_t acl, acl_entry_t modifier); extern int subtract_from_entry(acl_entry_t rentry, acl_entry_t modifier); extern int modify_acl(acl_t *oaclp, acl_entry_t modifier, unsigned int optflags, int position, int inheritance_level, unsigned flag_new_acl); extern int modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int position, int inheritance_level); -extern uuid_t *name_to_uuid(char *tok); +extern uuid_t *name_to_uuid(char *tok, int nametype); #endif /* __APPLE__*/ diff --git a/chown/chgrp.1 b/chown/chgrp.1 index 9407995..6621698 100644 --- a/chown/chgrp.1 +++ b/chown/chgrp.1 @@ -42,7 +42,7 @@ .Nm chgrp .Nd change group .Sh SYNOPSIS -.Nm +.Nm chgrp .Op Fl fhv .Oo .Fl R @@ -52,7 +52,7 @@ .Ar .Sh DESCRIPTION The -.Nm +.Nm chgrp utility sets the group ID of the file named by each .Ar file operand to the @@ -61,32 +61,39 @@ ID specified by the group operand. .Pp The following options are available: .Bl -tag -width indent +.\" ========== +.It Fl f +The force option ignores errors, except for usage errors and doesn't +query about strange modes (unless the user does not have proper permissions). +.\" ========== .It Fl H If the .Fl R option is specified, symbolic links on the command line are followed. (Symbolic links encountered in the tree traversal are not followed). +.\" ========== +.It Fl h +If the file is a symbolic link, the group ID of the link itself is changed +rather than the file that is pointed to. +.\" ========== .It Fl L If the .Fl R option is specified, all symbolic links are followed. +.\" ========== .It Fl P If the .Fl R option is specified, no symbolic links are followed. This is the default. +.\" ========== .It Fl R Change the group ID for the file hierarchies rooted in the files instead of just the files themselves. -.It Fl f -The force option ignores errors, except for usage errors and doesn't -query about strange modes (unless the user does not have proper permissions). -.It Fl h -If the file is a symbolic link, the group ID of the link itself is changed -rather than the file that is pointed to. +.\" ========== .It Fl v Cause -.Nm +.Nm chgrp to be verbose, showing files as the group is modified. .El .Pp @@ -109,7 +116,7 @@ If a group name is also a numeric group ID, the operand is used as a group name. .Pp The user invoking -.Nm +.Nm chgrp must belong to the specified group and be the owner of the file, or be the super-user. .Sh DIAGNOSTICS @@ -134,7 +141,7 @@ group ID file .Xr chown 8 .Sh STANDARDS The -.Nm +.Nm chgrp utility is expected to be .St -p1003.2 compatible. diff --git a/chown/chown.8 b/chown/chown.8 index 18d467d..fc991ce 100644 --- a/chown/chown.8 +++ b/chown/chown.8 @@ -39,7 +39,7 @@ .Nm chown .Nd change file owner and group .Sh SYNOPSIS -.Nm +.Nm chown .Op Fl fhv .Oo .Fl R @@ -47,7 +47,7 @@ .Oc .Ar owner Ns Op : Ns Ar group .Ar -.Nm +.Nm chown .Op Fl fhv .Oo .Fl R @@ -57,7 +57,7 @@ .Ar .Sh DESCRIPTION The -.Nm +.Nm chown utility changes the user ID and/or the group ID of the specified files. Symbolic links named by arguments are silently left unchanged unless .Fl h @@ -65,11 +65,17 @@ is used. .Pp The options are as follows: .Bl -tag -width Ds +.It Fl f +Don't report any failure to change file owner or group, nor modify +the exit status to reflect such failures. .It Fl H If the .Fl R option is specified, symbolic links on the command line are followed. (Symbolic links encountered in the tree traversal are not followed.) +.It Fl h +If the file is a symbolic link, change the user ID and/or the +group ID of the link itself. .It Fl L If the .Fl R @@ -78,19 +84,14 @@ option is specified, all symbolic links are followed. If the .Fl R option is specified, no symbolic links are followed. +Instead, the user and/or group ID of the link itself are modified. This is the default. .It Fl R Change the user ID and/or the group ID for the file hierarchies rooted in the files instead of just the files themselves. -.It Fl f -Don't report any failure to change file owner or group, nor modify -the exit status to reflect such failures. -.It Fl h -If the file is a symbolic link, change the user ID and/or the -group ID of the link itself. .It Fl v Cause -.Nm +.Nm chown to be verbose, showing files as the owner is modified. .El .Pp @@ -109,7 +110,8 @@ The .Ar owner and .Ar group -operands are both optional, however, one must be specified. +operands are both optional; +however, at least one must be specified. If the .Ar group operand is specified, it must be preceded by a colon (``:'') character. @@ -125,37 +127,47 @@ may be either a numeric group ID or a group name. If a group name is also a numeric group ID, the operand is used as a group name. .Pp -The ownership of a file may only be altered by a super-user for -obvious security reasons. +For obvious security reasons, +the ownership of a file may only be altered by a super-user. +Similarly, only a member of a group can change a file's group ID +to that group. .Sh DIAGNOSTICS .Ex -std .Sh COMPATIBILITY Previous versions of the -.Nm +.Nm chown utility used the dot (``.'') character to distinguish the group name. -This has been changed to be a colon (``:'') character so that user and -group names may contain the dot character. +This has been changed to be a colon (``:'') character, +so that user and group names may contain the dot character. .Pp -On previous versions of this system, symbolic links did not have -owners. +On previous versions of this system, +symbolic links did not have owners. .Pp The .Fl v option is non-standard and its use in scripts is not recommended. +.Sh LEGACY DESCRIPTION +In legacy mode, the +.Fl R +and +.Fl RP +options do not change the user ID +or the group ID of symbolic links. .Sh SEE ALSO .Xr chgrp 1 , .Xr find 1 , .Xr chown 2 , .Xr fts 3 , +.Xr compat 5 , .Xr symlink 7 .Sh STANDARDS The -.Nm +.Nm chown utility is expected to be .St -p1003.2 compliant. .Sh HISTORY A -.Nm +.Nm chown utility appeared in .At v1 . diff --git a/chown/chown.c b/chown/chown.c index 44a0f43..8af78c5 100644 --- a/chown/chown.c +++ b/chown/chown.c @@ -58,6 +58,13 @@ __RCSID("$FreeBSD: src/usr.sbin/chown/chown.c,v 1.24 2002/07/17 16:22:24 dwmalon #include #include #include +#include + +#ifdef __APPLE__ +#include +#else +#define COMPAT_MODE(a,b) (1) +#endif /* __APPLE__ */ void a_gid(const char *); void a_uid(const char *); @@ -78,7 +85,11 @@ main(int argc, char **argv) int Hflag, Lflag, Rflag, fflag, hflag, vflag; int ch, fts_options, rval; char *cp; + int unix2003_compat = 0; + int symlink_found = 0; + if (argc < 1) + usage(); cp = strrchr(argv[0], '/'); cp = (cp != NULL) ? cp + 1 : argv[0]; ischown = (strcmp(cp, "chown") == 0); @@ -136,6 +147,7 @@ main(int argc, char **argv) uid = (uid_t)-1; gid = (gid_t)-1; if (ischown) { + unix2003_compat = COMPAT_MODE("bin/chown", "Unix2003"); if ((cp = strchr(*argv, ':')) != NULL) { *cp++ = '\0'; a_gid(cp); @@ -148,13 +160,16 @@ main(int argc, char **argv) } #endif a_uid(*argv); - } else + } else { + unix2003_compat = COMPAT_MODE("bin/chgrp", "Unix2003"); a_gid(*argv); + } if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) err(1, NULL); for (rval = 0; (p = fts_read(ftsp)) != NULL;) { + symlink_found = 0; switch (p->fts_info) { case FTS_D: /* Change it at FTS_DP. */ if (!Rflag) @@ -178,15 +193,33 @@ main(int argc, char **argv) */ if (hflag) break; - else + else { + symlink_found = 1; + if (unix2003_compat) { + if (Hflag || Lflag) { /* -H or -L was specified */ + if (p->fts_errno) { + warnx("%s: %s", p->fts_name, strerror(p->fts_errno)); + rval = 1; + continue; + } + } + break; /* Otherwise symlinks keep going */ + } continue; + } default: break; } - if ((uid == (uid_t)-1 || uid == p->fts_statp->st_uid) && - (gid == (gid_t)-1 || gid == p->fts_statp->st_gid)) - continue; - if ((hflag ? lchown : chown)(p->fts_accpath, uid, gid) == -1) { + if (unix2003_compat) { + /* Can only avoid updating times if both uid and gid are -1 */ + if ((uid == (uid_t)-1) && (gid == (gid_t)-1)) + continue; + } else { + if ((uid == (uid_t)-1 || uid == p->fts_statp->st_uid) && + (gid == (gid_t)-1 || gid == p->fts_statp->st_gid)) + continue; + } + if (((hflag || symlink_found) ? lchown : chown)(p->fts_accpath, uid, gid) == -1) { if (!fflag) { chownerr(p->fts_path); rval = 1; diff --git a/tcopy/Makefile b/cksum/Makefile similarity index 75% rename from tcopy/Makefile rename to cksum/Makefile index 0d2d6b1..24e3168 100644 --- a/tcopy/Makefile +++ b/cksum/Makefile @@ -7,15 +7,18 @@ # and Makefile.postamble (both optional), and Makefile will include them. # -NAME = tcopy +NAME = cksum PROJECTVERSION = 2.8 PROJECT_TYPE = Tool -CFILES = tcopy.c +HFILES = extern.h -OTHERSRCS = Makefile Makefile.preamble Makefile.postamble tcopy.1 +CFILES = cksum.c crc.c print.c sum1.c sum2.c crc32.c +OTHERSRCS = Makefile Makefile.preamble Makefile.postamble cksum.1 + +OTHER_CFLAGS=-D__FBSDID=__RCSID MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC @@ -28,14 +31,14 @@ PROF_LIBS = $(LIBS) -NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/developer_cmds/Build +NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/doc_cmds/Build NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc NEXTSTEP_JAVA_COMPILER = /usr/bin/javac WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe -PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac +PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac include $(MAKEFILEDIR)/platform.make diff --git a/cksum/Makefile.postamble b/cksum/Makefile.postamble new file mode 100644 index 0000000..a0b1af9 --- /dev/null +++ b/cksum/Makefile.postamble @@ -0,0 +1,5 @@ +include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common + +after_install:: + $(LINKPRODUCT) $(DSTROOT)$(INSTALLDIR)/sum + $(LN) -f $(DSTROOT)/usr/share/man/man1/cksum.1 $(DSTROOT)/usr/share/man/man1/sum.1 diff --git a/tcopy/Makefile.preamble b/cksum/Makefile.preamble similarity index 100% rename from tcopy/Makefile.preamble rename to cksum/Makefile.preamble diff --git a/tcopy/PB.project b/cksum/PB.project similarity index 75% rename from tcopy/PB.project rename to cksum/PB.project index d628535..63b0f64 100644 --- a/tcopy/PB.project +++ b/cksum/PB.project @@ -2,21 +2,22 @@ DYNAMIC_CODE_GEN = YES; FILESTABLE = { FRAMEWORKS = (); - OTHER_LINKED = (tcopy.c); - OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, tcopy.1); + H_FILES = (extern.h); + OTHER_LINKED = (cksum.c, crc.c, print.c, sum1.c, sum2.c); + OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, cksum.1, sum.1); }; LANGUAGE = English; LOCALIZABLE_FILES = {}; MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; - NEXTSTEP_BUILDDIR = /tmp/developer_cmds/Build; + NEXTSTEP_BUILDDIR = /tmp/doc_cmds/Build; NEXTSTEP_BUILDTOOL = /bin/gnumake; NEXTSTEP_INSTALLDIR = /usr/bin; NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; - PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; + PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac"; PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = tcopy; + PROJECTNAME = cksum; PROJECTTYPE = Tool; PROJECTVERSION = 2.8; WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; diff --git a/cksum/cksum.1 b/cksum/cksum.1 new file mode 100644 index 0000000..b4161fe --- /dev/null +++ b/cksum/cksum.1 @@ -0,0 +1,182 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, Inc. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 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. +.\" +.\" @(#)cksum.1 8.2 (Berkeley) 4/28/95 +.\" $FreeBSD: src/usr.bin/cksum/cksum.1,v 1.19 2005/01/17 07:44:13 ru Exp $ +.\" +.Dd April 28, 1995 +.Dt CKSUM 1 +.Os +.Sh NAME +.Nm cksum , +.Nm sum +.Nd display file checksums and block counts +.Sh SYNOPSIS +.Nm +.Op Fl o Ar 1 | 2 | 3 +.Op Ar +.Nm sum +.Op Ar +.Sh DESCRIPTION +The +.Nm +utility writes to the standard output three whitespace separated +fields for each input file. +These fields are a checksum +.Tn CRC , +the total number of octets in the file and the file name. +If no file name is specified, the standard input is used and no file name +is written. +.Pp +The +.Nm sum +utility is identical to the +.Nm +utility, except that it defaults to using historic algorithm 1, as +described below. +It is provided for compatibility only. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl o +Use historic algorithms instead of the (superior) default one. +.Pp +Algorithm 1 is the algorithm used by historic +.Bx +systems as the +.Xr sum 1 +algorithm and by historic +.At V +systems as the +.Xr sum 1 +algorithm when using the +.Fl r +option. +This is a 16-bit checksum, with a right rotation before each addition; +overflow is discarded. +.Pp +Algorithm 2 is the algorithm used by historic +.At V +systems as the +default +.Xr sum 1 +algorithm. +This is a 32-bit checksum, and is defined as follows: +.Bd -unfilled -offset indent +s = sum of all bytes; +r = s % 2^16 + (s % 2^32) / 2^16; +cksum = (r % 2^16) + r / 2^16; +.Ed +.Pp +Algorithm 3 is what is commonly called the +.Ql 32bit CRC +algorithm. +This is a 32-bit checksum. +.Pp +Both algorithm 1 and 2 write to the standard output the same fields as +the default algorithm except that the size of the file in bytes is +replaced with the size of the file in blocks. +For historic reasons, the block size is 1024 for algorithm 1 and 512 +for algorithm 2. +Partial blocks are rounded up. +.El +.Pp +The default +.Tn CRC +used is based on the polynomial used for +.Tn CRC +error checking +in the networking standard +.St -iso8802-3 . +The +.Tn CRC +checksum encoding is defined by the generating polynomial: +.Pp +.Bd -unfilled -offset indent +G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 +.Ed +.Pp +Mathematically, the +.Tn CRC +value corresponding to a given file is defined by +the following procedure: +.Bd -ragged -offset indent +The +.Ar n +bits to be evaluated are considered to be the coefficients of a mod 2 +polynomial M(x) of degree +.Ar n Ns \-1 . +These +.Ar n +bits are the bits from the file, with the most significant bit being the most +significant bit of the first octet of the file and the last bit being the least +significant bit of the last octet, padded with zero bits (if necessary) to +achieve an integral number of octets, followed by one or more octets +representing the length of the file as a binary value, least significant octet +first. +The smallest number of octets capable of representing this integer are used. +.Pp +M(x) is multiplied by x^32 (i.e., shifted left 32 bits) and divided by +G(x) using mod 2 division, producing a remainder R(x) of degree <= 31. +.Pp +The coefficients of R(x) are considered to be a 32-bit sequence. +.Pp +The bit sequence is complemented and the result is the CRC. +.Ed +.Sh EXIT STATUS +.Ex -std cksum sum +.Sh SEE ALSO +.Xr md5 1 +.Pp +The default calculation is identical to that given in pseudo-code +in the following +.Tn ACM +article. +.Rs +.%T "Computation of Cyclic Redundancy Checks Via Table Lookup" +.%A Dilip V. Sarwate +.%J "Communications of the" Tn ACM +.%D "August 1988" +.Re +.Sh STANDARDS +The +.Nm +utility is expected to conform to +.St -p1003.2-92 . +.Sh HISTORY +The +.Nm +utility appeared in +.Bx 4.4 . diff --git a/mkfifo/mkfifo.c b/cksum/cksum.c similarity index 53% copy from mkfifo/mkfifo.c copy to cksum/cksum.c index 6bd45b0..51fdd17 100644 --- a/mkfifo/mkfifo.c +++ b/cksum/cksum.c @@ -1,9 +1,10 @@ -/* $NetBSD: mkfifo.c,v 1.8 1997/10/19 05:11:54 lukem Exp $ */ - -/* - * Copyright (c) 1990, 1993 +/*- + * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * + * This code is derived from software contributed to Berkeley by + * James W. Williams of NASA Goddard Space Flight Center. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,81 +34,114 @@ * SUCH DAMAGE. */ -#include #ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1990, 1993\n\ - The Regents of the University of California. All rights reserved.\n"); +static const char copyright[] = +"@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 -static char sccsid[] = "@(#)mkfifo.c 8.2 (Berkeley) 1/5/94"; +static char sccsid[] = "@(#)cksum.c 8.2 (Berkeley) 4/28/95"; #endif -__RCSID("$NetBSD: mkfifo.c,v 1.8 1997/10/19 05:11:54 lukem Exp $"); #endif /* not lint */ +#include +__FBSDID("$FreeBSD: src/usr.bin/cksum/cksum.c,v 1.17 2003/03/13 23:32:28 robert Exp $"); + +#include + +#include +#include +#include #include #include #include -#include -#include -#include -#include #include -#include -int main __P((int, char **)); -static void usage __P((void)); +#include "extern.h" + +static void usage(void); int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char **argv) { - int ch, exitval; - void * set; - mode_t mode; - - setlocale (LC_ALL, ""); + uint32_t val; + int ch, fd, rval; + off_t len; + char *fn, *p; + int (*cfncn)(int, uint32_t *, off_t *); + void (*pfncn)(char *, u_int32_t, off_t); + + cfncn=NULL; - /* The default mode is the value of the bitwise inclusive or of - S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, and S_IWOTH - modified by the file creation mask */ - mode = 0666 & ~umask(0); + if(*argv) { + if ((p = rindex(argv[0], '/')) == NULL) + p = argv[0]; + else + ++p; + if (!strcmp(p, "sum")) { + cfncn = csum1; + pfncn = psum1; + ++argv; + } + } + + if(!cfncn) { + cfncn = crc; + pfncn = pcrc; - while ((ch = getopt(argc, argv, "m:")) != -1) - switch(ch) { - case 'm': - if (!(set = setmode(optarg))) { - errx(1, "invalid file mode."); - /* NOTREACHED */ + while ((ch = getopt(argc, argv, "o:")) != -1) + switch (ch) { + case 'o': + if (!strcmp(optarg, "1")) { + cfncn = csum1; + pfncn = psum1; + } else if (!strcmp(optarg, "2")) { + cfncn = csum2; + pfncn = psum2; + } else if (!strcmp(optarg, "3")) { + cfncn = crc32; + pfncn = pcrc; + } else { + warnx("illegal argument to -o option"); + usage(); + } + break; + case '?': + default: + usage(); } - /* In symbolic mode strings, the + and - operators are - interpreted relative to an assumed initial mode of - a=rw. */ - mode = getmode (set, 0666); - break; - case '?': - default: - usage(); - } - argc -= optind; - argv += optind; - if (argv[0] == NULL) - usage(); + argc -= optind; + argv += optind; + } - for (exitval = 0; *argv; ++argv) { - if (mkfifo(*argv, mode) < 0) { - warn("%s", *argv); - exitval = 1; + fd = STDIN_FILENO; + fn = NULL; + rval = 0; + do { + if (*argv) { + fn = *argv++; + if ((fd = open(fn, O_RDONLY, 0)) < 0) { + warn("%s", fn); + rval = 1; + continue; + } } - } - exit(exitval); + if (cfncn(fd, &val, &len)) { + warn("%s", fn ? fn : "stdin"); + rval = 1; + } else + pfncn(fn, val, len); + (void)close(fd); + } while (*argv); + exit(rval); } -void -usage() +static void +usage(void) { - (void)fprintf(stderr, "usage: mkfifo [-m mode] fifoname ...\n"); + (void)fprintf(stderr, "usage: cksum [-o 1 | 2 | 3] [file ...]\n"); + (void)fprintf(stderr, " sum [file ...]\n"); exit(1); } diff --git a/cksum/crc.c b/cksum/crc.c index b1a2f85..92693e8 100644 --- a/cksum/crc.c +++ b/cksum/crc.c @@ -38,14 +38,18 @@ #if 0 static char sccsid[] = "@(#)crc.c 8.1 (Berkeley) 6/17/93"; #endif -static const char rcsid[] = - "$FreeBSD: src/usr.bin/cksum/crc.c,v 1.4 1999/12/05 20:03:21 charnier Exp $"; #endif /* not lint */ +#include +__FBSDID("$FreeBSD: src/usr.bin/cksum/crc.c,v 1.8 2003/03/13 23:32:28 robert Exp $"); #include + +#include #include -static const u_int32_t crctab[] = { +#include "extern.h" + +static const uint32_t crctab[] = { 0x0, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, @@ -106,25 +110,24 @@ static const u_int32_t crctab[] = { * locations to store the crc and the number of bytes read. It returns 0 on * success and 1 on failure. Errno is set on failure. */ -u_int32_t crc_total = ~0; /* The crc over a number of files. */ +uint32_t crc_total = ~0; /* The crc over a number of files. */ int -crc(fd, cval, clen) - register int fd; - u_int32_t *cval, *clen; +crc(int fd, uint32_t *cval, off_t *clen) { - register u_char *p; - register int nr; - register u_int32_t crc, len; + uint32_t lcrc; + int nr; + off_t len; + u_char *p; u_char buf[16 * 1024]; #define COMPUTE(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)] - crc = len = 0; + lcrc = len = 0; crc_total = ~crc_total; while ((nr = read(fd, buf, sizeof(buf))) > 0) for (len += nr, p = buf; nr--; ++p) { - COMPUTE(crc, *p); + COMPUTE(lcrc, *p); COMPUTE(crc_total, *p); } if (nr < 0) @@ -134,11 +137,11 @@ crc(fd, cval, clen) /* Include the length of the file. */ for (; len != 0; len >>= 8) { - COMPUTE(crc, len & 0xff); + COMPUTE(lcrc, len & 0xff); COMPUTE(crc_total, len & 0xff); } - *cval = ~crc; + *cval = ~lcrc; crc_total = ~crc_total; return (0); } diff --git a/cksum/crc32.c b/cksum/crc32.c new file mode 100644 index 0000000..fa8f900 --- /dev/null +++ b/cksum/crc32.c @@ -0,0 +1,122 @@ +/* + * This code implements the AUTODIN II polynomial used by Ethernet, + * and can be used to calculate multicast address hash indices. + * It assumes that the low order bits will be transmitted first, + * and consequently the low byte should be sent first when + * the crc computation is finished. The crc should be complemented + * before transmission. + * The variable corresponding to the macro argument "crc" should + * be an unsigned long and should be preset to all ones for Ethernet + * use. An error-free packet will leave 0xDEBB20E3 in the crc. + * Spencer Garrett + */ + +#include +__FBSDID("$FreeBSD: src/usr.bin/cksum/crc32.c,v 1.9 2003/03/13 23:32:28 robert Exp $"); + +#include + +#include +#include +#include + +#include "extern.h" + +#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) + +/* generated using the AUTODIN II polynomial + * x^32 + x^26 + x^23 + x^22 + x^16 + + * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1 + */ +static const uint32_t crctab[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + +uint32_t crc32_total = 0; + +int +crc32(int fd, uint32_t *cval, off_t *clen) +{ + uint32_t lcrc = ~0; + int nr ; + off_t len ; + char buf[BUFSIZ], *p ; + + len = 0 ; + crc32_total = ~crc32_total ; + while ((nr = read(fd, buf, sizeof(buf))) > 0) + for (len += nr, p = buf; nr--; ++p) { + CRC(lcrc, *p) ; + CRC(crc32_total, *p) ; + } + if (nr < 0) + return 1 ; + + *clen = len ; + *cval = ~lcrc ; + crc32_total = ~crc32_total ; + return 0 ; +} diff --git a/mtree/extern.h b/cksum/extern.h similarity index 78% copy from mtree/extern.h copy to cksum/extern.h index c91086a..e9b594a 100644 --- a/mtree/extern.h +++ b/cksum/extern.h @@ -31,20 +31,17 @@ * SUCH DAMAGE. * * @(#)extern.h 8.1 (Berkeley) 6/6/93 - * $FreeBSD: src/usr.sbin/mtree/extern.h,v 1.3.2.2 2000/06/28 02:33:17 joe Exp $ + * $FreeBSD: src/usr.bin/cksum/extern.h,v 1.6 2003/03/13 23:32:28 robert Exp $ */ -int compare __P((char *, NODE *, FTSENT *)); -int crc __P((int, u_long *, u_long *)); -void cwalk __P((void)); -char *flags_to_string __P((u_long)); +#include -char *inotype __P((u_int)); -u_int parsekey __P((char *, int *)); -char *rlink __P((char *)); -NODE *spec __P((void)); -int verify __P((void)); - -int check_excludes __P((const char *, const char *)); -void init_excludes __P((void)); -void read_excludes_file __P((const char *)); +__BEGIN_DECLS +int crc(int, uint32_t *, off_t *); +void pcrc(char *, uint32_t, off_t); +void psum1(char *, uint32_t, off_t); +void psum2(char *, uint32_t, off_t); +int csum1(int, uint32_t *, off_t *); +int csum2(int, uint32_t *, off_t *); +int crc32(int, uint32_t *, off_t *); +__END_DECLS diff --git a/mtree/extern.h b/cksum/print.c similarity index 68% copy from mtree/extern.h copy to cksum/print.c index c91086a..4d732d9 100644 --- a/mtree/extern.h +++ b/cksum/print.c @@ -29,22 +29,47 @@ * 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. - * - * @(#)extern.h 8.1 (Berkeley) 6/6/93 - * $FreeBSD: src/usr.sbin/mtree/extern.h,v 1.3.2.2 2000/06/28 02:33:17 joe Exp $ */ -int compare __P((char *, NODE *, FTSENT *)); -int crc __P((int, u_long *, u_long *)); -void cwalk __P((void)); -char *flags_to_string __P((u_long)); +#ifndef lint +#if 0 +static char sccsid[] = "@(#)print.c 8.1 (Berkeley) 6/6/93"; +#endif +#endif /* not lint */ + +#include +__FBSDID("$FreeBSD: src/usr.bin/cksum/print.c,v 1.7 2003/03/13 23:32:28 robert Exp $"); + +#include + +#include +#include + +#include "extern.h" + +void +pcrc(char *fn, uint32_t val, off_t len) +{ + (void)printf("%lu %jd", (u_long)val, (intmax_t)len); + if (fn != NULL) + (void)printf(" %s", fn); + (void)printf("\n"); +} -char *inotype __P((u_int)); -u_int parsekey __P((char *, int *)); -char *rlink __P((char *)); -NODE *spec __P((void)); -int verify __P((void)); +void +psum1(char *fn, uint32_t val, off_t len) +{ + (void)printf("%lu %jd", (u_long)val, (intmax_t)(len + 1023) / 1024); + if (fn != NULL) + (void)printf(" %s", fn); + (void)printf("\n"); +} -int check_excludes __P((const char *, const char *)); -void init_excludes __P((void)); -void read_excludes_file __P((const char *)); +void +psum2(char *fn, uint32_t val, off_t len) +{ + (void)printf("%lu %jd", (u_long)val, (intmax_t)(len + 511) / 512); + if (fn != NULL) + (void)printf(" %s", fn); + (void)printf("\n"); +} diff --git a/mtree/extern.h b/cksum/sum1.c similarity index 70% copy from mtree/extern.h copy to cksum/sum1.c index c91086a..f3c05ce 100644 --- a/mtree/extern.h +++ b/cksum/sum1.c @@ -29,22 +29,48 @@ * 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. - * - * @(#)extern.h 8.1 (Berkeley) 6/6/93 - * $FreeBSD: src/usr.sbin/mtree/extern.h,v 1.3.2.2 2000/06/28 02:33:17 joe Exp $ */ -int compare __P((char *, NODE *, FTSENT *)); -int crc __P((int, u_long *, u_long *)); -void cwalk __P((void)); -char *flags_to_string __P((u_long)); +#ifndef lint +#if 0 +static char sccsid[] = "@(#)sum1.c 8.1 (Berkeley) 6/6/93"; +#endif +#endif /* not lint */ + +#include +__FBSDID("$FreeBSD: src/usr.bin/cksum/sum1.c,v 1.8 2003/03/13 23:32:28 robert Exp $"); + +#include + +#include +#include + +#include "extern.h" + +int +csum1(int fd, uint32_t *cval, off_t *clen) +{ + int nr; + u_int lcrc; + off_t total; + u_char *p; + u_char buf[8192]; -char *inotype __P((u_int)); -u_int parsekey __P((char *, int *)); -char *rlink __P((char *)); -NODE *spec __P((void)); -int verify __P((void)); + /* + * 16-bit checksum, rotating right before each addition; + * overflow is discarded. + */ + lcrc = total = 0; + while ((nr = read(fd, buf, sizeof(buf))) > 0) + for (total += nr, p = buf; nr--; ++p) { + if (lcrc & 1) + lcrc |= 0x10000; + lcrc = ((lcrc >> 1) + *p) & 0xffff; + } + if (nr < 0) + return (1); -int check_excludes __P((const char *, const char *)); -void init_excludes __P((void)); -void read_excludes_file __P((const char *)); + *cval = lcrc; + *clen = total; + return (0); +} diff --git a/mtree/extern.h b/cksum/sum2.c similarity index 68% copy from mtree/extern.h copy to cksum/sum2.c index c91086a..83ca362 100644 --- a/mtree/extern.h +++ b/cksum/sum2.c @@ -29,22 +29,50 @@ * 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. - * - * @(#)extern.h 8.1 (Berkeley) 6/6/93 - * $FreeBSD: src/usr.sbin/mtree/extern.h,v 1.3.2.2 2000/06/28 02:33:17 joe Exp $ */ -int compare __P((char *, NODE *, FTSENT *)); -int crc __P((int, u_long *, u_long *)); -void cwalk __P((void)); -char *flags_to_string __P((u_long)); +#ifndef lint +#if 0 +static char sccsid[] = "@(#)sum2.c 8.1 (Berkeley) 6/6/93"; +#endif +#endif /* not lint */ +#include +__FBSDID("$FreeBSD: src/usr.bin/cksum/sum2.c,v 1.8 2003/03/13 23:32:28 robert Exp $"); + +#include + +#include +#include + +#include "extern.h" + +int +csum2(int fd, uint32_t *cval, off_t *clen) +{ + uint32_t lcrc; + int nr; + off_t total; + u_char *p; + u_char buf[8192]; + + /* + * Draft 8 POSIX 1003.2: + * + * s = sum of all bytes + * r = s % 2^16 + (s % 2^32) / 2^16 + * lcrc = (r % 2^16) + r / 2^16 + */ + lcrc = total = 0; + while ((nr = read(fd, buf, sizeof(buf))) > 0) + for (total += nr, p = buf; nr--; ++p) + lcrc += *p; + if (nr < 0) + return (1); -char *inotype __P((u_int)); -u_int parsekey __P((char *, int *)); -char *rlink __P((char *)); -NODE *spec __P((void)); -int verify __P((void)); + lcrc = (lcrc & 0xffff) + (lcrc >> 16); + lcrc = (lcrc & 0xffff) + (lcrc >> 16); -int check_excludes __P((const char *, const char *)); -void init_excludes __P((void)); -void read_excludes_file __P((const char *)); + *cval = lcrc; + *clen = total; + return (0); +} diff --git a/compress/Makefile b/compress/Makefile index 9478ad1..f312cf5 100644 --- a/compress/Makefile +++ b/compress/Makefile @@ -17,7 +17,7 @@ CFILES = compress.c zopen.c OTHERSRCS = Makefile Makefile.preamble Makefile.postamble compress.1\ zopen.3 uncompress.1 zopen.h -NEXTSTEP_PB_CFLAGS += -D__FBSDID=__RCSID -D"__printflike(a,b)=" +NEXTSTEP_PB_CFLAGS += -D__FBSDID=__RCSID MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC diff --git a/compress/compress.c b/compress/compress.c index 14b509f..03311f9 100644 --- a/compress/compress.c +++ b/compress/compress.c @@ -78,6 +78,8 @@ main(int argc, char *argv[]) int bits, ch; char *p, newname[MAXPATHLEN]; + if (argc < 1) + usage(1); cat = 0; if ((p = rindex(argv[0], '/')) == NULL) p = argv[0]; @@ -402,10 +404,10 @@ setfile(const char *name, struct stat *fs) cwarn("chown: %s", name); fs->st_mode &= ~(S_ISUID|S_ISGID); } - if (chmod(name, fs->st_mode) && errno != EOPNOTSUPP) + if (chmod(name, fs->st_mode) && errno != ENOTSUP) cwarn("chmod: %s", name); - if (chflags(name, fs->st_flags) && errno != EOPNOTSUPP) + if (chflags(name, fs->st_flags) && errno != ENOTSUP) cwarn("chflags: %s", name); } diff --git a/cp/Makefile b/cp/Makefile index e128766..774bbfd 100644 --- a/cp/Makefile +++ b/cp/Makefile @@ -18,6 +18,7 @@ CFILES = cp.c utils.c OTHERSRCS = Makefile Makefile.preamble Makefile.postamble cp.1 +OTHER_CFLAGS = -D__FBSDID=__RCSID MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC diff --git a/cp/cp.1 b/cp/cp.1 index 81825dd..17ecd81 100644 --- a/cp/cp.1 +++ b/cp/cp.1 @@ -1,3 +1,4 @@ +.\"- .\" Copyright (c) 1989, 1990, 1993, 1994 .\" The Regents of the University of California. All rights reserved. .\" @@ -12,10 +13,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 the University of -.\" California, Berkeley and its contributors. .\" 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. @@ -33,34 +30,34 @@ .\" SUCH DAMAGE. .\" .\" @(#)cp.1 8.3 (Berkeley) 4/18/94 -.\" $FreeBSD: src/bin/cp/cp.1,v 1.25 2002/08/16 03:13:59 johan Exp $ +.\" $FreeBSD: src/bin/cp/cp.1,v 1.33 2005/02/25 00:40:46 trhodes Exp $ .\" -.Dd July 23, 2002 +.Dd February 23, 2005 .Dt CP 1 .Os .Sh NAME .Nm cp .Nd copy files .Sh SYNOPSIS -.Nm +.Nm cp .Oo .Fl R .Op Fl H | Fl L | Fl P .Oc -.Op Fl f | i | n -.Op Fl pv +.Op Fl fi | n +.Op Fl pvX .Ar source_file target_file -.Nm +.Nm cp .Oo .Fl R .Op Fl H | Fl L | Fl P .Oc -.Op Fl f | i | n -.Op Fl pv +.Op Fl fi | n +.Op Fl pvX .Ar source_file ... target_directory .Sh DESCRIPTION In the first synopsis form, the -.Nm +.Nm cp utility copies the contents of the .Ar source_file to the @@ -72,47 +69,11 @@ is copied to the destination .Ar target_directory . The names of the files themselves are not changed. If -.Nm +.Nm cp detects an attempt to copy a file to itself, the copy will fail. .Pp The following options are available: .Bl -tag -width flag -.It Fl H -If the -.Fl R -option is specified, symbolic links on the command line are followed. -(Symbolic links encountered in the tree traversal are not followed.) -.It Fl L -If the -.Fl R -option is specified, all symbolic links are followed. -.It Fl P -If the -.Fl R -option is specified, no symbolic links are followed. -This is the default. -.It Fl R -If -.Ar source_file -designates a directory, -.Nm -copies the directory and the entire subtree connected at that point. -This option also causes symbolic links to be copied, rather than -indirected through, and for -.Nm -to create special files rather than copying them as normal files. -Created directories have the same mode as the corresponding source -directory, unmodified by the process' umask. -.Pp -Note that -.Nm -copies hard linked files as separate files. -If you need to preserve hard links, consider using -.Xr tar 1 , -.Xr cpio 1 , -or -.Xr pax 1 -instead. .It Fl f For each existing destination pathname, remove it and create a new file, without prompting for confirmation @@ -121,12 +82,18 @@ regardless of its permissions. .Fl f option overrides any previous .Fl n -option, but not -.Fl i -option. See also the legacy section.) +option.) +.Pp +The target file is not unlinked before the copy. +Thus, any existing access rights will be retained. +.It Fl H +If the +.Fl R +option is specified, symbolic links on the command line are followed. +(Symbolic links encountered in the tree traversal are not followed.) .It Fl i Cause -.Nm +.Nm cp to write a prompt to the standard error output before copying a file that would overwrite an existing file. If the response from the standard input begins with the character @@ -137,10 +104,12 @@ the file copy is attempted. (The .Fl i option overrides any previous -.Fl f -or .Fl n -options.) +option.) +.It Fl L +If the +.Fl R +option is specified, all symbolic links are followed. .It Fl n Do not overwrite an existing file. (The @@ -150,33 +119,77 @@ option overrides any previous or .Fl i options.) +.It Fl P +If the +.Fl R +option is specified, no symbolic links are followed. +This is the default. .It Fl p Cause -.Nm -to preserve in the copy as many of the modification time, access time, -file flags, file mode, user ID, and group ID as allowed by permissions. +.Nm cp +to preserve the following attributes of each source +file in the copy: modification time, access time, +file flags, file mode, user ID, and group ID, as allowed by permissions. +Access Control Lists (ACLs) will also be preserved. .Pp If the user ID and group ID cannot be preserved, no error message is displayed and the exit value is not altered. .Pp -If the source file has its set user ID bit on and the user ID cannot -be preserved, the set user ID bit is not preserved +If the source file has its set-user-ID bit on and the user ID cannot +be preserved, the set-user-ID bit is not preserved in the copy's permissions. -If the source file has its set group ID bit on and the group ID cannot -be preserved, the set group ID bit is not preserved +If the source file has its set-group-ID bit on and the group ID cannot +be preserved, the set-group-ID bit is not preserved in the copy's permissions. -If the source file has both its set user ID and set group ID bits on, +If the source file has both its set-user-ID and set-group-ID bits on, and either the user ID or group ID cannot be preserved, neither -the set user ID nor set group ID bits are preserved in the copy's +the set-user-ID nor set-group-ID bits are preserved in the copy's permissions. +.It Fl R +If +.Ar source_file +designates a directory, +.Nm cp +copies the directory and the entire subtree connected at that point. +If the +.Ar source_file +ends in a +.Pa / , +the contents of the directory are copied rather than the +directory itself. +This option also causes symbolic links to be copied, rather than +indirected through, and for +.Nm cp +to create special files rather than copying them as normal files. +Created directories have the same mode as the corresponding source +directory, unmodified by the process' umask. +.Pp +In +.Fl R +mode, +.Nm cp +will continue copying even if errors are detected. +.Pp +Note that +.Nm cp +copies hard-linked files as separate files. +If you need to preserve hard links, consider using +.Xr tar 1 , +.Xr cpio 1 , +or +.Xr pax 1 +instead. .It Fl v Cause -.Nm +.Nm cp to be verbose, showing files as they are copied. +.It Fl X +Do not copy Extended Attributes (EAs) or resource forks. .El .Pp For each destination file that already exists, its contents are -overwritten if permissions allow. Its mode, user ID, and group +overwritten if permissions allow. +Its mode, user ID, and group ID are unchanged unless the .Fl p option was specified. @@ -194,13 +207,13 @@ used as modified by the file mode creation mask .Pf ( Ic umask , see .Xr csh 1 ) . -If the source file has its set user ID bit on, that bit is removed +If the source file has its set-user-ID bit on, that bit is removed unless both the source file and the destination file are owned by the same user. -If the source file has its set group ID bit on, that bit is removed +If the source file has its set-group-ID bit on, that bit is removed unless both the source file and the destination file are in the same group and the user is a member of that group. -If both the set user ID and set group ID bits are set, all of the above +If both the set-user-ID and set-group-ID bits are set, all of the above conditions must be fulfilled or both bits are removed. .Pp Appropriate permissions are required for file creation or overwriting. @@ -225,17 +238,28 @@ options are ignored unless the option is specified. In addition, these options override each other and the command's actions are determined by the last one specified. -.Sh DIAGNOSTICS +.Pp +If +.Nm cp +receives a +.Dv SIGINFO +(see the +.Cm status +argument for +.Xr stty 1 ) +signal, the current input and output file and the percentage complete +will be written to the standard output. +.Sh EXIT STATUS .Ex -std .Sh COMPATIBILITY Historic versions of the -.Nm +.Nm cp utility had a .Fl r option. -This implementation supports that option, however, its use is strongly -discouraged, as it does not correctly copy special files, symbolic links -or fifo's. +This implementation supports that option; +however, its use is strongly discouraged, +as it does not correctly copy special files, symbolic links, or fifo's. .Pp The .Fl v @@ -243,12 +267,18 @@ and .Fl n options are non-standard and their use in scripts is not recommended. .Sh LEGACY DESCRIPTION -When invoked in legacy mode, both -.Fl n , -.Fl i -options are overridden by the +In legacy mode, .Fl f -option. +will override +.Fl i . +Also, under the +.Fl f +option, the target file is always unlinked before the copy. +Thus, new access rights will always be set. +.Pp +In +.Fl R +mode, copying will terminate if an error is encountered. .Sh SEE ALSO .Xr mv 1 , .Xr rcp 1 , @@ -258,14 +288,12 @@ option. .Xr symlink 7 .Sh STANDARDS The -.Nm +.Nm cp command is expected to be .St -p1003.2 -compatible. It is also -.St -susv3 -conformant. +compatible. .Sh HISTORY A -.Nm +.Nm cp command appeared in .At v1 . diff --git a/cp/cp.c b/cp/cp.c index 7e9dc8f..f421cc9 100644 --- a/cp/cp.c +++ b/cp/cp.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1988, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -13,10 +13,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 the University of - * California, Berkeley and its contributors. * 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. @@ -34,6 +30,7 @@ * SUCH DAMAGE. */ +#if 0 #ifndef lint static char const copyright[] = "@(#) Copyright (c) 1988, 1993, 1994\n\ @@ -41,12 +38,11 @@ static char const copyright[] = #endif /* not lint */ #ifndef lint -#if 0 static char sccsid[] = "@(#)cp.c 8.2 (Berkeley) 4/1/94"; -#endif #endif /* not lint */ +#endif #include -__RCSID("$FreeBSD: src/bin/cp/cp.c,v 1.42 2002/09/22 11:15:56 mckay Exp $"); +__FBSDID("$FreeBSD: src/bin/cp/cp.c,v 1.52 2005/09/05 04:36:08 csjp Exp $"); /* * Cp copies source files to target files. @@ -63,13 +59,14 @@ __RCSID("$FreeBSD: src/bin/cp/cp.c,v 1.42 2002/09/22 11:15:56 mckay Exp $"); * in "to") to form the final target path. */ -#include +#include #include #include #include #include #include +#include #include #include #include @@ -77,9 +74,11 @@ __RCSID("$FreeBSD: src/bin/cp/cp.c,v 1.42 2002/09/22 11:15:56 mckay Exp $"); #ifdef __APPLE__ #include -#endif +#include +#else /* !__APPLE__ */ +#define COMPAT_MODE(a,b) (1) +#endif /* __APPLE__ */ -#include "get_compat.h" #include "extern.h" #define STRIP_TRAILING_SLASH(p) { \ @@ -92,12 +91,17 @@ static char emptystring[] = ""; PATH_T to = { to.p_path, emptystring, "" }; int fflag, iflag, nflag, pflag, vflag; +#ifdef __APPLE__ +int Xflag; +#endif /* __APPLE__ */ static int Rflag, rflag; +volatile sig_atomic_t info; enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; static int copy(char *[], enum op, int); static int mastercmp(const FTSENT * const *, const FTSENT * const *); +static void siginfo(int __unused); int main(int argc, char *argv[]) @@ -108,7 +112,7 @@ main(int argc, char *argv[]) char *target; Hflag = Lflag = Pflag = 0; - while ((ch = getopt(argc, argv, "HLPRfinprv")) != -1) + while ((ch = getopt(argc, argv, "HLPRXfinprv")) != -1) switch (ch) { case 'H': Hflag = 1; @@ -125,17 +129,23 @@ main(int argc, char *argv[]) case 'R': Rflag = 1; break; + case 'X': + Xflag = 1; + break; case 'f': fflag = 1; /* Determine if the STD is SUSv3 or Legacy */ - if (compat_mode("bin/cp", "unix2003")) + if (COMPAT_MODE("bin/cp", "unix2003")) nflag = 0; /* reset nflag, but not iflag */ else iflag = nflag = 0; /* reset both */ break; case 'i': iflag = 1; - fflag = nflag = 0; + if (COMPAT_MODE("bin/cp", "unix2003")) + nflag = 0; /* reset nflag, but not fflag */ + else + fflag = nflag = 0; break; case 'n': nflag = 1; @@ -182,6 +192,7 @@ main(int argc, char *argv[]) fts_options &= ~FTS_PHYSICAL; fts_options |= FTS_LOGICAL | FTS_COMFOLLOW; } + (void)signal(SIGINFO, siginfo); /* Save the target base in "to". */ target = argv[--argc]; @@ -261,7 +272,7 @@ main(int argc, char *argv[]) exit (copy(argv, type, fts_options)); } -int +static int copy(char *argv[], enum op type, int fts_options) { struct stat to_stat; @@ -371,11 +382,17 @@ copy(char *argv[], enum op type, int fts_options) * normally want to preserve them on directories. */ if (pflag) { + if (setfile(curr->fts_statp, -1)) + rval = 1; #ifdef __APPLE__ - copyfile(curr->fts_path, to.p_path, 0, COPYFILE_ACL); -#endif - if (setfile(curr->fts_statp, 0)) - rval = 1; + /* setfile will fail if writeattr is denied */ + if (copyfile(curr->fts_path, to.p_path, NULL, COPYFILE_ACL)<0) + warn("%s: unable to copy ACL to %s", curr->fts_path, to.p_path); +#else /* !__APPLE__ */ + if (preserve_dir_acls(curr->fts_statp, + curr->fts_accpath, to.p_path) != 0) + rval = 1; +#endif /* __APPLE__ */ } else { mode = curr->fts_statp->st_mode; if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) || @@ -428,7 +445,7 @@ copy(char *argv[], enum op type, int fts_options) case S_IFDIR: if (!Rflag && !rflag) { warnx("%s is a directory (not copied).", - curr->fts_path); + curr->fts_path); (void)fts_set(ftsp, curr, FTS_SKIP); badcp = rval = 1; break; @@ -444,10 +461,18 @@ copy(char *argv[], enum op type, int fts_options) if (dne) { if (mkdir(to.p_path, curr->fts_statp->st_mode | S_IRWXU) < 0) - err(1, "%s", to.p_path); + if (COMPAT_MODE("bin/cp", "unix2003")) { + warn("%s", to.p_path); + } else { + err(1, "%s", to.p_path); + } } else if (!S_ISDIR(to_stat.st_mode)) { errno = ENOTDIR; - err(1, "%s", to.p_path); + if (COMPAT_MODE("bin/cp", "unix2003")) { + warn("%s", to.p_path); + } else { + err(1, "%s", to.p_path); + } } /* * Arrange to correct directory attributes later @@ -456,8 +481,12 @@ copy(char *argv[], enum op type, int fts_options) */ curr->fts_number = pflag || dne; #ifdef __APPLE__ - copyfile(curr->fts_path, to.p_path, 0, COPYFILE_XATTR); -#endif + if (!Xflag) { + if (copyfile(curr->fts_path, to.p_path, NULL, COPYFILE_XATTR) < 0) + warn("%s: unable to copy extended attributes to %s", curr->fts_path, to.p_path); + /* ACL and mtime set in postorder traversal */ + } +#endif /* __APPLE__ */ break; case S_IFBLK: case S_IFCHR: @@ -488,6 +517,7 @@ copy(char *argv[], enum op type, int fts_options) } if (errno) err(1, "fts_read"); + fts_close(ftsp); return (rval); } @@ -499,7 +529,7 @@ copy(char *argv[], enum op type, int fts_options) * parent directory, whereas directories tend not to be. Copying the * files first reduces seeking. */ -int +static int mastercmp(const FTSENT * const *a, const FTSENT * const *b) { int a_info, b_info; @@ -516,3 +546,10 @@ mastercmp(const FTSENT * const *a, const FTSENT * const *b) return (1); return (0); } + +static void +siginfo(int sig __unused) +{ + + info = 1; +} diff --git a/cp/extern.h b/cp/extern.h index 66fea99..10a5211 100644 --- a/cp/extern.h +++ b/cp/extern.h @@ -10,10 +10,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 the University of - * California, Berkeley and its contributors. * 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. @@ -31,7 +27,7 @@ * SUCH DAMAGE. * * @(#)extern.h 8.2 (Berkeley) 4/1/94 - * $FreeBSD: src/bin/cp/extern.h,v 1.15 2002/07/23 00:42:56 johan Exp $ + * $FreeBSD: src/bin/cp/extern.h,v 1.20 2005/09/05 04:36:08 csjp Exp $ */ typedef struct { @@ -42,12 +38,18 @@ typedef struct { extern PATH_T to; extern int fflag, iflag, nflag, pflag, vflag; +#ifdef __APPLE__ +extern int Xflag; +#endif /* __APPLE__ */ +extern volatile sig_atomic_t info; __BEGIN_DECLS int copy_fifo(struct stat *, int); -int copy_file(FTSENT *, int); -int copy_link(FTSENT *, int); +int copy_file(const FTSENT *, int); +int copy_link(const FTSENT *, int); int copy_special(struct stat *, int); int setfile(struct stat *, int); +int preserve_dir_acls(struct stat *, char *, char *); +int preserve_fd_acls(int, int); void usage(void); __END_DECLS diff --git a/cp/utils.c b/cp/utils.c index 70dc376..2235939 100644 --- a/cp/utils.c +++ b/cp/utils.c @@ -10,10 +10,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 the University of - * California, Berkeley and its contributors. * 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. @@ -37,10 +33,11 @@ static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94"; #endif #endif /* not lint */ #include -__RCSID("$FreeBSD: src/bin/cp/utils.c,v 1.38 2002/07/31 16:52:16 markm Exp $"); +__FBSDID("$FreeBSD: src/bin/cp/utils.c,v 1.46 2005/09/05 04:36:08 csjp Exp $"); +#include +#include #include -#include #include #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED #include @@ -57,21 +54,27 @@ __RCSID("$FreeBSD: src/bin/cp/utils.c,v 1.38 2002/07/31 16:52:16 markm Exp $"); #include #ifdef __APPLE__ +#include #include #include #include -#endif +#include +#else +#define COMPAT_MODE(a,b) (1) +#endif /* __APPLE__ */ #include "extern.h" +#define cp_pct(x,y) (int)(100.0 * (double)(x) / (double)(y)) int -copy_file(FTSENT *entp, int dne) +copy_file(const FTSENT *entp, int dne) { static char buf[MAXBSIZE]; struct stat *fs; int ch, checkch, from_fd, rcount, rval, to_fd; ssize_t wcount; size_t wresid; + off_t wtotal; char *bufp; #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED char *p; @@ -97,8 +100,8 @@ copy_file(FTSENT *entp, int dne) if (nflag) { if (vflag) printf("%s not overwritten\n", to.p_path); - close(from_fd); - return (0); + (void)close(from_fd); + return (1); } else if (iflag) { (void)fprintf(stderr, "overwrite %s? %s", to.p_path, YESNO); @@ -112,15 +115,28 @@ copy_file(FTSENT *entp, int dne) } } - if (fflag) { - /* remove existing destination file name, - * create a new file */ - (void)unlink(to.p_path); - to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, - fs->st_mode & ~(S_ISUID | S_ISGID)); - } else - /* overwrite existing destination file name */ + if (COMPAT_MODE("bin/cp", "unix2003")) { + /* first try to overwrite existing destination file name */ to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); + if (to_fd == -1) { + if (fflag) { + /* Only if it fails remove file and create a new one */ + (void)unlink(to.p_path); + to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, + fs->st_mode & ~(S_ISUID | S_ISGID)); + } + } + } else { + if (fflag) { + /* remove existing destination file name, + * create a new file */ + (void)unlink(to.p_path); + to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, + fs->st_mode & ~(S_ISUID | S_ISGID)); + } else + /* overwrite existing destination file name */ + to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); + } } else to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, fs->st_mode & ~(S_ISUID | S_ISGID)); @@ -134,25 +150,25 @@ copy_file(FTSENT *entp, int dne) rval = 0; #ifdef __APPLE__ - if (S_ISREG(fs->st_mode)) { - struct statfs sfs; - - /* - * Pre-allocate blocks for the destination file if it - * resides on Xsan. - */ - if (fstatfs(to_fd, &sfs) == 0 && - strcmp(sfs.f_fstypename, "acfs") == 0) { - fstore_t fst; - - fst.fst_flags = 0; - fst.fst_posmode = F_PEOFPOSMODE; - fst.fst_offset = 0; - fst.fst_length = fs->st_size; - - (void) fcntl(to_fd, F_PREALLOCATE, &fst); - } - } + if (S_ISREG(fs->st_mode)) { + struct statfs sfs; + + /* + * Pre-allocate blocks for the destination file if it + * resides on Xsan. + */ + if (fstatfs(to_fd, &sfs) == 0 && + strcmp(sfs.f_fstypename, "acfs") == 0) { + fstore_t fst; + + fst.fst_flags = 0; + fst.fst_posmode = F_PEOFPOSMODE; + fst.fst_offset = 0; + fst.fst_length = fs->st_size; + + (void) fcntl(to_fd, F_PREALLOCATE, &fst); + } + } #endif /* __APPLE__ */ /* @@ -161,15 +177,26 @@ copy_file(FTSENT *entp, int dne) * wins some CPU back. */ #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED - if (S_ISREG(fs->st_mode) && fs->st_size <= 8 * 1048576) { + if (S_ISREG(fs->st_mode) && fs->st_size > 0 && + fs->st_size <= 8 * 1048576) { if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ, MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) { warn("%s", entp->fts_path); rval = 1; } else { + wtotal = 0; for (bufp = p, wresid = fs->st_size; ; bufp += wcount, wresid -= (size_t)wcount) { wcount = write(to_fd, bufp, wresid); + wtotal += wcount; + if (info) { + info = 0; + (void)fprintf(stderr, + "%s -> %s %3d%%\n", + entp->fts_path, to.p_path, + cp_pct(wtotal, fs->st_size)); + + } if (wcount >= (ssize_t)wresid || wcount <= 0) break; } @@ -186,10 +213,20 @@ copy_file(FTSENT *entp, int dne) } else #endif { + wtotal = 0; while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { for (bufp = buf, wresid = rcount; ; bufp += wcount, wresid -= wcount) { wcount = write(to_fd, bufp, wresid); + wtotal += wcount; + if (info) { + info = 0; + (void)fprintf(stderr, + "%s -> %s %3d%%\n", + entp->fts_path, to.p_path, + cp_pct(wtotal, fs->st_size)); + + } if (wcount >= (ssize_t)wresid || wcount <= 0) break; } @@ -205,12 +242,6 @@ copy_file(FTSENT *entp, int dne) } } -#ifdef __APPLE__ - if (pflag) - copyfile(entp->fts_path, to.p_path, 0, COPYFILE_XATTR | COPYFILE_ACL); - else - copyfile(entp->fts_path, to.p_path, 0, COPYFILE_XATTR); -#endif /* * Don't remove the target even after an error. The target might * not be a regular file, or its attributes might be important, @@ -218,8 +249,25 @@ copy_file(FTSENT *entp, int dne) * to remove it if we created it and its length is 0. */ +#ifdef __APPLE__ + /* do these before setfile in case copyfile changes mtime */ + if (!Xflag && S_ISREG(fs->st_mode)) { /* skip devices, etc */ + if (fcopyfile(from_fd, to_fd, NULL, COPYFILE_XATTR) < 0) + warn("%s: could not copy extended attributes to %s", entp->fts_path, to.p_path); + } if (pflag && setfile(fs, to_fd)) rval = 1; + if (pflag) { + /* If this ACL denies writeattr then setfile will fail... */ + if (fcopyfile(from_fd, to_fd, NULL, COPYFILE_ACL) < 0) + warn("%s: could not copy ACL to %s", entp->fts_path, to.p_path); + } +#else /* !__APPLE__ */ + if (pflag && setfile(fs, to_fd)) + rval = 1; + if (pflag && preserve_fd_acls(from_fd, to_fd) != 0) + rval = 1; +#endif /* __APPLE__ */ (void)close(from_fd); if (close(to_fd)) { warn("%s", to.p_path); @@ -229,7 +277,7 @@ copy_file(FTSENT *entp, int dne) } int -copy_link(FTSENT *p, int exists) +copy_link(const FTSENT *p, int exists) { int len; char llink[PATH_MAX]; @@ -248,9 +296,12 @@ copy_link(FTSENT *p, int exists) return (1); } #ifdef __APPLE__ - copyfile(p->fts_path, to.p_path, 0, COPYFILE_XATTR | COPYFILE_NOFOLLOW_SRC); + if (!Xflag) + if (copyfile(p->fts_path, to.p_path, NULL, COPYFILE_XATTR | COPYFILE_NOFOLLOW_SRC) <0) + warn("%s: could not copy extended attributes to %s", + p->fts_path, to.p_path); #endif - return (0); + return (pflag ? setfile(p->fts_statp, -1) : 0); } int @@ -264,7 +315,7 @@ copy_fifo(struct stat *from_stat, int exists) warn("mkfifo: %s", to.p_path); return (1); } - return (pflag ? setfile(from_stat, 0) : 0); + return (pflag ? setfile(from_stat, -1) : 0); } int @@ -278,7 +329,7 @@ copy_special(struct stat *from_stat, int exists) warn("mknod: %s", to.p_path); return (1); } - return (pflag ? setfile(from_stat, 0) : 0); + return (pflag ? setfile(from_stat, -1) : 0); } int @@ -286,20 +337,26 @@ setfile(struct stat *fs, int fd) { static struct timeval tv[2]; struct stat ts; - int rval; - int gotstat; + int rval, gotstat, islink, fdval; rval = 0; + fdval = fd != -1; + islink = !fdval && S_ISLNK(fs->st_mode); fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); - if (utimes(to.p_path, tv)) { - warn("utimes: %s", to.p_path); +#ifdef __APPLE__ + if (islink ? 0 : utimes(to.p_path, tv)) { +#else + if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) { +#endif /* __APPLE__ */ + warn("%sutimes: %s", islink ? "l" : "", to.p_path); rval = 1; } - if (fd ? fstat(fd, &ts) : stat(to.p_path, &ts)) + if (fdval ? fstat(fd, &ts) : + (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts))) gotstat = 0; else { gotstat = 1; @@ -313,37 +370,128 @@ setfile(struct stat *fs, int fd) * chown. If chown fails, lose setuid/setgid bits. */ if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid) - if (fd ? fchown(fd, fs->st_uid, fs->st_gid) : - chown(to.p_path, fs->st_uid, fs->st_gid)) { + if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) : + (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) : + chown(to.p_path, fs->st_uid, fs->st_gid))) { if (errno != EPERM) { - warn("chown: %s", to.p_path); + warn("%schown: %s", islink ? "l" : "", to.p_path); rval = 1; } fs->st_mode &= ~(S_ISUID | S_ISGID); } if (!gotstat || fs->st_mode != ts.st_mode) - if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) { - warn("chmod: %s", to.p_path); + if (fdval ? fchmod(fd, fs->st_mode) : + (islink ? lchmod(to.p_path, fs->st_mode) : + chmod(to.p_path, fs->st_mode))) { + warn("%schmod: %s", islink ? "l" : "", to.p_path); rval = 1; } if (!gotstat || fs->st_flags != ts.st_flags) - if (fd ? - fchflags(fd, fs->st_flags) : chflags(to.p_path, fs->st_flags)) { - warn("chflags: %s", to.p_path); + if (fdval ? + fchflags(fd, fs->st_flags) : + (islink ? lchflags(to.p_path, fs->st_flags) : + chflags(to.p_path, fs->st_flags))) { + warn("%schflags: %s", islink ? "l" : "", to.p_path); rval = 1; } return (rval); } +#ifndef __APPLE__ +int +preserve_fd_acls(int source_fd, int dest_fd) +{ + struct acl *aclp; + acl_t acl; + + if (fpathconf(source_fd, _PC_ACL_EXTENDED) != 1 || + fpathconf(dest_fd, _PC_ACL_EXTENDED) != 1) + return (0); + acl = acl_get_fd(source_fd); + if (acl == NULL) { + warn("failed to get acl entries while setting %s", to.p_path); + return (1); + } + aclp = &acl->ats_acl; + if (aclp->acl_cnt == 3) + return (0); + if (acl_set_fd(dest_fd, acl) < 0) { + warn("failed to set acl entries for %s", to.p_path); + return (1); + } + return (0); +} + +int +preserve_dir_acls(struct stat *fs, char *source_dir, char *dest_dir) +{ + acl_t (*aclgetf)(const char *, acl_type_t); + int (*aclsetf)(const char *, acl_type_t, acl_t); + struct acl *aclp; + acl_t acl; + + if (pathconf(source_dir, _PC_ACL_EXTENDED) != 1 || + pathconf(dest_dir, _PC_ACL_EXTENDED) != 1) + return (0); + /* + * If the file is a link we will not follow it + */ + if (S_ISLNK(fs->st_mode)) { + aclgetf = acl_get_link_np; + aclsetf = acl_set_link_np; + } else { + aclgetf = acl_get_file; + aclsetf = acl_set_file; + } + /* + * Even if there is no ACL_TYPE_DEFAULT entry here, a zero + * size ACL will be returned. So it is not safe to simply + * check the pointer to see if the default ACL is present. + */ + acl = aclgetf(source_dir, ACL_TYPE_DEFAULT); + if (acl == NULL) { + warn("failed to get default acl entries on %s", + source_dir); + return (1); + } + aclp = &acl->ats_acl; + if (aclp->acl_cnt != 0 && aclsetf(dest_dir, + ACL_TYPE_DEFAULT, acl) < 0) { + warn("failed to set default acl entries on %s", + dest_dir); + return (1); + } + acl = aclgetf(source_dir, ACL_TYPE_ACCESS); + if (acl == NULL) { + warn("failed to get acl entries on %s", source_dir); + return (1); + } + aclp = &acl->ats_acl; + if (aclsetf(dest_dir, ACL_TYPE_ACCESS, acl) < 0) { + warn("failed to set acl entries on %s", dest_dir); + return (1); + } + return (0); +} +#endif /* !__APPLE__ */ + void usage(void) { + if (COMPAT_MODE("bin/cp", "unix2003")) { + (void)fprintf(stderr, "%s\n%s\n", +"usage: cp [-R [-H | -L | -P]] [-fi | -n] [-pvX] source_file target_file", +" cp [-R [-H | -L | -P]] [-fi | -n] [-pvX] source_file ... " +"target_directory"); + } else { (void)fprintf(stderr, "%s\n%s\n", -"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-pv] src target", -" cp [-R [-H | -L | -P]] [-f | -i | -n] [-pv] src1 ... srcN directory"); +"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-pvX] source_file target_file", +" cp [-R [-H | -L | -P]] [-f | -i | -n] [-pvX] source_file ... " +"target_directory"); + } exit(EX_USAGE); } diff --git a/dd/conv.c b/dd/conv.c index 855a794..cb80edc 100644 --- a/dd/conv.c +++ b/dd/conv.c @@ -223,8 +223,10 @@ unblock(void) /* Translation and case conversion. */ if ((t = ctab) != NULL) - for (cnt = in.dbrcnt, inp = in.dbp; cnt--;) - *--inp = t[*inp]; + for (cnt = in.dbrcnt, inp = in.dbp; cnt--;) { + *inp = t[*inp]; + --inp; + } /* * Copy records (max cbsz size chunks) into the output buffer. The * translation has to already be done or we might not recognize the diff --git a/df/Makefile b/df/Makefile index 101cda1..5156e6f 100644 --- a/df/Makefile +++ b/df/Makefile @@ -21,7 +21,7 @@ MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC MAKEFILE = tool.make NEXTSTEP_INSTALLDIR = /bin -LIBS = +LIBS = -lutil DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) @@ -47,4 +47,4 @@ include $(MAKEFILEDIR)/$(MAKEFILE) -include Makefile.dependencies -ALL_CFLAGS += -I/System/Library/Frameworks/System.framework/PrivateHeaders +ALL_CFLAGS += -I/System/Library/Frameworks/System.framework/PrivateHeaders -D_DARWIN_USE_64_BIT_INODE diff --git a/df/Makefile.postamble b/df/Makefile.postamble index 234330d..a480e49 100644 --- a/df/Makefile.postamble +++ b/df/Makefile.postamble @@ -1,4 +1,2 @@ include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common -INSTALL_AS_GROUP = operator -INSTALL_PERMISSIONS = 2555 diff --git a/df/df.1 b/df/df.1 index 93a445d..7dd8624 100644 --- a/df/df.1 +++ b/df/df.1 @@ -39,7 +39,7 @@ .Nm df .Nd display free disk space .Sh SYNOPSIS -.Nm +.Nm df .Oo .Fl b | h | H | k | .Fl m | P @@ -49,7 +49,7 @@ .Op Fl T Ar type .Op Ar file | filesystem ... .Sh LEGACY SYNOPSIS -.Nm +.Nm df .Oo .Fl b | h | H | k | .Fl m | P @@ -60,7 +60,7 @@ .Op Ar file | filesystem ... .Sh DESCRIPTION The -.Nm +.Nm df utility displays statistics about the amount of free disk space on the specified .Ar filesystem @@ -80,13 +80,13 @@ The following options are available: Show all mount points, including those that were mounted with the MNT_IGNORE flag. .It Fl b -Use 512-byte blocks rather than the default. Note that -this overrides the +Use (the default) 512-byte blocks. +This is only useful as a way to override an .Ev BLOCKSIZE specification from the environment. .It Fl g -Use 1073741824-byte (1-Gbyte) blocks rather than the default. Note that -this overrides the +Use 1073741824-byte (1-Gbyte) blocks rather than the default. +Note that this overrides the .Ev BLOCKSIZE specification from the environment. .It Fl H @@ -100,8 +100,8 @@ digits to three or less using base 2 for sizes. .It Fl i Include statistics on the number of free inodes. .It Fl k -Use 1024-byte (1-Kbyte) blocks rather than the default. Note that -this overrides the +Use 1024-byte (1-Kbyte) blocks, rather than the default. +Note that this overrides the .Ev BLOCKSIZE specification from the environment. .It Fl l @@ -117,20 +117,14 @@ This option should be used if it is possible that one or more filesystems are in a state such that they will not be able to provide statistics without a long delay. When this option is specified, -.Nm +.Nm df will not request new statistics from the filesystems, but will respond with the possibly stale statistics that were previously obtained. .It Fl P -Use POSIX compliant output of 512-byte blocks rather than the default. -Note that this overrides the +Use (the default) 512-byte blocks. +This is only useful as a way to override an .Ev BLOCKSIZE specification from the environment. -.It Fl t -In legacy mode (see -.Xr compat 5 -for details) acts like -.Fl T -otherwise it is a no-op. .It Fl T Only print out statistics for filesystems of the specified types. More than one type may be specified in a comma separated list. @@ -140,10 +134,10 @@ to specify the filesystem types for which action should .Em not be taken. For example, the -.Nm +.Nm df command: .Bd -literal -offset indent -df -t nonfs,mfs +df -T nonfs,mfs .Ed .Pp lists all filesystems except those of type @@ -154,6 +148,13 @@ The .Xr lsvfs 1 command can be used to find out the types of filesystems that are available on the system. +.It Fl t +If used with no arguments, +this option is a no-op +(Mac OS X already prints the total allocated-space figures). +If used with an argument, it acts like +.Fl T , +but this usage is deprecated and should not be relied upon. .El .Sh ENVIRONMENT .Bl -tag -width BLOCKSIZE @@ -168,6 +169,29 @@ The and .Fl t flags are ignored if a file or filesystem is specified. +.Sh LEGACY DESCRIPTION +The "capacity" percentage is normally rounded up to the next higher integer. +In legacy mode, it is rounded down to the next lower integer. +.Pp +When the +.Fl P +option and the +.Fl k +option are used together, +sizes are reported in 1024-blocks. +In legacy mode, when the +.Fl P +option and +.Fl k +option are used together, +the last option specified dictates the reported block size. +.Pp +The +.Fl t +option is normally a no-op +(Mac OS X already prints the total allocated-space figures). +In legacy mode, it is equivalent to +.Fl T . .Sh SEE ALSO .Xr lsvfs 1 , .Xr quota 1 , @@ -175,12 +199,12 @@ flags are ignored if a file or filesystem is specified. .Xr getfsstat 2 , .Xr statfs 2 , .Xr getmntinfo 3 , -.Xr compat 5 +.Xr compat 5 , .Xr fstab 5 , .Xr mount 8 , .Xr quot 8 .Sh HISTORY A -.Nm +.Nm df command appeared in .At v1 . diff --git a/df/df.c b/df/df.c index dda262c..3438bca 100644 --- a/df/df.c +++ b/df/df.c @@ -53,8 +53,6 @@ static const char rcsid[] = #ifdef __APPLE__ #define MNT_IGNORE 0 -#include -typedef int32_t ufs_daddr_t; #endif #include @@ -62,8 +60,6 @@ typedef int32_t ufs_daddr_t; #include #include #include -#include -#include #include #include #include @@ -74,6 +70,7 @@ typedef int32_t ufs_daddr_t; #include #include #include +#include #ifdef __APPLE__ #include "get_compat.h" @@ -125,18 +122,16 @@ int checkvfsname(const char *, char **); char *getmntpt(char *); int longwidth(long long); char *makenetvfslist(void); -char **makevfslist(char *); -void prthuman(struct statfs *, long); -void prthumanval(double); +char **makevfslist(const char *); +void prthuman(struct statfs *, uint64_t); +void prthumanval(int64_t); void prtstat(struct statfs *, struct maxwidths *); long regetmntinfo(struct statfs **, long, char **); -int ufs_df(char *, struct maxwidths *); unit_t unit_adjust(double *); void update_maxwidths(struct maxwidths *, struct statfs *); void usage(void); int aflag = 0, hflag, iflag, nflag; -struct ufs_args mdev; static __inline int imax(int a, int b) { @@ -150,19 +145,20 @@ main(int argc, char *argv[]) struct statfs statfsbuf, *mntbuf; struct maxwidths maxwidths; const char *fstype; - char *mntpath, *mntpt, **vfslist; + char *mntpt, **vfslist; long mntsize; int ch, i, rv, tflag = 0, kludge_tflag = 0; + int kflag = 0; const char *options = "abgHhiklmnPt:T:"; if (COMPAT_MODE("bin/df", "unix2003")) { - /* Unix2003 requires -t be "include total capicity". which df - already does, but it conflits with the old -t so we need to + /* Unix2003 requires -t be "include total capacity". which df + already does, but it conflicts with the old -t so we need to *not* expect a string after -t (we provide -T in both cases to cover the old use of -t) */ options = "abgHhiklmnPtT:"; } - fstype = "ufs"; + fstype = "hfs"; vfslist = NULL; while ((ch = getopt(argc, argv, options)) != -1) @@ -173,7 +169,14 @@ main(int argc, char *argv[]) case 'b': /* FALLTHROUGH */ case 'P': - putenv("BLOCKSIZE=512"); + if (COMPAT_MODE("bin/df", "unix2003")) { + if (!kflag) { + /* -k overrides -P */ + putenv("BLOCKSIZE=512"); + } + } else { + putenv("BLOCKSIZE=512"); + } hflag = 0; break; case 'g': @@ -192,7 +195,12 @@ main(int argc, char *argv[]) iflag = 1; break; case 'k': - putenv("BLOCKSIZE=1k"); + if (COMPAT_MODE("bin/df", "unix2003")) { + putenv("BLOCKSIZE=1024"); + } else { + putenv("BLOCKSIZE=1k"); + } + kflag = 1; hflag = 0; break; case 'l': @@ -269,39 +277,9 @@ main(int argc, char *argv[]) continue; } } else if (S_ISCHR(stbuf.st_mode) || S_ISBLK(stbuf.st_mode)) { - if ((mntpt = getmntpt(*argv)) == 0) { - mdev.fspec = *argv; - mntpath = strdup("/tmp/df.XXXXXX"); - if (mntpath == NULL) { - warn("strdup failed"); - rv = 1; - continue; - } - mntpt = mkdtemp(mntpath); - if (mntpt == NULL) { - warn("mkdtemp(\"%s\") failed", mntpath); - rv = 1; - free(mntpath); - continue; - } - if (mount(fstype, mntpt, MNT_RDONLY, - &mdev) != 0) { - rv = ufs_df(*argv, &maxwidths) || rv; - (void)rmdir(mntpt); - free(mntpath); - continue; - } else if (statfs(mntpt, &statfsbuf) == 0) { - statfsbuf.f_mntonname[0] = '\0'; - prtstat(&statfsbuf, &maxwidths); - } else { - warn("%s", *argv); - rv = 1; - } - (void)unmount(mntpt, 0); - (void)rmdir(mntpt); - free(mntpath); - continue; - } + warnx("%s: Raw devices not supported", *argv); + rv = 1; + continue; } else mntpt = *argv; /* @@ -322,8 +300,9 @@ main(int argc, char *argv[]) rv++; continue; } + if (argc == 1) { - bzero(&maxwidths, sizeof(maxwidths)); + bzero(&maxwidths, sizeof(maxwidths)); update_maxwidths(&maxwidths, &statfsbuf); } prtstat(&statfsbuf, &maxwidths); @@ -400,36 +379,56 @@ unit_adjust(double *val) } void -prthuman(struct statfs *sfsp, long used) +prthuman(struct statfs *sfsp, uint64_t used) { - - prthumanval((double)sfsp->f_blocks * (double)sfsp->f_bsize); - prthumanval((double)used * (double)sfsp->f_bsize); - prthumanval((double)sfsp->f_bavail * (double)sfsp->f_bsize); + int64_t value; + + value = sfsp->f_blocks; + value *= sfsp->f_bsize; + prthumanval(value); + value = used; + value *= sfsp->f_bsize; + prthumanval(value); + value = sfsp->f_bavail; + value *= sfsp->f_bsize; + prthumanval(value); } void -prthumanval(double bytes) +prthumanval(int64_t bytes) { + char buf[6]; + int flags; - unit_t unit; - unit = unit_adjust(&bytes); + flags = HN_B | HN_NOSPACE | HN_DECIMAL; + if (hflag == UNITS_SI) + flags |= HN_DIVISOR_1000; + + humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1), + bytes, "", HN_AUTOSCALE, flags); - if (bytes == 0) - (void)printf(" 0B"); - else if (bytes > 10) - (void)printf(" %5.0f%c", bytes, "BKMGTPE"[unit]); + if (hflag == UNITS_SI) + (void)printf(" %6s", buf); else - (void)printf(" %5.1f%c", bytes, "BKMGTPE"[unit]); + (void)printf("%6si", buf); + } /* * Convert statfs returned filesystem size into BLOCKSIZE units. * Attempts to avoid overflow for large filesystems. */ -#define fsbtoblk(num, fsbs, bs) \ - (((fsbs) != 0 && (fsbs) < (bs)) ? \ - ((off_t)((unsigned)num)) / ((unsigned)(bs) / ((off_t)((unsigned)fsbs))) : ((off_t)((unsigned)num)) * ((off_t)((unsigned)fsbs)) / (bs)) +static intmax_t fsbtoblk(int64_t num, uint64_t fsbs, u_long bs, char *fs) +{ + if (num < 0) { + warnx("negative filesystem block count/size from fs %s", fs); + return 0; + } else if ((fsbs != 0) && (fsbs < bs)) { + return (num / (intmax_t) (bs / fsbs)); + } else { + return (num * (intmax_t) (fsbs / bs)); + } +} /* * Print out status about a filesystem. @@ -440,7 +439,8 @@ prtstat(struct statfs *sfsp, struct maxwidths *mwp) static long blocksize; static int headerlen, timesthrough; static const char *header; - unsigned long used, availblks, inodes; + uint64_t used, availblks, inodes; + char * avail_str; if (++timesthrough == 1) { mwp->mntfrom = imax(mwp->mntfrom, strlen("Filesystem")); @@ -452,11 +452,16 @@ prtstat(struct statfs *sfsp, struct maxwidths *mwp) mwp->total = imax(mwp->total, headerlen); } mwp->used = imax(mwp->used, strlen("Used")); - mwp->avail = imax(mwp->avail, strlen("Avail")); + if (COMPAT_MODE("bin/df", "unix2003") && !hflag) { + avail_str = "Available"; + } else { + avail_str = "Avail"; + } + mwp->avail = imax(mwp->avail, strlen(avail_str)); - (void)printf("%-*s %-*s %*s %*s Capacity", mwp->mntfrom, + (void)printf("%-*s %*s %*s %*s Capacity", mwp->mntfrom, "Filesystem", mwp->total, header, mwp->used, "Used", - mwp->avail, "Avail"); + mwp->avail, avail_str); if (iflag) { mwp->iused = imax(mwp->iused, strlen(" iused")); mwp->ifree = imax(mwp->ifree, strlen("ifree")); @@ -467,23 +472,38 @@ prtstat(struct statfs *sfsp, struct maxwidths *mwp) } (void)printf("%-*s", mwp->mntfrom, sfsp->f_mntfromname); - used = (off_t)((unsigned)sfsp->f_blocks) - (off_t)((unsigned)sfsp->f_bfree); + if (sfsp->f_blocks > sfsp->f_bfree) + used = sfsp->f_blocks - sfsp->f_bfree; + else + used = 0; availblks = sfsp->f_bavail + used; if (hflag) { prthuman(sfsp, used); } else { (void)printf(" %*lld %*lld %*lld", mwp->total, - fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize), - mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize), - mwp->avail, fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, - blocksize)); + fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize, sfsp->f_mntonname), + mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize, sfsp->f_mntonname), + mwp->avail, fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize, sfsp->f_mntonname)); + } + if (COMPAT_MODE("bin/df", "unix2003")) { + /* Standard says percentage must be rounded UP to next + integer value, not truncated */ + double value; + if (availblks == 0) + value = 100.0; + else { + value = (double)used / (double)availblks * 100.0; + if ((value-(int)value) > 0.0) value = value + 1.0; + } + (void)printf(" %5.0f%%", trunc(value)); + } else { + (void)printf(" %5.0f%%", + availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0); } - (void)printf(" %5.0f%%", - availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0); if (iflag) { - inodes = (unsigned)sfsp->f_files; + inodes = sfsp->f_files; used = inodes - sfsp->f_ffree; - (void)printf(" %*lu %*lu %4.0f%% ", mwp->iused, used, + (void)printf(" %*llu %*lu %4.0f%% ", mwp->iused, used, mwp->ifree, (unsigned long)sfsp->f_ffree, inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0); } else @@ -506,13 +526,13 @@ update_maxwidths(struct maxwidths *mwp, struct statfs *sfsp) mwp->mntfrom = imax(mwp->mntfrom, strlen(sfsp->f_mntfromname)); mwp->total = imax(mwp->total, longwidth(fsbtoblk(sfsp->f_blocks, - sfsp->f_bsize, blocksize))); - mwp->used = imax(mwp->used, longwidth(fsbtoblk(sfsp->f_blocks - - sfsp->f_bfree, sfsp->f_bsize, blocksize))); + sfsp->f_bsize, blocksize, sfsp->f_mntonname))); + if (sfsp->f_blocks >= sfsp->f_bfree) + mwp->used = imax(mwp->used, longwidth(fsbtoblk(sfsp->f_blocks - + sfsp->f_bfree, sfsp->f_bsize, blocksize, sfsp->f_mntonname))); mwp->avail = imax(mwp->avail, longwidth(fsbtoblk(sfsp->f_bavail, - sfsp->f_bsize, blocksize))); - mwp->iused = imax(mwp->iused, longwidth((unsigned)(sfsp->f_files - - sfsp->f_ffree))); + sfsp->f_bsize, blocksize, sfsp->f_mntonname))); + mwp->iused = imax(mwp->iused, longwidth((unsigned)(sfsp->f_files - sfsp->f_ffree))); mwp->ifree = imax(mwp->ifree, longwidth((unsigned)(sfsp->f_ffree))); } @@ -536,84 +556,13 @@ longwidth(long long val) return (len); } -/* - * This code constitutes the pre-system call Berkeley df code for extracting - * information from filesystem superblocks. - */ - -union { - struct fs iu_fs; - char dummy[SBSIZE]; -} sb; -#define sblock sb.iu_fs - -int rfd; - -int -ufs_df(char *file, struct maxwidths *mwp) -{ - struct statfs statfsbuf; - struct statfs *sfsp; - const char *mntpt; - static int synced; - - if (synced++ == 0) - sync(); - - if ((rfd = open(file, O_RDONLY)) < 0) { - warn("%s", file); - return (1); - } - if (bread((off_t)SBOFF, &sblock, SBSIZE) == 0) { - (void)close(rfd); - return (1); - } - sfsp = &statfsbuf; - sfsp->f_type = 1; - strcpy(sfsp->f_fstypename, "ufs"); - sfsp->f_flags = 0; - sfsp->f_bsize = sblock.fs_fsize; - sfsp->f_iosize = sblock.fs_bsize; - sfsp->f_blocks = sblock.fs_dsize; - sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag + - sblock.fs_cstotal.cs_nffree; - sfsp->f_bavail = freespace(&sblock, sblock.fs_minfree); - sfsp->f_files = sblock.fs_ncg * sblock.fs_ipg; - sfsp->f_ffree = sblock.fs_cstotal.cs_nifree; - sfsp->f_fsid.val[0] = 0; - sfsp->f_fsid.val[1] = 0; - if ((mntpt = getmntpt(file)) == 0) - mntpt = ""; - memmove(&sfsp->f_mntonname[0], mntpt, (size_t)MNAMELEN); - memmove(&sfsp->f_mntfromname[0], file, (size_t)MNAMELEN); - prtstat(sfsp, mwp); - (void)close(rfd); - return (0); -} - -int -bread(off_t off, void *buf, int cnt) -{ - ssize_t nr; - - (void)lseek(rfd, off, SEEK_SET); - if ((nr = read(rfd, buf, (size_t)cnt)) != (ssize_t)cnt) { - /* Probably a dismounted disk if errno == EIO. */ - if (errno != EIO) - (void)fprintf(stderr, "\ndf: %lld: %s\n", - (long long)off, strerror(nr > 0 ? EIO : errno)); - return (0); - } - return (1); -} - void usage(void) { char *t_flag = COMPAT_MODE("bin/df", "unix2003") ? "[-t]" : "[-t type]"; (void)fprintf(stderr, - "usage: df [-b | -H | -h | -k | -m | -P] [-ailn] [-T type] %s [file | filesystem ...]\n", t_flag); + "usage: df [-b | -H | -h | -k | -m | -P] [-ailn] [-T type] %s [filesystem ...]\n", t_flag); exit(EX_USAGE); } diff --git a/df/vfslist.c b/df/vfslist.c index c53ffe7..91e8577 100644 --- a/df/vfslist.c +++ b/df/vfslist.c @@ -67,10 +67,11 @@ checkvfsname(vfsname, vfslist) const char ** makevfslist(fslist) - char *fslist; + const char *fslist; { const char **av; int i; + const char *cnextcp; char *nextcp; if (fslist == NULL) @@ -79,14 +80,14 @@ makevfslist(fslist) fslist += 2; skipvfs = 1; } - for (i = 0, nextcp = fslist; *nextcp; nextcp++) - if (*nextcp == ',') + for (i = 0, cnextcp = fslist; *cnextcp; cnextcp++) + if (*cnextcp == ',') i++; if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) { warnx("malloc failed"); return (NULL); } - nextcp = fslist; + nextcp = strdup(fslist); i = 0; av[i++] = nextcp; while ((nextcp = strchr(nextcp, ',')) != NULL) { diff --git a/du/Makefile b/du/Makefile index d4a2b75..c6c7ead 100644 --- a/du/Makefile +++ b/du/Makefile @@ -16,6 +16,7 @@ CFILES = du.c OTHERSRCS = Makefile Makefile.preamble Makefile.postamble du.1 +OTHER_CFLAGS = -D__FBSDID=__RCSID MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC @@ -28,7 +29,7 @@ PROF_LIBS = $(LIBS) -NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/developer_cmds/Build +NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/file_cmds/Build NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc diff --git a/du/du.1 b/du/du.1 index 39fe7bd..51427a8 100644 --- a/du/du.1 +++ b/du/du.1 @@ -30,80 +30,77 @@ .\" SUCH DAMAGE. .\" .\" @(#)du.1 8.2 (Berkeley) 4/1/94 -.\" $FreeBSD: src/usr.bin/du/du.1,v 1.25 2002/12/12 17:26:00 ru Exp $ +.\" $FreeBSD: src/usr.bin/du/du.1,v 1.30 2005/05/21 09:55:05 ru Exp $ .\" -.Dd April 1, 1994 +.Dd June 2, 2004 .Dt DU 1 .Os .Sh NAME .Nm du .Nd display disk usage statistics .Sh SYNOPSIS -.Nm +.Nm du .Op Fl H | L | P -.Op Fl I Ar mask .Op Fl a | s | d Ar depth .Op Fl c -.Op Fl h | k +.Op Fl h | k | m .Op Fl x +.Op Fl I Ar mask .Op Ar .Sh DESCRIPTION The -.Nm +.Nm du utility displays the file system block usage for each file argument and for each directory in the file hierarchy rooted in each directory argument. If no file is specified, the block usage of the hierarchy rooted in the current directory is displayed. -If the -.Fl k -flag is specified, the number of 1024-byte -blocks used by the file is displayed, otherwise -.Xr getbsize 3 -is used to determine the preferred block size. -Partial numbers of blocks are rounded up. .Pp The options are as follows: .Bl -tag -width indent +.It Fl a +Display an entry for each file in a file hierarchy. +.It Fl c +Display a grand total. +.It Fl d Ar depth +Display an entry for all files and directories +.Ar depth +directories deep. .It Fl H Symbolic links on the command line are followed, symbolic links in file hierarchies are not followed. -.It Fl L -Symbolic links on the command line and in file hierarchies are followed. +.It Fl h +"Human-readable" output. +Use unit suffixes: Byte, Kilobyte, Megabyte, +Gigabyte, Terabyte and Petabyte. .It Fl I Ar mask Ignore files and directories matching the specified .Ar mask . +.It Fl k +Display block counts in 1024-byte (1-Kbyte) blocks. +.It Fl L +Symbolic links on the command line and in file hierarchies are followed. +.It Fl m +Display block counts in 1048576-byte (1-Mbyte) blocks. .It Fl P No symbolic links are followed. This is the default. -.It Fl a -Display an entry for each file in a file hierarchy. -.It Fl h -"Human-readable" output. Use unit suffixes: Byte, Kilobyte, Megabyte, -Gigabyte, Terabyte and Petabyte .It Fl r Generate messages about directories that cannot be read, files -that cannot be opened, and so on. This is the default case. +that cannot be opened, and so on. +This is the default case. This option exists solely for conformance with .St -xpg4 . .It Fl s Display an entry for each specified file. (Equivalent to .Fl d Li 0 ) -.It Fl d Ar depth -Display an entry for all files and directories -.Ar depth -directories deep. -.It Fl c -Display a grand total. -.It Fl k -Display block counts in 1024-byte (1-Kbyte) blocks. .It Fl x File system mount points are not traversed. .El .Pp The -.Nm +.Nm du utility counts the storage used by symbolic links and not the files they reference unless the .Fl H @@ -116,10 +113,16 @@ or .Fl L options are specified, storage used by any symbolic links which are followed is not counted or displayed. +If more than one of the +.Fl H , +.Fl L , +and +.Fl P +options is specified, the last one given is used. .Pp Files having multiple hard links are counted (and displayed) a single time per -.Nm +.Nm du execution. .Sh ENVIRONMENT .Bl -tag -width BLOCKSIZE @@ -136,13 +139,25 @@ is not set, and the .Fl k option is not specified, the block counts will be displayed in 512-byte blocks. .El +.Sh LEGACY DESCRIPTION +In legacy mode, only one of the +.Fl H , +.Fl L , +or +.Fl P +options may be specified. +.Pp +The command will detect and report a SYMLOOP error +(loop involving symbolic links). +In legacy mode, this is not the case. .Sh SEE ALSO .Xr df 1 , .Xr fts 3 , +.Xr compat 5 , .Xr symlink 7 , .Xr quot 8 .Sh HISTORY A -.Nm +.Nm du command appeared in .At v1 . diff --git a/du/du.c b/du/du.c index 8b1c46b..4a426ee 100644 --- a/du/du.c +++ b/du/du.c @@ -46,8 +46,9 @@ static const char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95"; #endif #endif /* not lint */ #include -__RCSID("$FreeBSD: src/usr.bin/du/du.c,v 1.28 2002/12/30 18:13:07 mike Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/du/du.c,v 1.38 2005/04/09 14:31:40 stefanf Exp $"); +#include #include #include #include @@ -56,19 +57,19 @@ __RCSID("$FreeBSD: src/usr.bin/du/du.c,v 1.28 2002/12/30 18:13:07 mike Exp $"); #include #include #include +#include #include +#include #include #include #include #include #include -#include -#include #ifdef __APPLE__ -#include "get_compat.h" +#include #else -#define COMPAT_MODE(func, mode) 1 +#define COMPAT_MODE(func, mode) (1) #endif #define KILO_SZ(n) (n) @@ -105,7 +106,7 @@ struct ignentry { SLIST_ENTRY(ignentry) next; }; -int linkchk(FTSENT *); +static int linkchk(FTSENT *); static void usage(void); void prthumanval(double); unit_t unit_adjust(double *); @@ -118,6 +119,7 @@ main(int argc, char *argv[]) { FTS *fts; FTSENT *p; + off_t savednumber = 0; long blocksize; int ftsoptions; int listall; @@ -125,38 +127,32 @@ main(int argc, char *argv[]) int Hflag, Lflag, Pflag, aflag, sflag, dflag, cflag, hflag, ch, notused, rval; char **save; static char dot[] = "."; - off_t *ftsnum, *ftsparnum, savednumber = 0; + off_t *ftsnum, *ftsparnum; + + setlocale(LC_ALL, ""); Hflag = Lflag = Pflag = aflag = sflag = dflag = cflag = hflag = 0; - + save = argv; ftsoptions = 0; depth = INT_MAX; SLIST_INIT(&ignores); - - while ((ch = getopt(argc, argv, "HI:LPasd:chkrx")) != -1) + + while ((ch = getopt(argc, argv, "HI:LPasd:chkmrx")) != -1) switch (ch) { case 'H': + Lflag = Pflag = 0; Hflag = 1; - Pflag = Lflag = 0; break; case 'I': ignoreadd(optarg); break; case 'L': - if (Pflag && COMPAT_MODE("bin/du", "legacy")) { - usage(); - } else { - Hflag = Pflag = 0; - } + Hflag = Pflag = 0; Lflag = 1; break; case 'P': - if (Lflag && COMPAT_MODE("bin/du", "legacy")) { - usage(); - } else { - Hflag = Lflag = 0; - } + Hflag = Lflag = 0; Pflag = 1; break; case 'a': @@ -183,8 +179,12 @@ main(int argc, char *argv[]) valp = vals_base2; break; case 'k': - if (!hflag) - putenv("BLOCKSIZE=1024"); + hflag = 0; + putenv("BLOCKSIZE=1024"); + break; + case 'm': + hflag = 0; + putenv("BLOCKSIZE=1048576"); break; case 'r': /* Compatibility. */ break; @@ -249,7 +249,7 @@ main(int argc, char *argv[]) blocksize /= 512; rval = 0; - + if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL) err(1, "fts_open"); @@ -270,14 +270,14 @@ main(int argc, char *argv[]) } else { ftsparnum[0] += ftsnum[0] += howmany(p->fts_statp->st_size, 512LL); } - + if (p->fts_level <= depth) { if (hflag) { (void) prthumanval(howmany(*ftsnum, blocksize)); (void) printf("\t%s\n", p->fts_path); } else { - (void) printf("%lld\t%s\n", - howmany(*ftsnum, blocksize), + (void) printf("%jd\t%s\n", + (intmax_t)howmany(*ftsnum, blocksize), p->fts_path); } } @@ -307,7 +307,7 @@ main(int argc, char *argv[]) if (p->fts_statp->st_nlink > 1 && linkchk(p)) break; - + if (listall || p->fts_level == 0) { if (hflag) { if (p->fts_statp->st_size < TWO_TB) { @@ -320,12 +320,12 @@ main(int argc, char *argv[]) (void) printf("\t%s\n", p->fts_path); } else { if (p->fts_statp->st_size < TWO_TB) { - (void) printf("%qd\t%s\n", - (long long)howmany(p->fts_statp->st_blocks, blocksize), + (void) printf("%jd\t%s\n", + (intmax_t)howmany(p->fts_statp->st_blocks, blocksize), p->fts_path); } else { - (void) printf("%qd\t%s\n", - (long long)howmany(howmany(p->fts_statp->st_size, 512LL), blocksize), + (void) printf("%jd\t%s\n", + (intmax_t)howmany(howmany(p->fts_statp->st_size, 512LL), blocksize), p->fts_path); } } @@ -349,7 +349,7 @@ main(int argc, char *argv[]) (void) prthumanval(howmany(savednumber, blocksize)); (void) printf("\ttotal\n"); } else { - (void) printf("%lld\ttotal\n", howmany(savednumber, blocksize)); + (void) printf("%jd\ttotal\n", (intmax_t)howmany(savednumber, blocksize)); } } @@ -357,36 +357,136 @@ main(int argc, char *argv[]) exit(rval); } +static int +linkchk(FTSENT *p) +{ + struct links_entry { + struct links_entry *next; + struct links_entry *previous; + int links; + dev_t dev; + ino_t ino; + }; + static const size_t links_hash_initial_size = 8192; + static struct links_entry **buckets; + static struct links_entry *free_list; + static size_t number_buckets; + static unsigned long number_entries; + static char stop_allocating; + struct links_entry *le, **new_buckets; + struct stat *st; + size_t i, new_size; + int hash; + + st = p->fts_statp; + + /* If necessary, initialize the hash table. */ + if (buckets == NULL) { + number_buckets = links_hash_initial_size; + buckets = malloc(number_buckets * sizeof(buckets[0])); + if (buckets == NULL) + errx(1, "No memory for hardlink detection"); + for (i = 0; i < number_buckets; i++) + buckets[i] = NULL; + } -typedef struct _ID { - dev_t dev; - ino_t inode; -} ID; + /* If the hash table is getting too full, enlarge it. */ + if (number_entries > number_buckets * 10 && !stop_allocating) { + new_size = number_buckets * 2; + new_buckets = malloc(new_size * sizeof(struct links_entry *)); + + /* Try releasing the free list to see if that helps. */ + if (new_buckets == NULL && free_list != NULL) { + while (free_list != NULL) { + le = free_list; + free_list = le->next; + free(le); + } + new_buckets = malloc(new_size * sizeof(new_buckets[0])); + } + if (new_buckets == NULL) { + stop_allocating = 1; + warnx("No more memory for tracking hard links"); + } else { + memset(new_buckets, 0, + new_size * sizeof(struct links_entry *)); + for (i = 0; i < number_buckets; i++) { + while (buckets[i] != NULL) { + /* Remove entry from old bucket. */ + le = buckets[i]; + buckets[i] = le->next; + + /* Add entry to new bucket. */ + hash = (le->dev ^ le->ino) % new_size; + + if (new_buckets[hash] != NULL) + new_buckets[hash]->previous = + le; + le->next = new_buckets[hash]; + le->previous = NULL; + new_buckets[hash] = le; + } + } + free(buckets); + buckets = new_buckets; + number_buckets = new_size; + } + } -int -linkchk(FTSENT *p) -{ - static ID *files; - static int maxfiles, nfiles; - ID *fp, *start; - ino_t ino; - dev_t dev; - - ino = p->fts_statp->st_ino; - dev = p->fts_statp->st_dev; - if ((start = files) != NULL) - for (fp = start + nfiles - 1; fp >= start; --fp) - if (ino == fp->inode && dev == fp->dev) { - return (1); + /* Try to locate this entry in the hash table. */ + hash = ( st->st_dev ^ st->st_ino ) % number_buckets; + for (le = buckets[hash]; le != NULL; le = le->next) { + if (le->dev == st->st_dev && le->ino == st->st_ino) { + /* + * Save memory by releasing an entry when we've seen + * all of it's links. + */ + if (--le->links <= 0) { + if (le->previous != NULL) + le->previous->next = le->next; + if (le->next != NULL) + le->next->previous = le->previous; + if (buckets[hash] == le) + buckets[hash] = le->next; + number_entries--; + /* Recycle this node through the free list */ + if (stop_allocating) { + free(le); + } else { + le->next = free_list; + free_list = le; + } } + return (1); + } + } - if (nfiles == maxfiles && (files = realloc((char *)files, - (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL) - errx(1, "can't allocate memory"); - files[nfiles].inode = ino; - files[nfiles].dev = dev; - ++nfiles; + if (stop_allocating) + return (0); + + /* Add this entry to the links cache. */ + if (free_list != NULL) { + /* Pull a node from the free list if we can. */ + le = free_list; + free_list = le->next; + } else + /* Malloc one if we have to. */ + le = malloc(sizeof(struct links_entry)); + if (le == NULL) { + stop_allocating = 1; + warnx("No more memory for tracking hard links"); + return (0); + } + le->dev = st->st_dev; + le->ino = st->st_ino; + le->links = st->st_nlink - 1; + number_entries++; + le->next = buckets[hash]; + le->previous = NULL; + if (buckets[hash] != NULL) + buckets[hash]->previous = le; + buckets[hash] = le; return (0); } @@ -437,7 +537,7 @@ static void usage(void) { (void)fprintf(stderr, - "usage: du [-H | -L | -P] [-a | -s | -d depth] [-c] [-h | -k] [-x] [-I mask] [file ...]\n"); + "usage: du [-H | -L | -P] [-a | -s | -d depth] [-c] [-h | -k | -m] [-x] [-I mask] [file ...]\n"); exit(EX_USAGE); } @@ -473,6 +573,7 @@ ignorep(FTSENT *ent) { struct ignentry *ign; +#ifdef __APPLE__ if (S_ISDIR(ent->fts_statp->st_mode) && !strcmp("fd", ent->fts_name)) { struct statfs sfsb; int rc = statfs(ent->fts_accpath, &sfsb); @@ -483,6 +584,7 @@ ignorep(FTSENT *ent) return 1; } } +#endif /* __APPLE__ */ SLIST_FOREACH(ign, &ignores, next) if (fnmatch(ign->mask, ent->fts_name, 0) != FNM_NOMATCH) return 1; diff --git a/install/install.1 b/install/install.1 index b3e6241..76f3697 100644 --- a/install/install.1 +++ b/install/install.1 @@ -39,7 +39,7 @@ .Nm install .Nd install binaries .Sh SYNOPSIS -.Nm +.Nm install .Op Fl bCcMpSsv .Op Fl B Ar suffix .Op Fl f Ar flags @@ -47,7 +47,7 @@ .Op Fl m Ar mode .Op Fl o Ar owner .Ar file1 file2 -.Nm +.Nm install .Op Fl bCcMpSsv .Op Fl B Ar suffix .Op Fl f Ar flags @@ -55,7 +55,7 @@ .Op Fl m Ar mode .Op Fl o Ar owner .Ar file1 ... fileN directory -.Nm +.Nm install .Fl d .Op Fl v .Op Fl g Ar group @@ -84,6 +84,14 @@ option's argument. .Pp The options are as follows: .Bl -tag -width indent +.\" ========== +.It Fl B Ar suffix +Use +.Ar suffix +as the backup suffix if +.Fl b +is given. +.\" ========== .It Fl b Back up any existing files before overwriting them by renaming them to @@ -91,44 +99,47 @@ them to See .Fl B for specifying a different backup suffix. -.It Fl B Ar suffix -Use -.Ar suffix -as the backup suffix if -.Fl b -is given. +.\" ========== .It Fl C Copy the file. If the target file already exists and the files are the same, then don't change the modification time of the target. +.\" ========== .It Fl c Copy the file. This is actually the default. The .Fl c option is only included for backwards compatibility. +.\" ========== .It Fl d Create directories. Missing parent directories are created as required. +.\" ========== .It Fl f Specify the target's file flags; see .Xr chflags 1 for a list of possible flags and their meanings. +.\" ========== .It Fl g Specify a group. A numeric GID is allowed. +.\" ========== .It Fl M Disable all use of .Xr mmap 2 . +.\" ========== .It Fl m Specify an alternate mode. The default mode is set to rwxr-xr-x (0755). The specified mode may be either an octal or symbolic value; see .Xr chmod 1 for a description of possible mode values. +.\" ========== .It Fl o Specify an owner. A numeric UID is allowed. +.\" ========== .It Fl p Preserve the modification time. Copy the file, as if the @@ -136,10 +147,11 @@ Copy the file, as if the (compare and copy) option is specified, except if the target file doesn't already exist or is different, then preserve the modification time of the file. +.\" ========== .It Fl S Safe copy. Normally, -.Nm +.Nm install unlinks an existing target before installing the new file. With the .Fl S @@ -147,30 +159,32 @@ flag a temporary file is used and then renamed to be the target. The reason this is safer is that if the copy or rename fails, the existing target is left untouched. +.\" ========== .It Fl s -.Nm +.Nm install exec's the command .Xr strip 1 to strip binaries so that -.Nm +.Nm install can be portable over a large number of systems and binary types. +.\" ========== .It Fl v Causes -.Nm +.Nm install to show when .Fl C actually installs something. .El .Pp By default, -.Nm +.Nm install preserves all file flags, with the exception of the .Dq nodump flag. .Pp The -.Nm +.Nm install utility attempts to prevent moving a file onto itself. .Pp Installing @@ -178,7 +192,7 @@ Installing creates an empty file. .Sh DIAGNOSTICS The -.Nm +.Nm install utility exits 0 on success, and 1 otherwise. .Sh FILES .Bl -tag -width INS@XXXX -compact @@ -201,7 +215,7 @@ are created in the target directory. .El .Sh COMPATIBILITY Historically -.Nm +.Nm install moved files by default. The default was changed to copy in .Fx 4.4 . @@ -216,22 +230,22 @@ The default was changed to copy in .Xr chown 8 .Sh HISTORY The -.Nm +.Nm install utility appeared in .Bx 4.2 . .Sh BUGS Temporary files may be left in the target directory if -.Nm +.Nm install exits abnormally. .Pp File flags cannot be set by .Xr fchflags 2 over a NFS file system. Other file systems do not have a concept of flags. -.Nm +.Nm install will only warn when flags could not be set on a file system that does not support them. .Pp -.Nm +.Nm install with .Fl v falsely says a file is copied when diff --git a/install/xinstall.c b/install/xinstall.c index 31e542d..d5b41a1 100644 --- a/install/xinstall.c +++ b/install/xinstall.c @@ -67,7 +67,7 @@ static const char rcsid[] = #ifdef __APPLE__ #include -#endif +#endif /* __APPLE__ */ #include "pathnames.h" @@ -442,6 +442,13 @@ install(from_name, to_name, fset, flags) err(EX_OSERR, "%s", to_name); } +#ifdef __APPLE__ + /* in case mtime is modified */ + if (!devnull && (S_ISLNK(from_sb.st_mode) || S_ISREG(from_sb.st_mode)) && + fcopyfile(from_fd, to_fd, NULL, COPYFILE_XATTR) < 0) { + warn("%s: unable to copy extended attributes from %s", to_name, from_name); + } +#endif /* __APPLE__ */ /* * Preserve the timestamp of the source file if necessary. */ @@ -490,14 +497,14 @@ install(from_name, to_name, fset, flags) /* * If provided a set of flags, set them, otherwise, preserve the * flags, except for the dump flag. - * NFS does not support flags. Ignore EOPNOTSUPP flags if we're just + * NFS does not support flags. Ignore ENOTSUP flags if we're just * trying to turn off UF_NODUMP. If we're trying to set real flags, * then warn if the the fs doesn't support it, otherwise fail. */ if (!devnull && fchflags(to_fd, flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) { if (flags & SETFLAGS) { - if (errno == EOPNOTSUPP) + if (errno == ENOTSUP) warn("%s: chflags", to_name); else { serrno = errno; @@ -507,15 +514,13 @@ install(from_name, to_name, fset, flags) } } } - -#if __APPLE__ - { - if (copyfile(from_name, to_name, NULL, COPYFILE_ACL | COPYFILE_XATTR) < 0) - { - warn("%s: copyfile", to_name); - } +#ifdef __APPLE__ + /* the ACL could prevent credential/permission system calls later on... */ + if (!devnull && (S_ISLNK(from_sb.st_mode) || S_ISREG(from_sb.st_mode)) && + (fcopyfile(from_fd, to_fd, NULL, COPYFILE_ACL) < 0)) { + warn("%s: unable to copy ACL from %s", to_name, from_name); } -#endif +#endif /* __APPLE__ */ (void)close(to_fd); if (!devnull) diff --git a/ipcrm/ipcrm.1 b/ipcrm/ipcrm.1 index 4cf67c2..55ff23c 100644 --- a/ipcrm/ipcrm.1 +++ b/ipcrm/ipcrm.1 @@ -21,7 +21,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: ipcrm.1,v 1.2.32.1 2005/02/26 03:36:38 nicolai Exp $ +.\" $Id: ipcrm.1,v 1.3 2005/04/12 23:51:24 nicolai Exp $ .\"" .Dd August 8, 1994 .Dt ipcrm 1 @@ -31,13 +31,13 @@ .Nd remove the specified message queues, semaphore sets, and shared memory segments .Sh SYNOPSIS -.Nm -.Op Fl q Ar msqid +.Nm ipcrm +.Op Fl M Ar shmkey .Op Fl m Ar shmid -.Op Fl s Ar semid .Op Fl Q Ar msgkey -.Op Fl M Ar shmkey +.Op Fl q Ar msqid .Op Fl S Ar semkey +.Op Fl s Ar semid .Ar ... .Sh DESCRIPTION .Nm Ipcrm @@ -45,34 +45,35 @@ removes the specified message queues, semaphores and shared memory segments. These System V IPC objects can be specified by their creation id or any associated key. .Pp -The following options are used to specify which IPC objects will be removed. Any number and combination of these options can be used: +The following options are used to specify which IPC objects will be removed. +Any number and combination of these options can be used: .Bl -tag -width indent -.It Fl q Ar msqid -Remove the message queue associated with the id -.Nm msqid -from the system. +.It Fl M Ar shmkey +Mark the shared memory segment associated with key +.Nm shmkey +for removal. +This marked segment will be destroyed after the last detach. .It Fl m Ar shmid Mark the shared memory segment associated with id .Nm shmid for removal. This marked segment will be destroyed after the last detach. -.It Fl s Ar semid -Removes the semaphore set associated with id -.Nm semid -from the system. .It Fl Q Ar msgkey Remove the message queue associated with key .Nm msgkey from the system. -.It Fl M Ar shmkey -Mark the shared memory segment associated with key -.Nm shmkey -for removal. -This marked segment will be destroyed after the last detach. +.It Fl q Ar msqid +Remove the message queue associated with the id +.Nm msqid +from the system. .It Fl S Ar semkey Remove the semaphore set associated with key .Nm semkey from the system. +.It Fl s Ar semid +Removes the semaphore set associated with id +.Nm semid +from the system. .El .Pp The identifiers and keys associated with these System V IPC objects can be diff --git a/ipcrm/ipcrm.c b/ipcrm/ipcrm.c index 567cfcb..be2d3be 100644 --- a/ipcrm/ipcrm.c +++ b/ipcrm/ipcrm.c @@ -31,7 +31,7 @@ #ifndef lint static const char rcsid[] = - "$Id: ipcrm.c,v 1.2.30.1 2005/02/26 03:36:38 nicolai Exp $"; + "$Id: ipcrm.c,v 1.3 2005/02/03 07:31:33 josborne Exp $"; #endif /* not lint */ #include @@ -42,10 +42,8 @@ static const char rcsid[] = #include #include #include -#if 0 #include #include -#endif #include #define IPC_TO_STR(x) (x == 'Q' ? "msq" : (x == 'M' ? "shm" : "sem")) @@ -66,13 +64,11 @@ int msgrm(key, id) key_t key; int id; { -#if 0 if (key) { id = msgget(key, 0); if (id == -1) return -1; } -#endif return msgctl(id, IPC_RMID, NULL); } @@ -92,7 +88,6 @@ int semrm(key, id) key_t key; int id; { -#if 0 union semun arg; if (key) { @@ -101,7 +96,6 @@ int semrm(key, id) return -1; } return semctl(id, 0, IPC_RMID, arg); -#endif } void not_configured() @@ -116,6 +110,7 @@ int main(argc, argv) { int c, result, errflg, target_id; key_t target_key; + char *en; errflg = 0; signal(SIGSYS, not_configured); @@ -126,7 +121,12 @@ int main(argc, argv) case 'q': case 'm': case 's': - target_id = atoi(optarg); + target_id = strtol(optarg, &en, 0); + if (*en) { + warnx("%s: '%s' is not a number", + IPC_TO_STRING(toupper(c)), optarg); + continue; + } if (c == 'q') result = msgrm(0, target_id); else if (c == 'm') @@ -145,7 +145,11 @@ int main(argc, argv) case 'Q': case 'M': case 'S': - target_key = atol(optarg); + target_key = strtol(optarg, &en, 0); + if (*en) { + warnx("%s: '%s' is not a number", IPC_TO_STRING(c), optarg); + continue; + } if (target_key == IPC_PRIVATE) { warnx("can't remove private %ss", IPC_TO_STRING(c)); continue; @@ -159,7 +163,7 @@ int main(argc, argv) if (result < 0) { errflg++; if (!signaled) - warn("%key(%ld): ", IPC_TO_STR(c), target_key); + warn("%s key(%ld): ", IPC_TO_STRING(c), target_key); else warnx("%ss are not configured in the running kernel", IPC_TO_STRING(c)); @@ -180,4 +184,3 @@ int main(argc, argv) } exit(errflg); } - diff --git a/ipcs/Makefile b/ipcs/Makefile index 2dd4656..ea77822 100644 --- a/ipcs/Makefile +++ b/ipcs/Makefile @@ -24,8 +24,7 @@ LIBS = DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) -NEXTSTEP_PB_CFLAGS = - +NEXTSTEP_PB_CFLAGS = -iquote /System/Library/Frameworks/System.framework/PrivateHeaders -iquote /System/Library/Frameworks/Kernel.framework/PrivateHeaders NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc @@ -44,6 +43,3 @@ include $(MAKEFILEDIR)/$(MAKEFILE) -include Makefile.postamble -include Makefile.dependencies - -ALL_CFLAGS += -I/System/Library/Frameworks/System.framework/PrivateHeaders - diff --git a/ipcs/Makefile.postamble b/ipcs/Makefile.postamble index 013b558..54e0481 100644 --- a/ipcs/Makefile.postamble +++ b/ipcs/Makefile.postamble @@ -1 +1,4 @@ include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common + +INSTALL_AS_USER = root +INSTALL_PERMISSIONS = 4511 diff --git a/ipcs/ipcs.1 b/ipcs/ipcs.1 index 6b057e2..f0a6df4 100644 --- a/ipcs/ipcs.1 +++ b/ipcs/ipcs.1 @@ -36,11 +36,11 @@ .Nm ipcs .Nd report System V interprocess communication facilities status .Sh SYNOPSIS -.Nm -.Op Fl abcmopqstMQST +.Nm ipcs +.Op Fl abcMmopQqSsTt .Sh DESCRIPTION The -.Nm +.Nm ipcs utility provides information on System V interprocess communication (IPC) facilities on the system. .Pp @@ -68,6 +68,8 @@ or the number of semaphores in a set of semaphores. .It Fl c Show the creator's name and group for active semaphores, message queues, and shared memory segments. +.It Fl M +Display system information about shared memory. .It Fl m Display information about active shared memory segments. .It Fl o @@ -84,10 +86,17 @@ is the last process to send a message to or receive a message from a message queue, the process that created a semaphore, or the last process to attach or detach a shared memory segment. +.It Fl Q +Display system information about messages queues. .It Fl q Display information about active message queues. +.It Fl S +Display system information about semaphores. .It Fl s Display information about active semaphores. +.It Fl T +Display system information about shared memory, message queues +and semaphores. .It Fl t Show access times for active semaphores, message queues, and shared memory segments. The access times is the time @@ -95,15 +104,6 @@ of the last control operation on an IPC object, the last send or receive of a message, the last attach or detach of a shared memory segment, or the last operation on a semaphore. -.It Fl M -Display system information about shared memory. -.It Fl Q -Display system information about messages queues. -.It Fl S -Display system information about semaphores. -.It Fl T -Display system information about shared memory, message queues -and semaphores. .El .Pp If none of the @@ -118,14 +118,14 @@ options are specified, information about all active IPC facilities is listed. .Sh RESTRICTIONS System data structures may change while -.Nm +.Nm ipcs is running; the output of -.Nm +.Nm ipcs is not guaranteed to be consistent. .Sh BUGS This manual page is woefully incomplete, because it does not at all attempt to explain the information printed by -.Nm . +.Nm ipcs . .Sh SEE ALSO .Xr ipcrm 1 .Sh AUTHORS diff --git a/ipcs/ipcs.c b/ipcs/ipcs.c index 5094d69..480a3c6 100644 --- a/ipcs/ipcs.c +++ b/ipcs/ipcs.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -41,54 +40,51 @@ #include #include #include +#include #include #include +#include #include #include -#include #include - -#define KERNEL - -#include -#include -#include -#include - +#include #include "sys/ipcs.h" +#define KERNEL 1 /* To get new ipc_perm and __(sem|shm|msg)ds_new */ +#include "sys/ipc.h" +#include "sys/sem_internal.h" +#include "sys/shm_internal.h" +#include "sys/msg.h" + /* The following is a kludge, until the problem of multiple inclusions of ipc.h is taken care of. */ #ifndef IXSEQ_TO_IPCID -#define IXSEQ_TO_IPCID(ix,perm) (((perm.seq) << 16) | (ix & 0xffff)) +#define IXSEQ_TO_IPCID(ix,perm) (((perm._seq) << 16L) | (ix & 0xffff)) #endif char * -fmt_perm(mode) - u_short mode; +fmt_perm(u_short mode, char write_char) { static char buffer[100]; buffer[0] = '-'; buffer[1] = '-'; buffer[2] = ((mode & 0400) ? 'r' : '-'); - buffer[3] = ((mode & 0200) ? 'w' : '-'); - buffer[4] = ((mode & 0100) ? 'a' : '-'); + buffer[3] = ((mode & 0200) ? write_char : '-'); + buffer[4] = '-'; buffer[5] = ((mode & 0040) ? 'r' : '-'); - buffer[6] = ((mode & 0020) ? 'w' : '-'); - buffer[7] = ((mode & 0010) ? 'a' : '-'); + buffer[6] = ((mode & 0020) ? write_char : '-'); + buffer[7] = '-'; buffer[8] = ((mode & 0004) ? 'r' : '-'); - buffer[9] = ((mode & 0002) ? 'w' : '-'); - buffer[10] = ((mode & 0001) ? 'a' : '-'); + buffer[9] = ((mode & 0002) ? write_char : '-'); + buffer[10] = '-'; buffer[11] = '\0'; return (&buffer[0]); } void -cvt_time(t, buf) - time_t t; - char *buf; +cvt_time(time_t t, char *buf) { struct tm *tm; @@ -113,15 +109,46 @@ cvt_time(t, buf) #define PID 8 #define TIME 16 +void usage() +{ + errx(EX_USAGE, "%s","usage: ipcs [-abcmopqstMQST]\n"); +} + +int safe_sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, + size_t newlen) + +{ + int rv, sv_errno=0; + + if (seteuid(0)) /* iterator needs root write access to sysctl */ + err(1, "seteuid(0) failed"); + + rv = sysctlbyname(name, oldp, oldlenp, newp, newlen); + if (rv < 0) + sv_errno = errno; + + if (seteuid(getuid())) + err(1, "seteuid(%d) failed", getuid()); + + if (rv < 0) + errno = sv_errno; + return rv; +} + int main(argc, argv) int argc; char *argv[]; { - int display = SHMINFO | MSGINFO | SEMINFO; + int display = 0; int option = 0; - char kvmoferr[_POSIX2_LINE_MAX]; /* Error buf for kvm_openfiles. */ - int i; + int exit_val = 0; + time_t now; + char datestring[100]; + int i; + + if (seteuid(getuid())) /* run as user */ + err(1, "seteuid(%d) failed", getuid()); while ((i = getopt(argc, argv, "MmQqSsabcoptT")) != -1) switch (i) { @@ -129,19 +156,19 @@ main(argc, argv) display = SHMTOTAL; break; case 'm': - display = SHMINFO; + display |= SHMINFO; break; case 'Q': display = MSGTOTAL; break; case 'q': - display = MSGINFO; + display |= MSGINFO; break; case 'S': display = SEMTOTAL; break; case 's': - display = SEMINFO; + display |= SEMINFO; break; case 'T': display = SHMTOTAL | MSGTOTAL | SEMTOTAL; @@ -167,7 +194,12 @@ main(argc, argv) default: usage(); } - + if (display == 0) + display = SHMINFO | MSGINFO | SEMINFO; + now = time(0); + if (0 == strftime(datestring, sizeof(datestring), "%a %b %e %H:%M:%S %Z %Y", localtime(&now))) + errx(1, "strftime failed\n"); + printf("IPC status from as of %s\n", datestring); if ((display & (MSGINFO | MSGTOTAL))) { if (display & MSGTOTAL) { struct IPCS_command ic; @@ -180,7 +212,16 @@ main(argc, argv) ic.ipcs_data = &msginfo; ic.ipcs_datalen = sizeof(msginfo); - sysctlbyname(IPCS_MSG_SYSCTL, &ic, &ic_size, &ic, ic_size); + if (safe_sysctlbyname(IPCS_MSG_SYSCTL, &ic, &ic_size, &ic, ic_size)) { + if (errno != EPERM) { + char buffer[1024]; + snprintf(buffer, 1024, "sysctlbyname(IPCS_MSG_SYSCTL, op=CONF, &ic, &%ld) datalen=%d", + sizeof(ic), ic.ipcs_datalen); + perror(buffer); + } else + perror("sysctlbyname IPCS_MSG_SYSCTL"); + } + printf("msginfo:\n"); printf("\tmsgmax: %6d\t(max characters in a message)\n", msginfo.msgmax); @@ -197,11 +238,10 @@ main(argc, argv) } if (display & MSGINFO) { struct IPCS_command ic; - struct msqid_ds ds; - struct msqid_ds *msqptr = &ds; + struct __msqid_ds_new ds; + struct __msqid_ds_new *msqptr = &ds; size_t ic_size = sizeof(ic); - printf("Message Queues:\n"); printf("T ID KEY MODE OWNER GROUP"); if (option & CREATOR) printf(" CREATOR CGROUP"); @@ -213,15 +253,19 @@ main(argc, argv) printf(" LSPID LRPID"); if (option & TIME) printf(" STIME RTIME CTIME"); - printf("\n"); + printf("\nMessage Queues:\n"); ic.ipcs_magic = IPCS_MAGIC; ic.ipcs_op = IPCS_MSG_ITER; ic.ipcs_cursor = 0; /* start */ - ic.ipcs_data = msqptr; ic.ipcs_datalen = sizeof(*msqptr); + ic.ipcs_data = msqptr; + + memset(msqptr, 0, sizeof(*msqptr)); + + while(!(safe_sysctlbyname(IPCS_MSG_SYSCTL, &ic, &ic_size, &ic, ic_size))) { + ic.ipcs_data = msqptr; - while(!(sysctlbyname(IPCS_MSG_SYSCTL, &ic, &ic_size, &ic, ic_size))) { if (msqptr->msg_qbytes != 0) { char stime_buf[100], rtime_buf[100], ctime_buf[100]; @@ -230,10 +274,10 @@ main(argc, argv) cvt_time(msqptr->msg_rtime, rtime_buf); cvt_time(msqptr->msg_ctime, ctime_buf); - printf("q %6d %10d %s %8s %8s", - IXSEQ_TO_IPCID(i, msqptr->msg_perm), - (int)msqptr->msg_perm.key, - fmt_perm(msqptr->msg_perm.mode), + printf("q %6d 0x%08x %s %8s %8s", + IXSEQ_TO_IPCID(ic.ipcs_cursor-1, msqptr->msg_perm), + (int)msqptr->msg_perm._key, + fmt_perm(msqptr->msg_perm.mode, 'w'), user_from_uid(msqptr->msg_perm.uid, 0), group_from_gid(msqptr->msg_perm.gid, 0)); @@ -264,13 +308,22 @@ main(argc, argv) printf("\n"); } + memset(msqptr, 0, sizeof(*msqptr)); + errno = 0; + } + + if (errno != ENOENT && errno != ERANGE) { + if (errno != EPERM) { + errx(1, "sysctlbyname(IPCS_MSG_SYSCTL, op=ITER, &ic, &%ld) datalen=%d failed:%s\n", + sizeof(ic), ic.ipcs_datalen, strerror(errno)); + } else + errx(1, "sysctlbyname IPCS_MSG_SYSCTL: %s", strerror(errno)); } printf("\n"); } } else if (display & (MSGINFO | MSGTOTAL)) { - fprintf(stderr, - "SVID messages facility not configured in the system\n"); + errx(1, "%s", "SVID messages facility not configured in the system\n"); } if ((display & (SHMINFO | SHMTOTAL))) { @@ -285,26 +338,31 @@ main(argc, argv) ic.ipcs_data = &shminfo; ic.ipcs_datalen = sizeof(shminfo); - sysctlbyname(IPCS_SHM_SYSCTL, &ic, &ic_size, &ic, ic_size); + if (safe_sysctlbyname(IPCS_SHM_SYSCTL, &ic, &ic_size, &ic, ic_size)) { + if (errno != EPERM) { + errx(1, "sysctlbyname(IPCS_SHM_SYSCTL, op=CONF, &ic, &%ld) datalen=%d failed: %s\n", + sizeof(ic), ic.ipcs_datalen, strerror(errno)); + } else + errx(1, "sysctlbyname: %s", strerror(errno)); + } printf("shminfo:\n"); - printf("\tshmmax: %7d\t(max shared memory segment size)\n", + printf("\tshmmax: %7lld\t(max shared memory segment size)\n", shminfo.shmmax); - printf("\tshmmin: %7d\t(min shared memory segment size)\n", + printf("\tshmmin: %7lld\t(min shared memory segment size)\n", shminfo.shmmin); - printf("\tshmmni: %7d\t(max number of shared memory identifiers)\n", + printf("\tshmmni: %7lld\t(max number of shared memory identifiers)\n", shminfo.shmmni); - printf("\tshmseg: %7d\t(max shared memory segments per process)\n", + printf("\tshmseg: %7lld\t(max shared memory segments per process)\n", shminfo.shmseg); - printf("\tshmall: %7d\t(max amount of shared memory in pages)\n\n", + printf("\tshmall: %7lld\t(max amount of shared memory in pages)\n\n", shminfo.shmall); } if (display & SHMINFO) { struct IPCS_command ic; - struct shmid_ds ds; - struct shmid_ds *shmptr = &ds; + struct __shmid_ds_new ds; + struct __shmid_ds_new *shmptr = &ds; size_t ic_size = sizeof(ic); - printf("Shared Memory:\n"); printf("T ID KEY MODE OWNER GROUP"); if (option & CREATOR) printf(" CREATOR CGROUP"); @@ -316,16 +374,19 @@ main(argc, argv) printf(" CPID LPID"); if (option & TIME) printf(" ATIME DTIME CTIME"); - printf("\n"); + printf("\nShared Memory:\n"); { /* XXX */ ic.ipcs_magic = IPCS_MAGIC; ic.ipcs_op = IPCS_SHM_ITER; ic.ipcs_cursor = 0; /* start */ - ic.ipcs_data = shmptr; ic.ipcs_datalen = sizeof(*shmptr); + ic.ipcs_data = shmptr; + memset(shmptr, 0, sizeof(shmptr)); + + while(!(safe_sysctlbyname(IPCS_SHM_SYSCTL, &ic, &ic_size, &ic, ic_size))) { + ic.ipcs_data = shmptr; /* xnu workaround */ - while(!(sysctlbyname(IPCS_SHM_SYSCTL, &ic, &ic_size, &ic, ic_size))) { if (shmptr->shm_perm.mode & 0x0800) { char atime_buf[100], dtime_buf[100], ctime_buf[100]; @@ -334,10 +395,10 @@ main(argc, argv) cvt_time(shmptr->shm_dtime, dtime_buf); cvt_time(shmptr->shm_ctime, ctime_buf); - printf("m %6d %10d %s %8s %8s", - IXSEQ_TO_IPCID(i, shmptr->shm_perm), - (int)shmptr->shm_perm.key, - fmt_perm(shmptr->shm_perm.mode), + printf("m %6d 0x%08x %s %8s %8s", + IXSEQ_TO_IPCID(ic.ipcs_cursor-1, shmptr->shm_perm), + (int)shmptr->shm_perm._key, + fmt_perm(shmptr->shm_perm.mode, 'w'), user_from_uid(shmptr->shm_perm.uid, 0), group_from_gid(shmptr->shm_perm.gid, 0)); @@ -351,7 +412,7 @@ main(argc, argv) shmptr->shm_nattch); if (option & BIGGEST) - printf(" %6d", + printf(" %6ld", shmptr->shm_segsz); if (option & PID) @@ -367,6 +428,16 @@ main(argc, argv) printf("\n"); } + memset(shmptr, 0, sizeof(*shmptr)); + errno = 0; + } + + if (errno != ENOENT && errno != ERANGE) { + if (errno != EPERM) { + errx(1, "sysctlbyname(IPCS_SHM_SYSCTL, op=ITER, &ic, &%ld) datalen=%d failed:%s\n", + sizeof(ic), ic.ipcs_datalen, strerror(errno)); + } else + errx(1, "sysctlbyname: %s", strerror(errno)); } } /* XXX */ printf("\n"); @@ -374,8 +445,7 @@ main(argc, argv) } else if (display & (SHMINFO | SHMTOTAL)) { - fprintf(stderr, - "SVID shared memory facility not configured in the system\n"); + errx(1, "%s", "SVID shared memory facility not configured in the system\n"); } if ((display & (SEMINFO | SEMTOTAL))) { @@ -390,7 +460,16 @@ else ic.ipcs_data = &seminfo; ic.ipcs_datalen = sizeof(seminfo); - sysctlbyname(IPCS_SEM_SYSCTL, &ic, &ic_size, &ic, ic_size); + if (safe_sysctlbyname(IPCS_SEM_SYSCTL, &ic, &ic_size, &ic, ic_size)) { + if (errno != EPERM) { + char buffer[1024]; + snprintf(buffer, 1024, "sysctlbyname(IPCS_SEM_SYSCTL, op=CONF, &ic, &%ld) datalen=%d", + sizeof(ic), ic.ipcs_datalen); + perror(buffer); + } else + perror("sysctlbyname IPCS_SEM_SYSCTL/SEM_CONF"); + } + printf("seminfo:\n"); printf("\tsemmap: %6d\t(# of entries in semaphore map)\n", seminfo.semmap); @@ -415,11 +494,10 @@ else } if (display & SEMINFO) { struct IPCS_command ic; - struct semid_ds ds; - struct semid_ds *semaptr = &ds; + struct __semid_ds_new ds; + struct __semid_ds_new *semaptr = &ds; size_t ic_size = sizeof(ic); - printf("Semaphores:\n"); printf("T ID KEY MODE OWNER GROUP"); if (option & CREATOR) printf(" CREATOR CGROUP"); @@ -427,25 +505,29 @@ else printf(" NSEMS"); if (option & TIME) printf(" OTIME CTIME"); - printf("\n"); + printf("\nSemaphores:\n"); ic.ipcs_magic = IPCS_MAGIC; ic.ipcs_op = IPCS_SEM_ITER; ic.ipcs_cursor = 0; /* start */ - ic.ipcs_data = semaptr; ic.ipcs_datalen = sizeof(*semaptr); + ic.ipcs_data = semaptr; + + memset(semaptr, 0, sizeof(*semaptr)); + + while(!(safe_sysctlbyname(IPCS_SEM_SYSCTL, &ic, &ic_size, &ic, ic_size))) { + ic.ipcs_data = semaptr; /* xnu workaround */ - while(!(sysctlbyname(IPCS_SEM_SYSCTL, &ic, &ic_size, &ic, ic_size))) { if ((semaptr->sem_perm.mode & SEM_ALLOC) != 0) { char ctime_buf[100], otime_buf[100]; cvt_time(semaptr->sem_otime, otime_buf); cvt_time(semaptr->sem_ctime, ctime_buf); - printf("s %6d %10d %s %8s %8s", - IXSEQ_TO_IPCID(i, semaptr->sem_perm), - (int)semaptr->sem_perm.key, - fmt_perm(semaptr->sem_perm.mode), + printf("s %6d 0x%08x %s %8s %8s", + IXSEQ_TO_IPCID(ic.ipcs_cursor-1, semaptr->sem_perm), + (int)semaptr->sem_perm._key, + fmt_perm(semaptr->sem_perm.mode, 'a'), user_from_uid(semaptr->sem_perm.uid, 0), group_from_gid(semaptr->sem_perm.gid, 0)); @@ -465,22 +547,23 @@ else printf("\n"); } + memset(semaptr, 0, sizeof(*semaptr)); + errno = 0; } + if (errno != ENOENT && errno != ERANGE) { + if (errno != EPERM) { + errx(1, "sysctlbyname(IPCS_SEM_SYSCTL/ITER, op=ITER, &ic, &%ld) datalen=%d failed: %s\n", + sizeof(ic), ic.ipcs_datalen, strerror(errno)); + } else + errx(1, "sysctlbyname: IPCS_SEM_SYSCTL %s", strerror(errno)); + } printf("\n"); } } else if (display & (SEMINFO | SEMTOTAL)) { - fprintf(stderr, "SVID semaphores facility not configured in the system\n"); + errx(1, "%s", "SVID semaphores facility not configured in the system\n"); } - exit(0); -} - -usage() -{ - - fprintf(stderr, - "usage: ipcs [-abcmopqstMQST]\n"); - exit(1); + exit(exit_val); } diff --git a/ln/Makefile b/ln/Makefile index 15d04bd..db22a08 100644 --- a/ln/Makefile +++ b/ln/Makefile @@ -17,6 +17,7 @@ CFILES = ln.c OTHERSRCS = Makefile Makefile.preamble Makefile.postamble ln.1\ symlink.7 +OTHER_CFLAGS = -D__FBSDID=__RCSID MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC diff --git a/ln/ln.1 b/ln/ln.1 index 1dac859..37100d3 100644 --- a/ln/ln.1 +++ b/ln/ln.1 @@ -1,3 +1,4 @@ +.\"- .\" Copyright (c) 1980, 1990, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -12,10 +13,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 the University of -.\" California, Berkeley and its contributors. .\" 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. @@ -33,29 +30,29 @@ .\" SUCH DAMAGE. .\" .\" @(#)ln.1 8.2 (Berkeley) 12/30/93 -.\" $FreeBSD: src/bin/ln/ln.1,v 1.25 2002/08/21 17:32:32 trhodes Exp $ +.\" $FreeBSD: src/bin/ln/ln.1,v 1.31 2006/02/14 11:08:05 glebius Exp $ .\" -.Dd December 30, 1993 +.Dd February 14, 2006 .Dt LN 1 .Os .Sh NAME -.Nm ln , -.Nm link +.Nm link , +.Nm ln .Nd make links .Sh SYNOPSIS -.Nm -.Op Fl fhinsv +.Nm ln +.Op Fl Ffhinsv .Ar source_file .Op Ar target_file -.Nm -.Op Fl fhinsv +.Nm ln +.Op Fl Ffhinsv .Ar source_file ... .Ar target_dir .Nm link .Ar source_file Ar target_file .Sh DESCRIPTION The -.Nm +.Nm ln utility creates a new directory entry (linked file) which has the same modes as the original file. It is useful for maintaining multiple copies of a file in many places @@ -71,25 +68,47 @@ to a file is one of the differences between a hard and symbolic link. .Pp The options are as follows: .Bl -tag -width flag -.It Fl f -If the target file already exists, -then unlink it so that the link may occur. -(The +.\" ========== +.It Fl F +If the target file already exists and is a directory, then remove it +so that the link may occur. +The +.Fl F +option should be used with either .Fl f -option overrides any previous +or .Fl i -options.) +options. +If none is specified, +.Fl f +is implied. +The +.Fl F +option is a no-op unless +.Fl s +option is specified. .It Fl h If the .Ar target_file or .Ar target_dir -is a symbolic link, do not follow it. This is most useful with the +is a symbolic link, do not follow it. +This is most useful with the .Fl f option, to replace a symlink which may point to a directory. +.\" ========== +.It Fl f +If the target file already exists, +then unlink it so that the link may occur. +(The +.Fl f +option overrides any previous +.Fl i +options.) +.\" ========== .It Fl i Cause -.Nm +.Nm ln to write a prompt to standard error if the target file exists. If the response from the standard input begins with the character .Sq Li y @@ -102,22 +121,25 @@ Otherwise, do not attempt the link. option overrides any previous .Fl f options.) +.\" ========== .It Fl n Same as .Fl h , for compatibility with other -.Nm +.Nm ln implementations. +.\" ========== .It Fl s Create a symbolic link. +.\" ========== .It Fl v Cause -.Nm +.Nm ln to be verbose, showing files as they are processed. .El .Pp By default, -.Nm +.Nm ln makes .Em hard links. @@ -127,23 +149,24 @@ the file. Hard links may not normally refer to directories and may not span file systems. .Pp A symbolic link contains the name of the file to -which it is linked. The referenced file is used when an -.Xr open 2 +which it is linked. +The referenced file is used when an +.Xr open 2 operation is performed on the link. A -.Xr stat 2 +.Xr stat 2 on a symbolic link will return the linked-to file; an -.Xr lstat 2 +.Xr lstat 2 must be done to obtain information about the link. The -.Xr readlink 2 +.Xr readlink 2 call may be used to read the contents of a symbolic link. Symbolic links may span file systems and may refer to directories. .Pp Given one or two arguments, -.Nm +.Nm ln creates a link to an existing file -.Ar source_file . +.Ar source_file . If .Ar target_file is given, the link has that name; @@ -152,10 +175,10 @@ may also be a directory in which to place the link; otherwise it is placed in the current directory. If only the directory is specified, the link will be made to the last component of -.Ar source_file . +.Ar source_file . .Pp Given more than two arguments, -.Nm +.Nm ln makes links in .Ar target_dir to all the named source files. @@ -169,13 +192,6 @@ No options may be supplied in this simple mode of operation, which performs a .Xr link 2 operation using the two passed arguments. -.Sh SEE ALSO -.Xr link 2 , -.Xr lstat 2 , -.Xr readlink 2 , -.Xr stat 2 , -.Xr symlink 2 , -.Xr symlink 7 .Sh COMPATIBILITY The .Fl h , @@ -185,11 +201,24 @@ and .Fl v options are non-standard and their use in scripts is not recommended. They are provided solely for compatibility with other -.Nm +.Nm ln implementations. +.Pp +The +.Fl F +option is +.Fx +extention and should not be used in portable scripts. +.Sh SEE ALSO +.Xr link 2 , +.Xr lstat 2 , +.Xr readlink 2 , +.Xr stat 2 , +.Xr symlink 2 , +.Xr symlink 7 .Sh STANDARDS The -.Nm +.Nm ln utility conforms to .St -p1003.2-92 . .Pp @@ -199,6 +228,6 @@ command conforms to .St -susv2 . .Sh HISTORY An -.Nm +.Nm ln command appeared in .At v1 . diff --git a/ln/ln.c b/ln/ln.c index ffe399d..f7bdc7a 100644 --- a/ln/ln.c +++ b/ln/ln.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1987, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -10,10 +10,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 the University of - * California, Berkeley and its contributors. * 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. @@ -31,6 +27,7 @@ * SUCH DAMAGE. */ +#if 0 #ifndef lint static char const copyright[] = "@(#) Copyright (c) 1987, 1993, 1994\n\ @@ -38,12 +35,11 @@ static char const copyright[] = #endif /* not lint */ #ifndef lint -#if 0 static char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 3/31/94"; -#endif #endif /* not lint */ +#endif #include -__RCSID("$FreeBSD: src/bin/ln/ln.c,v 1.29 2002/07/31 16:53:59 markm Exp $"); +__FBSDID("$FreeBSD: src/bin/ln/ln.c,v 1.34 2006/02/14 11:08:05 glebius Exp $"); #include #include @@ -57,6 +53,7 @@ __RCSID("$FreeBSD: src/bin/ln/ln.c,v 1.29 2002/07/31 16:53:59 markm Exp $"); #include int fflag; /* Unlink existing files. */ +int Fflag; /* Remove empty directories also. */ int hflag; /* Check new name for symlink first. */ int iflag; /* Interactive mode. */ int sflag; /* Symbolic, not hard, link. */ @@ -75,6 +72,8 @@ main(int argc, char *argv[]) char *p, *sourcedir; int ch, exitval; + if (argc < 1) + usage(); /* * Test for the special case where the utility is called as * "link", for which the functionality provided is greatly @@ -95,8 +94,11 @@ main(int argc, char *argv[]) exit(linkit(argv[0], argv[1], 0)); } - while ((ch = getopt(argc, argv, "fhinsv")) != -1) + while ((ch = getopt(argc, argv, "Ffhinsv")) != -1) switch (ch) { + case 'F': + Fflag = 1; + break; case 'f': fflag = 1; iflag = 0; @@ -125,6 +127,10 @@ main(int argc, char *argv[]) linkf = sflag ? symlink : link; linkch = sflag ? '-' : '='; + if (sflag == 0) + Fflag = 0; + if (Fflag == 1 && iflag == 0) + fflag = 1; switch(argc) { case 0: @@ -204,7 +210,12 @@ linkit(const char *target, const char *source, int isdir) * and interactively if -i was specified. */ if (fflag && exists) { - if (unlink(source)) { + if (Fflag && S_ISDIR(sb.st_mode)) { + if (rmdir(source)) { + warn("%s", source); + return (1); + } + } else if (unlink(source)) { warn("%s", source); return (1); } @@ -220,7 +231,12 @@ linkit(const char *target, const char *source, int isdir) return (1); } - if (unlink(source)) { + if (Fflag && S_ISDIR(sb.st_mode)) { + if (rmdir(source)) { + warn("%s", source); + return (1); + } + } else if (unlink(source)) { warn("%s", source); return (1); } @@ -240,8 +256,8 @@ void usage(void) { (void)fprintf(stderr, "%s\n%s\n%s\n", - "usage: ln [-fhinsv] file1 file2", - " ln [-fhinsv] file ... directory", - " link file1 file2"); + "usage: ln [-Ffhinsv] source_file [target_file]", + " ln [-Ffhinsv] source_file ... target_dir", + " link source_file target_file"); exit(1); } diff --git a/ln/symlink.7 b/ln/symlink.7 index dc9f702..726f583 100644 --- a/ln/symlink.7 +++ b/ln/symlink.7 @@ -1,3 +1,4 @@ +.\"- .\" Copyright (c) 1992, 1993, 1994 .\" The Regents of the University of California. All rights reserved. .\" @@ -9,10 +10,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 the University of -.\" California, Berkeley and its contributors. .\" 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. @@ -30,7 +27,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)symlink.7 8.3 (Berkeley) 3/31/94 -.\" $FreeBSD: src/bin/ln/symlink.7,v 1.25 2002/08/21 17:32:32 trhodes Exp $ +.\" $FreeBSD: src/bin/ln/symlink.7,v 1.30 2005/02/13 22:25:09 ru Exp $ .\" .Dd March 31, 1994 .Dt SYMLINK 7 @@ -49,7 +46,7 @@ file. Hard links may not refer to directories and may not reference files on different file systems. A symbolic link contains the name of the file to which it is linked, -i.e. it is a pointer to another name, and not to an underlying object. +i.e., it is a pointer to another name, and not to an underlying object. For this reason, symbolic links may reference directories and may span file systems. .Pp @@ -72,7 +69,7 @@ the link. Symbolic links may reference other symbolic links, in which case the links are dereferenced until an object that is not a symbolic link is found, -a symbolic link which references a file which doesn't exist is found, +a symbolic link which references a file which does not exist is found, or a loop is detected. (Loop detection is done by placing an upper limit on the number of links that may be followed, and an error results if this limit is @@ -138,7 +135,7 @@ an existing symbolic link can be changed by means of the .Xr lchflags 2 , .Xr lchmod 2 , .Xr lchown 2 , -and +and .Xr lutimes 2 system calls, respectively. Of these, only the flags are used by the system; @@ -172,7 +169,7 @@ would display the contents of the file .Dq Li afile . .Pp It is important to realize that this rule includes commands which may -optionally traverse file trees, e.g. the command +optionally traverse file trees, e.g.\& the command .Dq Li "chown file" is included in this rule, while the command .Dq Li "chown -R file" @@ -213,7 +210,7 @@ The command is also an exception to this rule. For compatibility with historic systems (when .Nm ls -is not doing a tree walk, i.e. the +is not doing a tree walk, i.e., the .Fl R option is not specified), the @@ -228,7 +225,8 @@ or if the .Fl d or .Fl l -options are not specified. (The +options are not specified. +(The .Nm ls command is the only command where the .Fl H @@ -416,14 +414,16 @@ options. To maintain compatibility with historic systems, the .Nm ls -command acts a little differently. If you do not specify the +command acts a little differently. +If you do not specify the .Fl F , .Fl d or .Fl l options, .Nm ls -will follow symbolic links specified on the command line. If the +will follow symbolic links specified on the command line. +If the .Fl L flag is specified, .Nm ls diff --git a/ls/Makefile b/ls/Makefile index 35bb9cc..f593549 100644 --- a/ls/Makefile +++ b/ls/Makefile @@ -14,11 +14,11 @@ PROJECT_TYPE = Tool HFILES = extern.h ls.h -CFILES = cmp.c ls.c print.c util.c +CFILES = cmp.c ls.c print.c util.c humanize_number.c OTHERSRCS = Makefile Makefile.preamble Makefile.postamble ls.1 -OTHER_CFLAGS = -DCOLORLS -I/System/Library/Frameworks/System.framework/PrivateHeaders +OTHER_CFLAGS = -DCOLORLS -I/System/Library/Frameworks/System.framework/PrivateHeaders -D__FBSDID=__RCSID -D_DARWIN_USE_64_BIT_INODE OTHER_LDFLAGS = -lncurses MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles diff --git a/ls/extern.h b/ls/extern.h index 273719c..9d16436 100644 --- a/ls/extern.h +++ b/ls/extern.h @@ -44,12 +44,14 @@ int statcmp(const FTSENT *, const FTSENT *); int revstatcmp(const FTSENT *, const FTSENT *); int sizecmp (const FTSENT *, const FTSENT *); int revsizecmp (const FTSENT *, const FTSENT *); +int humanize_number(char *, size_t, int64_t, const char *, int, int); void printcol(DISPLAY *); void printlong(DISPLAY *); void printscol(DISPLAY *); void printstream(DISPLAY *); void usage(void); +int prn_normal(const char *); size_t len_octal(const char *, int); int prn_octal(const char *); int prn_printable(const char *); diff --git a/ls/humanize_number.c b/ls/humanize_number.c new file mode 100644 index 0000000..f855a4b --- /dev/null +++ b/ls/humanize_number.c @@ -0,0 +1,148 @@ +/* $NetBSD: humanize_number.c,v 1.8 2004/07/27 01:56:24 enami Exp $ */ + +/* + * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ls.h" + +int +humanize_number(char *buf, size_t len, int64_t bytes, + const char *suffix, int scale, int flags) +{ + const char *prefixes, *sep; + int b, i, r, maxscale, s1, s2, sign; + int64_t divisor, max; + size_t baselen; + + assert(buf != NULL); + assert(suffix != NULL); + assert(scale >= 0); + + if (flags & HN_DIVISOR_1000) { + /* SI for decimal multiplies */ + divisor = 1000; + if (flags & HN_B) + prefixes = "B\0k\0M\0G\0T\0P\0E"; + else + prefixes = "\0\0k\0M\0G\0T\0P\0E"; + } else { + /* + * binary multiplies + * XXX IEC 60027-2 recommends Ki, Mi, Gi... + */ + divisor = 1024; + if (flags & HN_B) + prefixes = "B\0K\0M\0G\0T\0P\0E"; + else + prefixes = "\0\0K\0M\0G\0T\0P\0E"; + } + +#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1]) + maxscale = 7; + + if (scale >= maxscale && + (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0) + return (-1); + + if (buf == NULL || suffix == NULL) + return (-1); + + if (len > 0) + buf[0] = '\0'; + if (bytes < 0) { + sign = -1; + bytes *= -100; + baselen = 3; /* sign, digit, prefix */ + } else { + sign = 1; + bytes *= 100; + baselen = 2; /* digit, prefix */ + } + if (flags & HN_NOSPACE) + sep = ""; + else { + sep = " "; + baselen++; + } + baselen += strlen(suffix); + + /* Check if enough room for `x y' + suffix + `\0' */ + if (len < baselen + 1) + return (-1); + + if (scale & (HN_AUTOSCALE | HN_GETSCALE)) { + /* See if there is additional columns can be used. */ + for (max = 100, i = len - baselen; i-- > 0;) + max *= 10; + + for (i = 0; bytes >= max && i < maxscale; i++) + bytes /= divisor; + + if (scale & HN_GETSCALE) + return (i); + } else + for (i = 0; i < scale && i < maxscale; i++) + bytes /= divisor; + + /* If a value <= 9.9 after rounding and ... */ + if (bytes < 995 && i > 0 && flags & HN_DECIMAL) { + /* baselen + \0 + .N */ + if (len < baselen + 1 + 2) + return (-1); + b = ((int)bytes + 5) / 10; + s1 = b / 10; + s2 = b % 10; + r = snprintf(buf, len, "%d%s%d%s%s%s", + sign * s1, localeconv()->decimal_point, s2, + sep, SCALE2PREFIX(i), suffix); + } else + r = snprintf(buf, len, "%lld%s%s%s", + /* LONGLONG */ + (long long)(sign * ((bytes + 50) / 100)), + sep, SCALE2PREFIX(i), suffix); + + return (r); +} diff --git a/ls/ls.1 b/ls/ls.1 index dad0f65..c59ac1f 100644 --- a/ls/ls.1 +++ b/ls/ls.1 @@ -42,21 +42,21 @@ .Nm ls .Nd list directory contents .Sh SYNOPSIS -.Nm -.Op Fl ABCFGHLPRTWZabcdefghiklmnopqrstuwx1 +.Nm ls +.Op Fl ABCFGHLPRSTW@abcdefghiklmnopqrstuwx1 .Op Ar .Sh DESCRIPTION For each operand that names a .Ar file of a type other than directory, -.Nm +.Nm ls displays its name as well as any requested, associated information. For each operand that names a .Ar file of type directory, -.Nm +.Nm ls displays the names of files contained within that directory, as well as any requested, associated information. @@ -70,12 +70,29 @@ lexicographical order. .Pp The following options are available: .Bl -tag -width indent +.\" ========== +.It Fl @ +Display extended attribute keys and sizes. +.It Fl 1 +(The numeric digit +.Dq one . ) +Force output to be +one entry per line. +This is the default when +output is not to a terminal. +.\" ========== .It Fl A List all entries except for .Pa \&. and .Pa .. . Always set for the super-user. +.\" ========== +.It Fl a +Include directory entries whose names begin with a +dot +.Pq Pa \&. . +.\" ========== .It Fl B Force printing of non-printable characters (as defined by .Xr ctype 3 @@ -84,8 +101,26 @@ and current locale settings) in file names as where .Va xxx is the numeric value of the character in octal. +.\" ========== +.It Fl b +As +.Fl B , +but use +.Tn C +escape codes whenever possible. +.\" ========== .It Fl C Force multi-column output; this is the default when output is to a terminal. +.\" ========== +.It Fl c +Use time when file status was last changed for sorting or printing. +.\" ========== +.It Fl d +Directories are listed as plain files (not searched recursively). +.\" ========== +.It Fl e +Print the Access Control List (ACL) associated with the file, if present. +.\" ========== .It Fl F Display a slash .Pq Ql / @@ -106,12 +141,26 @@ and a vertical bar .Pq Ql \&| after each that is a .Tn FIFO . +.\" ========== +.It Fl f +Output is not sorted. +This option turns on the +.Fl a +option. +.\" ========== .It Fl G Enable colorized output. This option is equivalent to defining .Ev CLICOLOR in the environment. (See below.) +.\" ========== +.It Fl g +This option is only available for compatibility with POSIX; +it is used to display the group name in the long +.Pq Fl l +format output (the owner name is suppressed). +.\" ========== .It Fl H Symbolic links on the command line are followed. This option is assumed if @@ -120,65 +169,17 @@ none of the or .Fl l options are specified. -.It Fl L -If argument is a symbolic link, list the file or directory the link references -rather than the link itself. -This option cancels the -.Fl P -option. -.It Fl P -If argument is a symbolic link, list the link itself rather than the -object the link references. -This option cancels the -.Fl H -and -.Fl L -options. -.It Fl R -Recursively list subdirectories encountered. -.It Fl S -Sort files by size -.It Fl T -When used with the -.Fl l -(lowercase letter -.Dq ell ) -option, display complete time information for the file, including -month, day, hour, minute, second, and year. -.It Fl W -Display whiteouts when scanning directories. -.It Fl a -Include directory entries whose names begin with a -dot -.Pq Pa \&. . -.It Fl b -As -.Fl B , -but use -.Tn C -escape codes whenever possible. -.It Fl c -Use time when file status was last changed for sorting or printing. -.It Fl d -Directories are listed as plain files (not searched recursively). -.It Fl e -Print the Access Control List (ACL) associated with the file, if present. -.It Fl f -Output is not sorted. -.It Fl g -This option is only available for compatibility -with POSIX; -it is used to display the group name in the long -.Pq Fl l -format output. +.\" ========== .It Fl h When used with the .Fl l option, use unit suffixes: Byte, Kilobyte, Megabyte, Gigabyte, Terabyte and Petabyte in order to reduce the number of digits to three or less using base 2 for sizes. +.\" ========== .It Fl i For each file, print the file's file serial number (inode number). +.\" ========== .It Fl k If the .Fl s @@ -186,6 +187,14 @@ option is specified, print the file size allocation in kilobytes, not blocks. This option overrides the environment variable .Ev BLOCKSIZE . +.\" ========== +.It Fl L +If argument is a symbolic link, list the file or directory the link references +rather than the link itself. +This option cancels the +.Fl P +option. +.\" ========== .It Fl l (The lowercase letter .Dq ell . ) @@ -193,32 +202,58 @@ List in long format. (See below.) If the output is to a terminal, a total sum for all the file sizes is output on a line before the long listing. +.\" ========== .It Fl m Stream output format; list files across the page, separated by commas. +.\" ========== .It Fl n -Display user and group IDs numerically rather than converting to a user -or group name in a long +Display user and group IDs numerically, +rather than converting to a user or group name in a long .Pq Fl l output. -.It Fl o +This option turns on the +.Fl l +option. +.\" ========== +.It Fl O Include the file flags in a long .Pq Fl l output. +.\" ========== +.It Fl o +List in long format, but omit the group id. +.\" ========== +.It Fl P +If argument is a symbolic link, list the link itself rather than the +object the link references. +This option cancels the +.Fl H +and +.Fl L +options. +.\" ========== .It Fl p Write a slash .Pq Ql / after each filename if that file is a directory. +.\" ========== .It Fl q Force printing of non-graphic characters in file names as the character .Ql \&? ; this is the default when output is to a terminal. +.\" ========== +.It Fl R +Recursively list subdirectories encountered. +.\" ========== .It Fl r Reverse the order of the sort to get reverse lexicographical order or the oldest entries first (or largest files last, if combined with sort by size -.Pq Fl S -flag). +.\" ========== +.It Fl S +Sort files by size +.\" ========== .It Fl s Display the number of file system blocks actually used by each file, in units of 512 bytes, where partial units are rounded up to the next integer value. @@ -227,10 +262,20 @@ sizes is output on a line before the listing. The environment variable .Ev BLOCKSIZE overrides the unit size of 512 bytes. +.\" ========== +.It Fl T +When used with the +.Fl l +(lowercase letter +.Dq ell ) +option, display complete time information for the file, including +month, day, hour, minute, second, and year. +.\" ========== .It Fl t Sort by time modified (most recently modified first) before sorting the operands by lexicographical order. +.\" ========== .It Fl u Use time of last access, instead of last modification @@ -238,33 +283,34 @@ of the file for sorting .Pq Fl t or printing .Pq Fl l . +.\" ========== +.It Fl v +Force unedited printing of non-graphic characters; this is the default when +output is not to a terminal. +.\" ========== +.It Fl W +Display whiteouts when scanning directories. +.Pq Fl S +flag). +.\" ========== .It Fl w Force raw printing of non-printable characters. This is the default when output is not to a terminal. +.\" ========== .It Fl x The same as .Fl C , except that the multi-column output is produced with entries sorted across, rather than down, the columns. -.It Fl v -Force unedited printing of non-graphic characters; this is the default when -output is not to a terminal. -.It Fl 1 -(The numeric digit -.Dq one . ) -Force output to be -one entry per line. -This is the default when -output is not to a terminal. .El .Pp The .Fl 1 , C , x , and .Fl l -options all override each other; the last one specified determines -the format used. +options all override each other; +the last one specified determines the format used. .Pp The .Fl c @@ -277,8 +323,9 @@ The .Fl B , b , w , and .Fl q -options all override each other; the last one specified determines -the format used for non-printable characters. +options all override each other; +the last one specified determines the format used +for non-printable characters. .Pp The .Fl H , L @@ -288,7 +335,7 @@ options all override each other (either partially or fully); they are applied in the order specified. .Pp By default, -.Nm +.Nm ls lists one entry per line to standard output; the exceptions are to terminals or when the .Fl C @@ -314,17 +361,22 @@ number of bytes in the file, abbreviated month, day-of-month file was last modified, hour file last modified, minute file last modified, and the pathname. -In addition, for each directory whose contents are displayed, the total -number of 512-byte blocks used by the files in the directory is displayed -on a line by itself immediately before the information for the files in the -directory. -If the file or directory has extended security information, the permissions -field printed by the +In addition, for each directory whose contents are displayed, +the total number of 512-byte blocks used by the files in the directory +is displayed on a line by itself, +immediately before the information for the files in the directory. +If the file or directory has extended attributes, +the permissions field printed by the +.Fl l +option is followed by a '@' character. +Otherwise, if the file or directory has extended security information, +the permissions field printed by the .Fl l option is followed by a '+' character. .Pp -If the modification time of the file is more than 6 months -in the past or future, then the year of the last modification +If the modification time of the file +is more than 6 months in the past or future, +then the year of the last modification is displayed in place of the hour and minute fields. .Pp If the owner or group names are not a known user or group name, @@ -336,16 +388,16 @@ the numeric ID's are displayed. If the file is a character special or block special file, the major and minor device numbers for the file are displayed in the size field. -If the file is a symbolic link the pathname of the -linked-to file is preceded by +If the file is a symbolic link, +the pathname of the linked-to file is preceded by .Dq Li -> . .Pp The file mode printed under the .Fl l option consists of the entry type, owner permissions, and group permissions. -The entry type character describes the type of file, as -follows: +The entry type character describes the type of file, +as follows: .Pp .Bl -tag -width 4n -offset indent -compact .It Sy b @@ -429,24 +481,15 @@ or .El .Sh EXAMPLES The following is how to do an -.Nm -listing sorted by size (and shows why -.Nm -does not need a separate option for this): -.Pp -.Dl "ls -l | sort -n +4" +.Nm ls +listing sorted by increasing size .Pp -Additionally, the -.Fl r -flag to -.Xr sort 1 -may be used -to get the results sorted from largest to smallest (a reverse sort). +.Dl "ls -lrS" .Sh DIAGNOSTICS .Ex -std .Sh ENVIRONMENT The following environment variables affect the execution of -.Nm : +.Nm ls : .Bl -tag -width ".Ev CLICOLOR_FORCE" .It Ev BLOCKSIZE If the environment variable @@ -499,7 +542,7 @@ decimal integer, it is used as the column position width for displaying multiple-text-column output. The -.Nm +.Nm ls utility calculates how many pathname text columns to display based on the width provided. @@ -628,6 +671,38 @@ The group field is now automatically included in the long listing for files in order to be compatible with the .St -p1003.2 specification. +.Sh LEGACY DESCRIPTION +In legacy mode, the +.Fl f +option does not turn on the +.Fl a +option and the +.Fl g , +.Fl n , +and +.Fl o +options do not turn on the +.Fl l +option. +.Pp +Also, the +.Fl o +option causes the file flags to be included in a long (-l) output; +there is no +.Fl O +option. +.Pp +When +.Fl H +is specified (and not overridden by +.Fl L +or +.Fl P ) +and a file argument is a symlink +that resolves to a non-directory file, +the output will reflect the nature of the link, +rather than that of the file. +In legacy operation, the output will describe the file. .Sh SEE ALSO .Xr chflags 1 , .Xr chmod 1 , @@ -639,12 +714,12 @@ specification. .Xr sticky 8 .Sh STANDARDS The -.Nm +.Nm ls utility conforms to .St -p1003.1-2001 . .Sh HISTORY An -.Nm +.Nm ls command appeared in .At v1 . .Sh BUGS diff --git a/ls/ls.c b/ls/ls.c index f009917..749af98 100644 --- a/ls/ls.c +++ b/ls/ls.c @@ -84,8 +84,8 @@ __RCSID("$FreeBSD: src/bin/ls/ls.c,v 1.66 2002/09/21 01:28:36 wollman Exp $"); #define STRBUF_SIZEOF(t) (1 + CHAR_BIT * sizeof(t) / 3 + 1) static void display(FTSENT *, FTSENT *); -static u_quad_t makenines(u_long); -static int mastercmp(const FTSENT * const *, const FTSENT * const *); +static u_quad_t makenines(u_quad_t); +static int mastercmp(const FTSENT **, const FTSENT **); static void traverse(int, char **, int); static void (*printfcn)(DISPLAY *); @@ -106,7 +106,7 @@ static int f_listdot; /* list files beginning with . */ int f_nonprint; /* show unprintables as ? */ static int f_nosort; /* don't sort output */ int f_notabs; /* don't use tab-separated multi-col output */ -static int f_numericonly; /* don't convert uid/gid to name */ + int f_numericonly; /* don't convert uid/gid to name */ int f_octal; /* show unprintables as \xxx */ int f_octal_escape; /* like f_octal but use C escapes if possible */ static int f_recursive; /* ls subdirectories also */ @@ -123,7 +123,9 @@ static int f_sizesort; /* sort by size */ int f_type; /* add type character for non-regular files */ static int f_whiteout; /* show whiteout entries */ int f_acl; /* show ACLs in long listing */ + int f_xattr; /* show extended attributes in long listing */ int f_group; /* show group */ + int f_owner; /* show owner */ #ifdef COLORLS int f_color; /* add type in color for non-regular files */ @@ -149,6 +151,8 @@ main(int argc, char *argv[]) char *bp = tcapbuf; #endif + if (argc < 1) + usage(); (void)setlocale(LC_ALL, ""); /* Terminal defaults to -Cq, non-terminal defaults to -1. */ @@ -173,7 +177,7 @@ main(int argc, char *argv[]) f_listdot = 1; fts_options = FTS_PHYSICAL; - while ((ch = getopt(argc, argv, "1ABCFGHLPRSTWabcdefghiklmnopqrstuvwx")) + while ((ch = getopt(argc, argv, "1@ABCFGHLOPRSTWabcdefghiklmnopqrstuvwx")) != -1) { switch (ch) { /* @@ -217,7 +221,12 @@ main(int argc, char *argv[]) f_slash = 0; break; case 'H': - fts_options |= FTS_COMFOLLOW; + if (COMPAT_MODE("bin/ls", "Unix2003")) { + fts_options &= ~FTS_LOGICAL; + fts_options |= FTS_PHYSICAL; + fts_options |= FTS_COMFOLLOWDIR; + } else + fts_options |= FTS_COMFOLLOW; break; case 'G': setenv("CLICOLOR", "", 1); @@ -225,9 +234,12 @@ main(int argc, char *argv[]) case 'L': fts_options &= ~FTS_PHYSICAL; fts_options |= FTS_LOGICAL; + if (COMPAT_MODE("bin/ls", "Unix2003")) { + fts_options &= ~(FTS_COMFOLLOW|FTS_COMFOLLOWDIR); + } break; case 'P': - fts_options &= ~FTS_COMFOLLOW; + fts_options &= ~(FTS_COMFOLLOW|FTS_COMFOLLOWDIR); fts_options &= ~FTS_LOGICAL; fts_options |= FTS_PHYSICAL; break; @@ -247,6 +259,10 @@ main(int argc, char *argv[]) break; case 'f': f_nosort = 1; + if (COMPAT_MODE("bin/ls", "Unix2003")) { + fts_options |= FTS_SEEDOT; + f_listdot = 1; + } break; case 'g': /* Compatibility with Unix03 */ if (COMPAT_MODE("bin/ls", "Unix2003")) { @@ -272,9 +288,21 @@ main(int argc, char *argv[]) break; case 'n': f_numericonly = 1; + if (COMPAT_MODE("bin/ls", "Unix2003")) { + f_longform = 1; + f_singlecol = 0; + f_stream = 0; + } break; case 'o': - f_flags = 1; + if (COMPAT_MODE("bin/ls", "Unix2003")) { + f_owner = 1; + f_longform = 1; + f_singlecol = 0; + f_stream = 0; + } else { + f_flags = 1; + } break; case 'p': f_slash = 1; @@ -321,6 +349,12 @@ main(int argc, char *argv[]) case 'e': f_acl = 1; break; + case '@': + f_xattr = 1; + break; + case 'O': + f_flags = 1; + break; default: case '?': usage(); @@ -382,7 +416,7 @@ main(int argc, char *argv[]) * If not -F, -d or -l options, follow any symbolic links listed on * the command line. */ - if (!f_longform && !f_listdir && !f_type) + if (!f_longform && !f_listdir && !f_type && !f_inode) fts_options |= FTS_COMFOLLOW; /* @@ -457,15 +491,17 @@ traverse(int argc, char *argv[], int options) { FTS *ftsp; FTSENT *p, *chp; - int ch_options; + int ch_options, error; if ((ftsp = fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL) err(1, "fts_open"); display(NULL, fts_children(ftsp, 0)); - if (f_listdir) + if (f_listdir) { + fts_close(ftsp); return; + } /* * If not recursing down this tree and don't need stat info, just get @@ -477,6 +513,9 @@ traverse(int argc, char *argv[], int options) switch (p->fts_info) { case FTS_DC: warnx("%s: directory causes a cycle", p->fts_name); + if (COMPAT_MODE("bin/ls", "Unix2003")) { + rval = 1; + } break; case FTS_DNR: case FTS_ERR: @@ -505,9 +544,23 @@ traverse(int argc, char *argv[], int options) if (!f_recursive && chp != NULL) (void)fts_set(ftsp, p, FTS_SKIP); break; + case FTS_SLNONE: /* Same as default unless Unix conformance */ + if (COMPAT_MODE("bin/ls", "Unix2003")) { + if ((options & FTS_LOGICAL)!=0) { /* -L was specified */ + if (p->fts_errno) { + warnx("%s: %s", p->fts_name, strerror(p->fts_errno)); + rval = 1; + } + } + } + break; default: break; } + error = errno; + fts_close(ftsp); + errno = error; + if (errno) err(1, "fts_read"); } @@ -526,7 +579,8 @@ display(FTSENT *p, FTSENT *list) NAMES *np; off_t maxsize; u_int64_t btotal, maxblock; - u_long lattrlen, maxinode, maxlen, maxnlink, maxlattr; + u_long lattrlen, maxlen, maxnlink, maxlattr; + ino_t maxinode; int bcfile, maxflags; gid_t maxgroup; uid_t maxuser; @@ -582,7 +636,11 @@ display(FTSENT *p, FTSENT *list) strcpy(initmax2, "0"); ninitmax = sscanf(jinitmax, +#if _DARWIN_FEATURE_64_BIT_INODE + " %llu : %qu : %lu : %i : %i : %i : %qu : %lu : %lu ", +#else " %lu : %qu : %lu : %i : %i : %i : %qu : %lu : %lu ", +#endif &maxinode, &maxblock, &maxnlink, &maxuser, &maxgroup, &maxflags, &maxsize, &maxlen, &maxlattr); f_notabs = 1; @@ -744,7 +802,11 @@ display(FTSENT *p, FTSENT *list) d.s_flags = maxflags; d.s_lattr = maxlattr; d.s_group = maxgroup; +#if _DARWIN_FEATURE_64_BIT_INODE + (void)snprintf(buf, sizeof(buf), "%llu", maxinode); +#else (void)snprintf(buf, sizeof(buf), "%lu", maxinode); +#endif d.s_inode = strlen(buf); (void)snprintf(buf, sizeof(buf), "%lu", maxnlink); d.s_nlink = strlen(buf); @@ -767,7 +829,7 @@ display(FTSENT *p, FTSENT *list) * All other levels use the sort function. Error entries remain unsorted. */ static int -mastercmp(const FTSENT * const *a, const FTSENT * const *b) +mastercmp(const FTSENT **a, const FTSENT **b) { int a_info, b_info; @@ -796,7 +858,7 @@ mastercmp(const FTSENT * const *a, const FTSENT * const *b) * into a number that wide in decimal. */ static u_quad_t -makenines(u_long n) +makenines(u_quad_t n) { u_long i; u_quad_t reg; diff --git a/ls/ls.h b/ls/ls.h index 73e264d..6bb1aa2 100644 --- a/ls/ls.h +++ b/ls/ls.h @@ -40,6 +40,14 @@ #define NO_PRINT 1 +#define HN_DECIMAL 0x01 +#define HN_NOSPACE 0x02 +#define HN_B 0x04 +#define HN_DIVISOR_1000 0x08 + +#define HN_GETSCALE 0x10 +#define HN_AUTOSCALE 0x20 + extern long blocksize; /* block size units */ extern int f_accesstime; /* use time of last access */ @@ -58,10 +66,13 @@ extern int f_statustime; /* use time of last mode change */ extern int f_notabs; /* don't use tab-separated multi-col output */ extern int f_type; /* add type character for non-regular files */ extern int f_acl; /* print ACLs in long format */ +extern int f_xattr; /* print extended attributes in long format */ extern int f_group; /* list group without owner */ +extern int f_owner; /* list owner without group */ #ifdef COLORLS extern int f_color; /* add type in color for non-regular files */ #endif +extern int f_numericonly; /* don't convert uid/gid to name */ typedef struct { FTSENT *list; diff --git a/ls/print.c b/ls/print.c index a9d651e..02b1211 100644 --- a/ls/print.c +++ b/ls/print.c @@ -46,6 +46,7 @@ __RCSID("$FreeBSD: src/bin/ls/print.c,v 1.57 2002/08/29 14:29:09 keramida Exp $" #include #ifdef __APPLE__ #include +#include #include #include #include @@ -70,6 +71,12 @@ __RCSID("$FreeBSD: src/bin/ls/print.c,v 1.57 2002/08/29 14:29:09 keramida Exp $" #include #endif +#ifdef __APPLE__ +#include +#else +#define COMPAT_MODE(a,b) (1) +#endif /* __APPLE__ */ + #include "ls.h" #include "extern.h" @@ -85,27 +92,6 @@ static int colortype(mode_t); #define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) -#define KILO_SZ(n) (n) -#define MEGA_SZ(n) ((n) * (n)) -#define GIGA_SZ(n) ((n) * (n) * (n)) -#define TERA_SZ(n) ((n) * (n) * (n) * (n)) -#define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n)) - -#define KILO_2_SZ (KILO_SZ(1024ULL)) -#define MEGA_2_SZ (MEGA_SZ(1024ULL)) -#define GIGA_2_SZ (GIGA_SZ(1024ULL)) -#define TERA_2_SZ (TERA_SZ(1024ULL)) -#define PETA_2_SZ (PETA_SZ(1024ULL)) - -static u_int64_t vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ}; - -typedef enum { - NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX -} unit_t; -static unit_t unit_adjust(off_t *); - -static int unitp[] = {NONE, KILO, MEGA, GIGA, TERA, PETA}; - #ifdef COLORLS /* Most of these are taken from */ typedef enum Colors { @@ -139,6 +125,11 @@ printscol(DISPLAY *dp) { FTSENT *p; + if (COMPAT_MODE("bin/ls", "Unix2003")) { + if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) + (void)printf("total %qu\n", (u_int64_t)howmany(dp->btotal, blocksize)); + } + for (p = dp->list; p; p = p->fts_link) { if (IS_NOPRINT(p)) continue; @@ -158,7 +149,7 @@ printname(const char *name) else if (f_nonprint) return prn_printable(name); else - return printf("%s", name); + return prn_normal(name); } /* @@ -219,8 +210,10 @@ uuid_to_name(uuid_t *uu) if (NULL == name) err(1, "malloc"); - if (0 != mbr_uuid_to_id(uu, &id, &is_gid)) + if (!f_numericonly) { + if (0 != mbr_uuid_to_id(*uu, &id, &is_gid)) goto errout; + } switch (is_gid) { case ID_TYPE_UID: @@ -238,20 +231,43 @@ uuid_to_name(uuid_t *uu) snprintf(name, MAXNAMETAG, "%s:%s", "group", tgrp->gr_name); break; default: - if (0 != mbr_uuid_to_string(uu, name)) - goto errout; + goto errout; } return name; errout: - fprintf(stderr, "Unable to translate qualifier on ACL\n"); - strcpy(name, ""); + if (0 != mbr_uuid_to_string(*uu, name)) { + fprintf(stderr, "Unable to translate qualifier on ACL\n"); + strcpy(name, ""); + } return name; } static void +printxattr(DISPLAY *dp, char *filename, ssize_t xattr) +{ + int flags = XATTR_NOFOLLOW; + char *buf = malloc(xattr); + + if (NULL == buf) + err(1, "malloc"); + if (listxattr(filename, buf, xattr, flags) > 0) { + char *name; + for (name = buf; name < buf+xattr; name += strlen(name) + 1) { + ssize_t size = getxattr(filename, name, 0, 0, 0, flags); + putchar('\t'); + printname(name); + putchar('\t'); + printsize(dp->s_size, size); + putchar('\n'); + } + } + free(buf); +} + +static void printacl(acl_t acl, int isdir) { - acl_entry_t entry; + acl_entry_t entry = NULL; int index; uuid_t *applicable; char *name = NULL; @@ -326,7 +342,11 @@ printlong(DISPLAY *dp) char buf[20]; #ifdef __APPLE__ acl_t acl = NULL; + acl_entry_t dummy; char full_path[MAXPATHLEN]; + char *filename; + ssize_t xattr = 0; + char str[2]; #endif #ifdef COLORLS int color_printed = 0; @@ -339,34 +359,73 @@ printlong(DISPLAY *dp) if (IS_NOPRINT(p)) continue; sp = p->fts_statp; - if (f_inode) + if (f_inode) +#if _DARWIN_FEATURE_64_BIT_INODE + (void)printf("%*llu ", dp->s_inode, (u_quad_t)sp->st_ino); +#else (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); +#endif if (f_size) (void)printf("%*qu ", dp->s_block, (u_int64_t)howmany(sp->st_blocks, blocksize)); strmode(sp->st_mode, buf); np = p->fts_pointer; #ifdef __APPLE__ - if (p->fts_parent->fts_name && *p->fts_parent->fts_name) + buf[10] = '\0'; /* make +/@ abut the mode */ + filename = p->fts_name; + if (p->fts_level != FTS_ROOTLEVEL) { snprintf(full_path, sizeof full_path, "%s/%s", - p->fts_parent->fts_accpath, p->fts_accpath); - acl = acl_get_file(full_path, ACL_TYPE_EXTENDED); - } else - acl = acl_get_file(p->fts_accpath, ACL_TYPE_EXTENDED); + p->fts_parent->fts_accpath, p->fts_name); + filename = full_path; + } + /* symlinks can not have ACLs */ + acl = acl_get_link_np(filename, ACL_TYPE_EXTENDED); + if (acl && acl_get_entry(acl, ACL_FIRST_ENTRY, &dummy) == -1) { + acl_free(acl); + acl = NULL; + } + xattr = listxattr(filename, NULL, 0, XATTR_NOFOLLOW); + if (xattr < 0) + xattr = 0; + str[1] = '\0'; + if (xattr > 0) + str[0] = '@'; + else if (acl != NULL) + str[0] = '+'; + else + str[0] = ' '; +#endif /* __APPLE__ */ + if (f_group && f_owner) { /* means print neither */ +#ifdef __APPLE__ + (void)printf("%s%s %*u ", buf, str, dp->s_nlink, + sp->st_nlink); +#else /* ! __APPLE__ */ + (void)printf("%s %*u ", buf, dp->s_nlink, + sp->st_nlink); #endif /* __APPLE__ */ - if (f_group) { + } + else if (f_group) { #ifdef __APPLE__ - (void)printf("%s%s %*u %-*s ", buf, acl == NULL ? " " : "+", dp->s_nlink, + (void)printf("%s%s %*u %-*s ", buf, str, dp->s_nlink, sp->st_nlink, dp->s_group, np->group); #else /* ! __APPLE__ */ (void)printf("%s %*u %-*s ", buf, dp->s_nlink, sp->st_nlink, dp->s_group, np->group); #endif /* __APPLE__ */ } + else if (f_owner) { +#ifdef __APPLE__ + (void)printf("%s%s %*u %-*s ", buf, str, dp->s_nlink, + sp->st_nlink, dp->s_user, np->user); +#else /* ! __APPLE__ */ + (void)printf("%s %*u %-*s ", buf, dp->s_nlink, + sp->st_nlink, dp->s_user, np->user); +#endif /* __APPLE__ */ + } else { #ifdef __APPLE__ - (void)printf("%s%s %*u %-*s %-*s ", buf, acl == NULL ? " " : "+", dp->s_nlink, + (void)printf("%s%s %*u %-*s %-*s ", buf, str, dp->s_nlink, sp->st_nlink, dp->s_user, np->user, dp->s_group, np->group); #else /* ! __APPLE__ */ @@ -411,9 +470,15 @@ printlong(DISPLAY *dp) printlink(p); (void)putchar('\n'); #ifdef __APPLE__ - if (f_acl && (acl != NULL)) - printacl(acl, S_ISDIR(sp->st_mode)); - acl_free(acl); + if (f_xattr && xattr) { + printxattr(dp, filename, xattr); + } + if (acl != NULL) { + if (f_acl) + printacl(acl, S_ISDIR(sp->st_mode)); + acl_free(acl); + acl = NULL; + } #endif /* __APPLE__ */ } } @@ -582,6 +647,14 @@ printtime(time_t ftime) if (f_sectime) /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ format = d_first ? "%e %b %T %Y " : "%b %e %T %Y "; + else if (COMPAT_MODE("bin/ls", "Unix2003")) { + if (ftime + SIXMONTHS > now && ftime <= now) + /* mmm dd hh:mm || dd mmm hh:mm */ + format = d_first ? "%e %b %R " : "%b %e %R "; + else + /* mmm dd yyyy || dd mmm yyyy */ + format = d_first ? "%e %b %Y " : "%b %e %Y "; + } else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) /* mmm dd hh:mm || dd mmm hh:mm */ format = d_first ? "%e %b %R " : "%b %e %R "; @@ -800,43 +873,13 @@ printlink(FTSENT *p) static void printsize(size_t width, off_t bytes) { - unit_t unit; - if (f_humanval) { - unit = unit_adjust(&bytes); - - if (bytes == 0) - (void)printf("%*s ", (int)width, "0B"); - else - (void)printf("%*lld%c ", (int)width - 1, bytes, - "BKMGTPE"[unit]); - } else - (void)printf("%*lld ", (int)width, bytes); -} - -/* - * Output in "human-readable" format. Uses 3 digits max and puts - * unit suffixes at the end. Makes output compact and easy to read, - * especially on huge disks. - * - */ -unit_t -unit_adjust(off_t *val) -{ - double abval; - unit_t unit; - unsigned int unit_sz; - - abval = fabs((double)*val); - - unit_sz = abval ? ilogb(abval) / 10 : 0; - - if (unit_sz >= UNIT_MAX) { - unit = NONE; - } else { - unit = unitp[unit_sz]; - *val /= (double)vals_base2[unit_sz]; - } + if (f_humanval) { + char buf[5]; - return (unit); + humanize_number(buf, sizeof(buf), (int64_t)bytes, "", + HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); + (void)printf("%5s ", buf); + } else + (void)printf("%*jd ", (u_int)width, bytes); } diff --git a/ls/util.c b/ls/util.c index e74fa61..7f8830a 100644 --- a/ls/util.c +++ b/ls/util.c @@ -1,4 +1,4 @@ -/* +/*- * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -13,10 +13,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 the University of - * California, Berkeley and its contributors. * 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. @@ -39,8 +35,8 @@ static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/2/94"; #endif /* not lint */ #endif -#include -__RCSID("$FreeBSD: src/bin/ls/util.c,v 1.30 2002/06/30 05:13:54 obrien Exp $"); +#include +__FBSDID("$FreeBSD: src/bin/ls/util.c,v 1.38 2005/06/03 11:05:58 dd Exp $"); #include #include @@ -48,25 +44,82 @@ __RCSID("$FreeBSD: src/bin/ls/util.c,v 1.30 2002/06/30 05:13:54 obrien Exp $"); #include #include #include +#include #include #include #include +#include +#include #include "ls.h" #include "extern.h" int +prn_normal(const char *s) +{ + mbstate_t mbs; + wchar_t wc; + int i, n; + size_t clen; + + memset(&mbs, 0, sizeof(mbs)); + n = 0; + while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) { + if (clen == (size_t)-2) { + n += printf("%s", s); + break; + } + if (clen == (size_t)-1) { + memset(&mbs, 0, sizeof(mbs)); + putchar((unsigned char)*s); + s++; + n++; + continue; + } + for (i = 0; i < (int)clen; i++) + putchar((unsigned char)s[i]); + s += clen; + if (iswprint(wc)) + n += wcwidth(wc); + } + return (n); +} + +int prn_printable(const char *s) { - char c; - int n; + mbstate_t mbs; + wchar_t wc; + int i, n; + size_t clen; - for (n = 0; (c = *s) != '\0'; ++s, ++n) - if (isprint((unsigned char)c)) - putchar(c); - else + memset(&mbs, 0, sizeof(mbs)); + n = 0; + while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) { + if (clen == (size_t)-1) { putchar('?'); - return n; + s++; + n++; + memset(&mbs, 0, sizeof(mbs)); + continue; + } + if (clen == (size_t)-2) { + putchar('?'); + n++; + break; + } + if (!iswprint(wc)) { + putchar('?'); + s += clen; + n++; + continue; + } + for (i = 0; i < (int)clen; i++) + putchar((unsigned char)s[i]); + s += clen; + n += wcwidth(wc); + } + return (n); } /* @@ -85,70 +138,83 @@ prn_printable(const char *s) size_t len_octal(const char *s, int len) { - size_t r = 0; + mbstate_t mbs; + wchar_t wc; + size_t clen, r; - while (len--) - if (isprint((unsigned const char)*s++)) r++; else r += 4; - return r; + memset(&mbs, 0, sizeof(mbs)); + r = 0; + while (len != 0 && (clen = mbrtowc(&wc, s, len, &mbs)) != 0) { + if (clen == (size_t)-1) { + r += 4; + s++; + len--; + memset(&mbs, 0, sizeof(mbs)); + continue; + } + if (clen == (size_t)-2) { + r += 4 * len; + break; + } + if (iswprint(wc)) + r++; + else + r += 4 * clen; + s += clen; + } + return (r); } int prn_octal(const char *s) { - unsigned char ch; - int len = 0; + static const char esc[] = "\\\\\"\"\aa\bb\ff\nn\rr\tt\vv"; + const char *p; + mbstate_t mbs; + wchar_t wc; + size_t clen; + unsigned char ch; + int goodchar, i, len, prtlen; - while ((ch = (unsigned char)*s++)) { - if (isprint(ch) && (ch != '\"') && (ch != '\\')) - putchar(ch), len++; - else if (f_octal_escape) { - putchar('\\'); - switch (ch) { - case '\\': - putchar('\\'); - break; - case '\"': - putchar('"'); - break; - case '\a': - putchar('a'); - break; - case '\b': - putchar('b'); - break; - case '\f': - putchar('f'); - break; - case '\n': - putchar('n'); - break; - case '\r': - putchar('r'); - break; - case '\t': - putchar('t'); - break; - case '\v': - putchar('v'); - break; - default: + memset(&mbs, 0, sizeof(mbs)); + len = 0; + while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) { + goodchar = clen != (size_t)-1 && clen != (size_t)-2; + if (goodchar && iswprint(wc) && wc != L'\"' && wc != L'\\') { + for (i = 0; i < (int)clen; i++) + putchar((unsigned char)s[i]); + len += wcwidth(wc); + } else if (goodchar && f_octal_escape && wc >= 0 && + wc <= (wchar_t)UCHAR_MAX && + (p = strchr(esc, (char)wc)) != NULL) { + putchar('\\'); + putchar(p[1]); + len += 2; + } else { + if (goodchar) + prtlen = clen; + else if (clen == (size_t)-1) + prtlen = 1; + else + prtlen = strlen(s); + for (i = 0; i < prtlen; i++) { + ch = (unsigned char)s[i]; + putchar('\\'); putchar('0' + (ch >> 6)); putchar('0' + ((ch >> 3) & 7)); putchar('0' + (ch & 7)); - len += 2; - break; - } - len += 2; - } - else { - putchar('\\'); - putchar('0' + (ch >> 6)); - putchar('0' + ((ch >> 3) & 7)); - putchar('0' + (ch & 7)); - len += 4; + len += 4; + } } + if (clen == (size_t)-2) + break; + if (clen == (size_t)-1) { + memset(&mbs, 0, sizeof(mbs)); + s++; + } else + s += clen; } - return len; + return (len); } void @@ -156,9 +222,9 @@ usage(void) { (void)fprintf(stderr, #ifdef COLORLS - "usage: ls [-ABCFGHLPRSTWZabcdefghiklmnopqrstuwx1]" + "usage: ls [-ABCFGHLPRSTWabcdefghiklmnopqrstuwx1]" #else - "usage: ls [-ABCFHLPRSTWZabcdefghiklmnopqrstuwx1]" + "usage: ls [-ABCFHLPRSTWabcdefghiklmnopqrstuwx1]" #endif " [file ...]\n"); exit(1); diff --git a/mkdir/mkdir.c b/mkdir/mkdir.c index 1bb430d..e76e92b 100644 --- a/mkdir/mkdir.c +++ b/mkdir/mkdir.c @@ -113,7 +113,7 @@ main(int argc, char *argv[]) warn("%s", *argv); success = 0; } else if (vflag) - (void)printf("%s\n", *argv); + (void)printf("mkdir: created directory '%s'\n", *argv); if (!success) exitval = 1; diff --git a/mkfifo/mkfifo.1 b/mkfifo/mkfifo.1 index f8a0e16..1656503 100644 --- a/mkfifo/mkfifo.1 +++ b/mkfifo/mkfifo.1 @@ -43,22 +43,25 @@ .Nm mkfifo .Nd make fifos .Sh SYNOPSIS -.Nm +.Nm mkfifo .Op Fl m Ar mode .Ar fifo_name ... .Sh DESCRIPTION -.Nm -creates the fifos requested, in the order specified, -using mode -.Li \&0666 -modified by the current +.Nm mkfifo +creates the fifos requested, in the order specified. +By default, +the resulting fifos have mode +.Li \&0666 +(rw-rw-rw-), limited by the current .Xr umask 2 . .Pp The options are as follows: .Bl -tag -width Ds .It Fl m -Set the file permission bits of newly-created directories to -.Ar mode . +Set the file permission bits of newly-created fifos to +.Ar mode , +without respect to the current umask. +.Pp The mode is specified as in .Xr chmod 1 . In symbolic mode strings, the @@ -69,23 +72,29 @@ operators are interpreted relative to an assumed initial mode of .Dq a=rw .El .Pp -.Nm +.Nm mkfifo requires write permission in the parent directory. .Pp -.Nm -exits 0 if successful, and >0 if an error occurred. +.Nm mkfifo +exits with 0 if successful, and with >0 if an error occurred. +.Sh LEGACY DESCRIPTION +In legacy mode, the fifo's file permission bits +are always limited by the current umask. .Sh SEE ALSO .Xr mkdir 1 , .Xr rm 1 , +.Xr umask 1 , .Xr mkfifo 2 , +.Xr umask 2 , +.Xr compat 5 , .Xr mknod 8 .Sh STANDARDS The -.Nm +.Nm mkfifo utility is expected to be .St -p1003.2-92 compliant. .Sh HISTORY -.Nm +.Nm mkfifo command appeared in .Bx 4.4 . diff --git a/mkfifo/mkfifo.c b/mkfifo/mkfifo.c index 6bd45b0..0abbd70 100644 --- a/mkfifo/mkfifo.c +++ b/mkfifo/mkfifo.c @@ -55,6 +55,11 @@ __RCSID("$NetBSD: mkfifo.c,v 1.8 1997/10/19 05:11:54 lukem Exp $"); #include #include #include +#ifdef __APPLE__ +#include +#else +#define COMPAT_MODE(a,b) (1) +#endif /* __APPLE__ */ int main __P((int, char **)); static void usage __P((void)); @@ -67,17 +72,21 @@ main(argc, argv) int ch, exitval; void * set; mode_t mode; + int m_used = 0; setlocale (LC_ALL, ""); /* The default mode is the value of the bitwise inclusive or of S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, and S_IWOTH modified by the file creation mask */ - mode = 0666 & ~umask(0); + if (!COMPAT_MODE("bin/mkfifo", "Unix2003")) { + mode = 0666 & ~umask(0); + } while ((ch = getopt(argc, argv, "m:")) != -1) switch(ch) { case 'm': + m_used = 1; if (!(set = setmode(optarg))) { errx(1, "invalid file mode."); /* NOTREACHED */ @@ -96,6 +105,12 @@ main(argc, argv) if (argv[0] == NULL) usage(); + if (COMPAT_MODE("bin/mkfifo", "Unix2003")) { + mode_t maskbits = umask(0); /* now must disable umask so -m mode won't be masked again */ + if (!m_used) + mode = 0666 & ~maskbits; + } + for (exitval = 0; *argv; ++argv) { if (mkfifo(*argv, mode) < 0) { warn("%s", *argv); diff --git a/mknod/mknod.8 b/mknod/mknod.8 index d68dab1..9e5e9eb 100644 --- a/mknod/mknod.8 +++ b/mknod/mknod.8 @@ -54,6 +54,9 @@ .Ar name .Op Cm c | Cm b .Ar number +.Nm +.Ar name +.Ar w .Sh DESCRIPTION The .Nm @@ -74,12 +77,14 @@ Device name, for example for a SCSI disk on an HP300 or a .Dq pty for pseudo-devices. -.It Cm b | Cm c +.It Cm b | Cm c | Cm w Type of device. If the device is a block type device such as a tape or disk drive which needs both cooked and raw special files, the type is .Cm b . +Whiteout nodes are type +.Cm w . All other devices are character type devices, such as terminal and pseudo devices, and are type .Cm c . diff --git a/mknod/mknod.c b/mknod/mknod.c index 884b8e5..0f08005 100644 --- a/mknod/mknod.c +++ b/mknod/mknod.c @@ -348,7 +348,7 @@ main(argc, argv) argc -= optind; argv += optind; - if (argc < 3 || argc > 10) + if (argc < 2 || argc > 10) usage(); name = *argv; @@ -360,18 +360,25 @@ main(argc, argv) mode |= S_IFCHR; else if (*argv[0] == 'b') mode |= S_IFBLK; + else if (*argv[0] == 'w') + mode |= S_IFWHT; else - errx(1, "node type must be 'b' or 'c'."); + errx(1, "node type must be 'b' or 'c' or 'w'."); argc--; argv++; for (n = 0; n < argc; n++) { + if (S_ISWHT(mode)) { + errx(1, "whiteout nodes have no device numbers."); + } numbers[n] = strtoul(argv[n], &p, 0); if ((p && *p != '\0') || (numbers[n] == ULONG_MAX && errno == ERANGE)) errx(1, "invalid number: %s", argv[n]); } - if (argc == 1) + if (S_ISWHT(mode)) + dev = 0; + else if (argc == 1) dev = numbers[0]; else dev = (*pack)(argc, numbers); @@ -393,5 +400,6 @@ usage() fprintf(stderr, "usage: mknod [-F format] name [b | c] major minor\n"); fprintf(stderr, " mknod [-F format] name [b | c] major unit subunit\n"); fprintf(stderr, " mknod name [b | c] number\n"); + fprintf(stderr, " mknod name w\n"); exit(1); } diff --git a/mtree/Makefile b/mtree/Makefile index 6917e8f..dbee24e 100644 --- a/mtree/Makefile +++ b/mtree/Makefile @@ -14,16 +14,17 @@ PROJECT_TYPE = Tool HFILES = extern.h mtree.h -CFILES = compare.c create.c excludes.c misc.c mtree.c spec.c verify.c +CFILES = compare.c create.c excludes.c misc.c mtree.c spec.c specspec.c verify.c OTHERSRCS = Makefile Makefile.preamble Makefile.postamble mtree.8 +OTHER_CFLAGS = -D__FBSDID=__RCSID -DENABLE_MD5 -DENABLE_RMD160 -DENABLE_SHA1 MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC MAKEFILE = tool.make NEXTSTEP_INSTALLDIR = /usr/sbin -LIBS = +LIBS = -lmd -lcrypto DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) diff --git a/mtree/compare.c b/mtree/compare.c index 8f9591d..69cad5f 100644 --- a/mtree/compare.c +++ b/mtree/compare.c @@ -10,11 +10,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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,40 +27,43 @@ * SUCH DAMAGE. */ -#ifndef lint #if 0 +#ifndef lint static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93"; -#endif -static const char rcsid[] = - "$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.15.2.3 2001/01/12 19:17:18 phk Exp $"; #endif /* not lint */ +#endif +#include +__FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobez Exp $"); #include #include +#include + #include #include #include #include -#ifdef MD5 +#ifdef ENABLE_MD5 #include #endif -#ifdef SHA1 +#ifdef ENABLE_RMD160 +#include +#endif +#ifdef ENABLE_SHA1 #include #endif -#ifdef RMD160 -#include +#ifdef ENABLE_SHA256 +#include #endif +#include #include #include #include +#include + #include "mtree.h" #include "extern.h" -extern int uflag; -extern int lineno; - -static char *ftype __P((u_int)); - #define INDENTNAMELEN 8 #define LABEL \ if (!label++) { \ @@ -73,15 +72,14 @@ static char *ftype __P((u_int)); } int -compare(name, s, p) - char *name; - register NODE *s; - register FTSENT *p; +compare(char *name __unused, NODE *s, FTSENT *p) { - extern int uflag; - u_long len, val; + struct timeval tv[2]; + uint32_t val; int fd, label; - char *cp, *tab = ""; + off_t len; + char *cp; + const char *tab = ""; char *fflags; label = 0; @@ -174,8 +172,8 @@ typeerr: LABEL; if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size && !S_ISDIR(p->fts_statp->st_mode)) { LABEL; - (void)printf("%ssize expected %qd found %qd\n", - tab, s->st_size, p->fts_statp->st_size); + (void)printf("%ssize expected %jd found %jd\n", tab, + (intmax_t)s->st_size, (intmax_t)p->fts_statp->st_size); tab = "\t"; } /* @@ -188,8 +186,19 @@ typeerr: LABEL; LABEL; (void)printf("%smodification time expected %.24s ", tab, ctime(&s->st_mtimespec.tv_sec)); - (void)printf("found %.24s\n", + (void)printf("found %.24s", ctime(&p->fts_statp->st_mtimespec.tv_sec)); + if (uflag) { + tv[0].tv_sec = s->st_mtimespec.tv_sec; + tv[0].tv_usec = s->st_mtimespec.tv_nsec / 1000; + tv[1] = tv[0]; + if (utimes(p->fts_accpath, tv)) + (void)printf(" not modified: %s\n", + strerror(errno)); + else + (void)printf(" modified\n"); + } else + (void)printf("\n"); tab = "\t"; } if (s->flags & F_CKSUM) { @@ -209,17 +218,11 @@ typeerr: LABEL; if (s->cksum != val) { LABEL; (void)printf("%scksum expected %lu found %lu\n", - tab, s->cksum, val); + tab, s->cksum, (unsigned long)val); + tab = "\t"; } - tab = "\t"; } } - /* - * XXX - * since chflags(2) will reset file times, the utimes() above - * may have been useless! oh well, we'd rather have correct - * flags, rather than times? - */ if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) { LABEL; fflags = flags_to_string(s->st_flags); @@ -240,7 +243,7 @@ typeerr: LABEL; (void)printf("\n"); tab = "\t"; } -#ifdef MD5 +#ifdef ENABLE_MD5 if (s->flags & F_MD5) { char *new_digest, buf[33]; @@ -257,8 +260,8 @@ typeerr: LABEL; tab = "\t"; } } -#endif /* MD5 */ -#ifdef SHA1 +#endif /* ENABLE_MD5 */ +#ifdef ENABLE_SHA1 if (s->flags & F_SHA1) { char *new_digest, buf[41]; @@ -270,13 +273,13 @@ typeerr: LABEL; tab = "\t"; } else if (strcmp(new_digest, s->sha1digest)) { LABEL; - printf("%sSHA-1 expected %s found %s\n", + printf("%sSHA-1 expected %s found %s\n", tab, s->sha1digest, new_digest); tab = "\t"; } } -#endif /* SHA1 */ -#ifdef RMD160 +#endif /* ENABLE_SHA1 */ +#ifdef ENABLE_RMD160 if (s->flags & F_RMD160) { char *new_digest, buf[41]; @@ -293,20 +296,37 @@ typeerr: LABEL; tab = "\t"; } } -#endif /* RMD160 */ +#endif /* ENABLE_RMD160 */ +#ifdef ENABLE_SHA256 + if (s->flags & F_SHA256) { + char *new_digest, buf[65]; + + new_digest = SHA256_File(p->fts_accpath, buf); + if (!new_digest) { + LABEL; + printf("%sSHA-256: %s: %s\n", tab, p->fts_accpath, + strerror(errno)); + tab = "\t"; + } else if (strcmp(new_digest, s->sha256digest)) { + LABEL; + printf("%sSHA-256 expected %s found %s\n", + tab, s->sha256digest, new_digest); + tab = "\t"; + } + } +#endif /* ENABLE_SHA256 */ if (s->flags & F_SLINK && strcmp(cp = rlink(p->fts_accpath), s->slink)) { LABEL; (void)printf("%slink_ref expected %s found %s\n", - tab, cp, s->slink); + tab, s->slink, cp); } return (label); } -char * -inotype(type) - u_int type; +const char * +inotype(u_int type) { switch(type & S_IFMT) { case S_IFBLK: @@ -329,9 +349,8 @@ inotype(type) /* NOTREACHED */ } -static char * -ftype(type) - u_int type; +const char * +ftype(u_int type) { switch(type) { case F_BLOCK: @@ -355,14 +374,15 @@ ftype(type) } char * -rlink(name) - char *name; +rlink(char *name) { - static char lbuf[MAXPATHLEN]; - register int len; + static char lbuf[MAXPATHLEN * 4]; + int len; + char tbuf[MAXPATHLEN]; - if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1) + if ((len = readlink(name, tbuf, sizeof(tbuf) - 1)) == -1) err(1, "line %d: %s", lineno, name); - lbuf[len] = '\0'; + tbuf[len] = '\0'; + strvis(lbuf, tbuf, VIS_WHITE | VIS_OCTAL); return (lbuf); } diff --git a/mtree/create.c b/mtree/create.c index f755acc..8860955 100644 --- a/mtree/create.c +++ b/mtree/create.c @@ -10,11 +10,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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,13 +27,13 @@ * SUCH DAMAGE. */ -#ifndef lint #if 0 +#ifndef lint static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93"; -#endif -static const char rcsid[] = - "$FreeBSD: src/usr.sbin/mtree/create.c,v 1.18.2.3 2001/01/12 19:17:18 phk Exp $"; #endif /* not lint */ +#endif +#include +__FBSDID("$FreeBSD: src/usr.sbin/mtree/create.c,v 1.37 2005/03/29 11:44:17 tobez Exp $"); #include #include @@ -47,16 +43,20 @@ static const char rcsid[] = #include #include #include -#ifdef MD5 +#ifdef ENABLE_MD5 #include #endif -#ifdef SHA1 +#ifdef ENABLE_SHA1 #include #endif -#ifdef RMD160 +#ifdef ENABLE_RMD160 #include #endif +#ifdef ENABLE_SHA256 +#include +#endif #include +#include #include #include #include @@ -67,43 +67,41 @@ static const char rcsid[] = #define INDENTNAMELEN 15 #define MAXLINELEN 80 -extern long int crc_total; -extern int ftsoptions; -extern int dflag, iflag, nflag, sflag; -extern u_int keys; -extern char fullpath[MAXPATHLEN]; -extern int lineno; - static gid_t gid; static uid_t uid; static mode_t mode; static u_long flags = 0xffffffff; -static int dsort __P((const FTSENT **, const FTSENT **)); -static void output __P((int, int *, const char *, ...)); -static int statd __P((FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, - u_long *)); -static void statf __P((int, FTSENT *)); +static int dsort(const FTSENT * const *, const FTSENT * const *); +static void output(int, int *, const char *, ...) __printflike(3, 4); +static int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *); +static void statf(int, FTSENT *); void -cwalk() +cwalk(void) { - register FTS *t; - register FTSENT *p; - time_t clock; + FTS *t; + FTSENT *p; + time_t cl; char *argv[2], host[MAXHOSTNAMELEN]; + char dot[] = "."; int indent = 0; - (void)time(&clock); - (void)gethostname(host, sizeof(host)); - (void)printf( - "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n#\t date: %s", - getlogin(), host, fullpath, ctime(&clock)); + if (!nflag) { + (void)time(&cl); + (void)gethostname(host, sizeof(host)); + (void)printf( + "#\t user: %s\n#\tmachine: %s\n", + getlogin(), host); + (void)printf( + "#\t tree: %s\n#\t date: %s", + fullpath, ctime(&cl)); + } - argv[0] = "."; + argv[0] = dot; argv[1] = NULL; if ((t = fts_open(argv, ftsoptions, dsort)) == NULL) - err(1, "line %d: fts_open", lineno); + err(1, "fts_open()"); while ((p = fts_read(t))) { if (iflag) indent = p->fts_level * 4; @@ -141,17 +139,16 @@ cwalk() } (void)fts_close(t); if (sflag && keys & F_CKSUM) - warnx("%s checksum: %lu", fullpath, crc_total); + warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total); } static void -statf(indent, p) - int indent; - FTSENT *p; +statf(int indent, FTSENT *p) { struct group *gr; struct passwd *pw; - u_long len, val; + uint32_t val; + off_t len; int fd, offset; char *fflags; char *escaped_name; @@ -159,13 +156,13 @@ statf(indent, p) escaped_name = calloc(1, p->fts_namelen * 4 + 1); if (escaped_name == NULL) errx(1, "statf(): calloc() failed"); - strvis(escaped_name, p->fts_name, VIS_WHITE | VIS_OCTAL); + strvis(escaped_name, p->fts_name, VIS_WHITE | VIS_OCTAL | VIS_GLOB); if (iflag || S_ISDIR(p->fts_statp->st_mode)) offset = printf("%*s%s", indent, "", escaped_name); else offset = printf("%*s %s", indent, "", escaped_name); - + free(escaped_name); if (offset > (INDENTNAMELEN + indent)) @@ -177,26 +174,32 @@ statf(indent, p) output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode)); if (p->fts_statp->st_uid != uid) { if (keys & F_UNAME) { - if ((pw = getpwuid(p->fts_statp->st_uid)) != NULL) { + pw = getpwuid(p->fts_statp->st_uid); + if (pw != NULL) output(indent, &offset, "uname=%s", pw->pw_name); - } else { + else if (wflag) + warnx("Could not get uname for uid=%u", + p->fts_statp->st_uid); + else errx(1, - "line %d: could not get uname for uid=%u", - lineno, p->fts_statp->st_uid); - } + "Could not get uname for uid=%u", + p->fts_statp->st_uid); } if (keys & F_UID) output(indent, &offset, "uid=%u", p->fts_statp->st_uid); } if (p->fts_statp->st_gid != gid) { if (keys & F_GNAME) { - if ((gr = getgrgid(p->fts_statp->st_gid)) != NULL) { + gr = getgrgid(p->fts_statp->st_gid); + if (gr != NULL) output(indent, &offset, "gname=%s", gr->gr_name); - } else { + else if (wflag) + warnx("Could not get gname for gid=%u", + p->fts_statp->st_gid); + else errx(1, - "line %d: could not get gname for gid=%u", - lineno, p->fts_statp->st_gid); - } + "Could not get gname for gid=%u", + p->fts_statp->st_gid); } if (keys & F_GID) output(indent, &offset, "gid=%u", p->fts_statp->st_gid); @@ -206,54 +209,59 @@ statf(indent, p) if (keys & F_NLINK && p->fts_statp->st_nlink != 1) output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink); if (keys & F_SIZE) - output(indent, &offset, "size=%qd", p->fts_statp->st_size); + output(indent, &offset, "size=%jd", + (intmax_t)p->fts_statp->st_size); if (keys & F_TIME) output(indent, &offset, "time=%ld.%ld", - p->fts_statp->st_mtimespec.tv_sec, + (long)p->fts_statp->st_mtimespec.tv_sec, p->fts_statp->st_mtimespec.tv_nsec); if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 || crc(fd, &val, &len)) - err(1, "line %d: %s", lineno, p->fts_accpath); + err(1, "%s", p->fts_accpath); (void)close(fd); - output(indent, &offset, "cksum=%lu", val); + output(indent, &offset, "cksum=%lu", (unsigned long)val); } -#ifdef MD5 +#ifdef ENABLE_MD5 if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { char *digest, buf[33]; digest = MD5File(p->fts_accpath, buf); - if (!digest) { - err(1, "line %d: %s", lineno, p->fts_accpath); - } else { - output(indent, &offset, "md5digest=%s", digest); - } + if (!digest) + err(1, "%s", p->fts_accpath); + output(indent, &offset, "md5digest=%s", digest); } -#endif /* MD5 */ -#ifdef SHA1 +#endif /* ENABLE_MD5 */ +#ifdef ENABLE_SHA1 if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) { char *digest, buf[41]; digest = SHA1_File(p->fts_accpath, buf); - if (!digest) { - err(1, "line %d: %s", lineno, p->fts_accpath); - } else { - output(indent, &offset, "sha1digest=%s", digest); - } + if (!digest) + err(1, "%s", p->fts_accpath); + output(indent, &offset, "sha1digest=%s", digest); } -#endif /* SHA1 */ -#ifdef RMD160 +#endif /* ENABLE_SHA1 */ +#ifdef ENABLE_RMD160 if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) { char *digest, buf[41]; digest = RIPEMD160_File(p->fts_accpath, buf); - if (!digest) { - err(1, "line %d: %s", lineno, p->fts_accpath); - } else { - output(indent, &offset, "ripemd160digest=%s", digest); - } + if (!digest) + err(1, "%s", p->fts_accpath); + output(indent, &offset, "ripemd160digest=%s", digest); } -#endif /* RMD160 */ +#endif /* ENABLE_RMD160 */ +#ifdef ENABLE_SHA256 + if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) { + char *digest, buf[65]; + + digest = SHA256_File(p->fts_accpath, buf); + if (!digest) + err(1, "%s", p->fts_accpath); + output(indent, &offset, "sha256digest=%s", digest); + } +#endif /* ENABLE_SHA256 */ if (keys & F_SLINK && (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) output(indent, &offset, "link=%s", rlink(p->fts_accpath)); @@ -272,19 +280,13 @@ statf(indent, p) #define MAXS 16 static int -statd(t, parent, puid, pgid, pmode, pflags) - FTS *t; - FTSENT *parent; - uid_t *puid; - gid_t *pgid; - mode_t *pmode; - u_long *pflags; +statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags) { - register FTSENT *p; - register gid_t sgid; - register uid_t suid; - register mode_t smode; - register u_long sflags; + FTSENT *p; + gid_t sgid; + uid_t suid; + mode_t smode; + u_long sflags; struct group *gr; struct passwd *pw; gid_t savegid = *pgid; @@ -298,7 +300,7 @@ statd(t, parent, puid, pgid, pmode, pflags) if ((p = fts_children(t, 0)) == NULL) { if (errno) - err(1, "line %d: %s", lineno, RP(parent)); + err(1, "%s", RP(parent)); return (1); } @@ -348,7 +350,7 @@ statd(t, parent, puid, pgid, pmode, pflags) */ if ((((keys & F_UNAME) | (keys & F_UID)) && (*puid != saveuid)) || (((keys & F_GNAME) | (keys & F_GID)) && (*pgid != savegid)) || - ((keys & F_MODE) && (*pmode != savemode)) || + ((keys & F_MODE) && (*pmode != savemode)) || ((keys & F_FLAGS) && (*pflags != saveflags)) || (first)) { first = 0; @@ -357,22 +359,24 @@ statd(t, parent, puid, pgid, pmode, pflags) else (void)printf("/set type=file"); if (keys & F_UNAME) { - if ((pw = getpwuid(saveuid)) != NULL) + pw = getpwuid(saveuid); + if (pw != NULL) (void)printf(" uname=%s", pw->pw_name); + else if (wflag) + warnx( "Could not get uname for uid=%u", saveuid); else - errx(1, - "line %d: could not get uname for uid=%u", - lineno, saveuid); + errx(1, "Could not get uname for uid=%u", saveuid); } if (keys & F_UID) (void)printf(" uid=%lu", (u_long)saveuid); if (keys & F_GNAME) { - if ((gr = getgrgid(savegid)) != NULL) + gr = getgrgid(savegid); + if (gr != NULL) (void)printf(" gname=%s", gr->gr_name); + else if (wflag) + warnx("Could not get gname for gid=%u", savegid); else - errx(1, - "line %d: could not get gname for gid=%u", - lineno, savegid); + errx(1, "Could not get gname for gid=%u", savegid); } if (keys & F_GID) (void)printf(" gid=%lu", (u_long)savegid); @@ -395,8 +399,7 @@ statd(t, parent, puid, pgid, pmode, pflags) } static int -dsort(a, b) - const FTSENT **a, **b; +dsort(const FTSENT * const *a, const FTSENT * const *b) { if (S_ISDIR((*a)->fts_statp->st_mode)) { if (!S_ISDIR((*b)->fts_statp->st_mode)) @@ -406,30 +409,14 @@ dsort(a, b) return (strcmp((*a)->fts_name, (*b)->fts_name)); } -#if __STDC__ #include -#else -#include -#endif void -#if __STDC__ output(int indent, int *offset, const char *fmt, ...) -#else -output(indent, offset, fmt, va_alist) - int indent; - int *offset; - char *fmt; - va_dcl -#endif { va_list ap; char buf[1024]; -#if __STDC__ va_start(ap, fmt); -#else - va_start(ap); -#endif (void)vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); diff --git a/mtree/excludes.c b/mtree/excludes.c index afdb6e4..8904771 100644 --- a/mtree/excludes.c +++ b/mtree/excludes.c @@ -12,7 +12,7 @@ * no representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied * warranty. - * + * * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF @@ -27,8 +27,8 @@ * SUCH DAMAGE. */ -static const char rcsid[] = - "$FreeBSD: src/usr.sbin/mtree/excludes.c,v 1.1.2.4 2001/01/12 19:17:18 phk Exp $"; +#include +__FBSDID("$FreeBSD: src/usr.sbin/mtree/excludes.c,v 1.8 2003/10/21 08:27:05 phk Exp $"); #include #include /* XXX for mtree.h */ @@ -38,13 +38,14 @@ static const char rcsid[] = #include #include #include +#include #include #include "mtree.h" /* XXX for extern.h */ #include "extern.h" /* - * We're assuming that there won't be a whole lot of excludes, + * We're assuming that there won't be a whole lot of excludes, * so it's OK to use a stupid algorithm. */ struct exclude { @@ -103,7 +104,7 @@ check_excludes(const char *fname, const char *path) #define MATCH(g, n) (fnmatch((g), (n), FNM_PATHNAME) == 0) LIST_FOREACH(e, &excludes, link) { - if (e->pathname && MATCH(e->glob, path) + if ((e->pathname && MATCH(e->glob, path)) || MATCH(e->glob, fname)) return 1; } diff --git a/mtree/extern.h b/mtree/extern.h index c91086a..4c7adb2 100644 --- a/mtree/extern.h +++ b/mtree/extern.h @@ -10,11 +10,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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,20 +27,33 @@ * SUCH DAMAGE. * * @(#)extern.h 8.1 (Berkeley) 6/6/93 - * $FreeBSD: src/usr.sbin/mtree/extern.h,v 1.3.2.2 2000/06/28 02:33:17 joe Exp $ + * $FreeBSD: src/usr.sbin/mtree/extern.h,v 1.13 2004/01/11 19:38:48 phk Exp $ */ +extern uint32_t crc_total; -int compare __P((char *, NODE *, FTSENT *)); -int crc __P((int, u_long *, u_long *)); -void cwalk __P((void)); -char *flags_to_string __P((u_long)); +#ifdef _FTS_H_ +int compare(char *, NODE *, FTSENT *); +#endif +int crc(int, uint32_t *, off_t *); +void cwalk(void); +char *flags_to_string(u_long); -char *inotype __P((u_int)); -u_int parsekey __P((char *, int *)); -char *rlink __P((char *)); -NODE *spec __P((void)); -int verify __P((void)); +const char *inotype(u_int); +u_int parsekey(char *, int *); +char *rlink(char *); +NODE *mtree_readspec(FILE *fi); +int mtree_verifyspec(FILE *fi); +int mtree_specspec(FILE *fi, FILE *fj); -int check_excludes __P((const char *, const char *)); -void init_excludes __P((void)); -void read_excludes_file __P((const char *)); +int check_excludes(const char *, const char *); +void init_excludes(void); +void read_excludes_file(const char *); +const char * ftype(u_int type); + +extern int ftsoptions; +extern u_int keys; +extern int lineno; +extern int dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, wflag; +#ifdef MAXPATHLEN +extern char fullpath[MAXPATHLEN]; +#endif diff --git a/mtree/misc.c b/mtree/misc.c index b26bda3..4cf852f 100644 --- a/mtree/misc.c +++ b/mtree/misc.c @@ -10,11 +10,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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,27 +27,26 @@ * SUCH DAMAGE. */ -#ifndef lint #if 0 +#ifndef lint static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93"; -#endif -static const char rcsid[] = - "$FreeBSD: src/usr.sbin/mtree/misc.c,v 1.8.2.1 2000/06/28 02:33:17 joe Exp $"; #endif /*not lint */ +#endif +#include +__FBSDID("$FreeBSD: src/usr.sbin/mtree/misc.c,v 1.16 2005/03/29 11:44:17 tobez Exp $"); #include #include #include #include +#include #include #include #include "mtree.h" #include "extern.h" -extern int lineno; - typedef struct _key { - char *name; /* key name */ + const char *name; /* key name */ u_int val; /* value */ #define NEEDVALUE 0x01 @@ -66,18 +61,21 @@ static KEY keylist[] = { {"gname", F_GNAME, NEEDVALUE}, {"ignore", F_IGN, 0}, {"link", F_SLINK, NEEDVALUE}, -#ifdef MD5 +#ifdef ENABLE_MD5 {"md5digest", F_MD5, NEEDVALUE}, #endif {"mode", F_MODE, NEEDVALUE}, {"nlink", F_NLINK, NEEDVALUE}, {"nochange", F_NOCHANGE, 0}, -#ifdef RMD160 +#ifdef ENABLE_RMD160 {"ripemd160digest", F_RMD160, NEEDVALUE}, #endif -#ifdef SHA1 +#ifdef ENABLE_SHA1 {"sha1digest", F_SHA1, NEEDVALUE}, #endif +#ifdef ENABLE_SHA256 + {"sha256digest", F_SHA256, NEEDVALUE}, +#endif {"size", F_SIZE, NEEDVALUE}, {"time", F_TIME, NEEDVALUE}, {"type", F_TYPE, NEEDVALUE}, @@ -85,13 +83,12 @@ static KEY keylist[] = { {"uname", F_UNAME, NEEDVALUE}, }; +int keycompare(const void *, const void *); + u_int -parsekey(name, needvaluep) - char *name; - int *needvaluep; +parsekey(char *name, int *needvaluep) { KEY *k, tmp; - int keycompare __P((const void *, const void *)); tmp.name = name; k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY), @@ -105,15 +102,13 @@ parsekey(name, needvaluep) } int -keycompare(a, b) - const void *a, *b; +keycompare(const void *a, const void *b) { - return (strcmp(((KEY *)a)->name, ((KEY *)b)->name)); + return (strcmp(((const KEY *)a)->name, ((const KEY *)b)->name)); } char * -flags_to_string(fflags) - u_long fflags; +flags_to_string(u_long fflags) { char *string; diff --git a/mtree/mtree.8 b/mtree/mtree.8 index 8b4cb26..72536d3 100644 --- a/mtree/mtree.8 +++ b/mtree/mtree.8 @@ -9,10 +9,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 the University of -.\" California, Berkeley and its contributors. .\" 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. @@ -30,17 +26,20 @@ .\" SUCH DAMAGE. .\" .\" From: @(#)mtree.8 8.2 (Berkeley) 12/11/93 -.\" $FreeBSD: src/usr.sbin/mtree/mtree.8,v 1.16.2.9 2001/08/16 15:56:08 ru Exp $ +.\" $FreeBSD: src/usr.sbin/mtree/mtree.8,v 1.53 2005/07/31 03:30:47 keramida Exp $ .\" -.Dd February 26, 1999 +.Dd March 29, 2005 .Dt MTREE 8 .Os .Sh NAME .Nm mtree .Nd map a directory hierarchy .Sh SYNOPSIS -.Nm -.Op Fl LPUcdeinqrux +.Nm mtree +.Op Fl LPUcdeinqruxw +.Bk -words +.Op Fl f Ar spec +.Ek .Bk -words .Op Fl f Ar spec .Ek @@ -60,9 +59,9 @@ .Op Fl X Ar exclude-list .Ek .Sh DESCRIPTION -The utility -.Nm -compares the file hierarchy rooted in the current directory against a +The +.Nm mtree +utility compares the file hierarchy rooted in the current directory against a specification read from the standard input. Messages are written to the standard output for any files whose characteristics do not match the specifications, or which are @@ -70,24 +69,34 @@ missing from either the file hierarchy or the specification. .Pp The options are as follows: .Bl -tag -width flag -.It Fl L -Follow all symbolic links in the file hierarchy. -.It Fl P -Don't follow symbolic links in the file hierarchy, instead consider -the symbolic link itself in any comparisons. This is the default. -.It Fl U -Modify the owner, group and permissions of existing files to match -the specification and create any missing directories or symbolic links. -User, group and permissions must all be specified for missing directories -to be created. -Corrected mismatches are not considered errors. +.\" ========== .It Fl c Print a specification for the file hierarchy to the standard output. +.\" ========== .It Fl d Ignore everything except directory type files. +.\" ========== .It Fl e -Don't complain about files that are in the file hierarchy, but not in the +Do not complain about files that are in the file hierarchy, but not in the specification. +.\" ========== +.It Fl f Ar file +Read the specification from +.Ar file , +instead of from the standard input. +.Pp +If this option is specified twice, +the two specifications are compared with each other, +rather than to the file hierarchy. +The specifications be sorted like output generated using +.Fl c . +The output format in this case is somewhat remniscent of +.Xr comm 1 , +having "in first spec only", "in second spec only", and "different" +columns, prefixed by zero, one and two TAB characters respectively. +Each entry in the "different" column occupies two lines, +one from each specification. +.\" ========== .It Fl i Indent the output 4 spaces each time a directory level is descended when create a specification with the @@ -96,49 +105,73 @@ option. This does not affect either the /set statements or the comment before each directory. It does however affect the comment before the close of each directory. -.It Fl n -Do not emit pathname comments when creating a specification. Normally -a comment is emitted before each directory and before the close of that -directory when using the -.Fl c -option. -.It Fl q -Quiet mode. Do not complain when a -.Dq missing -directory cannot be created because it is already exists. -This occurs when the directory is a symbolic link. -.It Fl r -Remove any files in the file hierarchy that are not described in the -specification. -.It Fl u -Same as -.Fl U -except a status of 2 is returned if the file hierarchy did not match -the specification. -.It Fl x -Don't descend below mount points in the file hierarchy. -.It Fl f Ar file -Read the specification from -.Ar file , -instead of from the standard input. +.\" ========== .It Fl K Ar keywords Add the specified (whitespace or comma separated) .Ar keywords to the current set of keywords. +.\" ========== .It Fl k Ar keywords Use the ``type'' keyword plus the specified (whitespace or comma separated) .Ar keywords instead of the current set of keywords. +.\" ========== +.It Fl L +Follow all symbolic links in the file hierarchy. +.\" ========== +.It Fl n +Do not emit pathname comments when creating a specification. +Normally +a comment is emitted before each directory and before the close of that +directory when using the +.Fl c +option. +.\" ========== +.It Fl P +Do not follow symbolic links in the file hierarchy, instead consider +the symbolic link itself in any comparisons. +This is the default. +.\" ========== .It Fl p Ar path Use the file hierarchy rooted in -.Ar path , +.Ar path , instead of the current directory. +.\" ========== +.It Fl q +Quiet mode. +Do not complain when a +.Dq missing +directory cannot be created because it already exists. +This occurs when the directory is a symbolic link. +.\" ========== +.It Fl r +Remove any files in the file hierarchy that are not described in the +specification. +.\" ========== .It Fl s Ar seed Display a single checksum to the standard error output that represents all of the files for which the keyword .Cm cksum was specified. The checksum is seeded with the specified value. +.\" ========== +.It Fl U +Modify the owner, group, permissions, and modification time of existing +files to match the specification and create any missing directories or +symbolic links. +User, group and permissions must all be specified for missing directories +to be created. +Corrected mismatches are not considered errors. +.\" ========== +.It Fl u +Same as +.Fl U +except a status of 2 is returned if the file hierarchy did not match +the specification. +.\" ========== +.It Fl w +Make some error conditions non-fatal warnings. +.\" ========== .It Fl X Ar exclude-list The specified file contains .Xr fnmatch 3 @@ -148,13 +181,17 @@ If the pattern contains a .Ql \&/ character, it will be matched against entire pathnames (relative to the starting directory); otherwise, -it will be matched against basenames only. No comments are allowed in +it will be matched against basenames only. +No comments are allowed in the .Ar exclude-list file. +.\" ========== +.It Fl x +Do not descend below mount points in the file hierarchy. .El .Pp -Specifications are mostly composed of ``keywords'', i.e. strings that +Specifications are mostly composed of ``keywords'', i.e., strings that specify values relating to files. No keywords have default values, and if a keyword has no value set, no checks based on it are performed. @@ -167,9 +204,11 @@ the .Xr cksum 1 utility. .It Cm flags -The file flags as a symbolic name. See +The file flags as a symbolic name. +See .Xr chflags 1 -for information on these names. If no flags are to be set the string +for information on these names. +If no flags are to be set the string .Dq none may be used to override the current default. .It Cm ignore @@ -178,18 +217,18 @@ Ignore any file hierarchy below this file. The file group as a numeric value. .It Cm gname The file group as a symbolic name. -.\" .It Cm md5digest -.\" The MD5 message digest of the file. -.\" .It Cm sha1digest -.\" The -.\" .Tn FIPS -.\" 160-1 -.\" .Pq Dq Tn SHA-1 -.\" message digest of the file. -.\" .It Cm ripemd160digest -.\" The -.\" .Tn RIPEMD160 -.\" message digest of the file. +.It Cm md5digest +The MD5 message digest of the file. +.It Cm sha1digest +The +.Tn FIPS +160-1 +.Pq Dq Tn SHA-1 +message digest of the file. +.It Cm ripemd160digest +The +.Tn RIPEMD160 +message digest of the file. .It Cm mode The current file's permissions as a numeric (octal) or symbolic value. @@ -281,63 +320,43 @@ Empty lines and lines whose first non-whitespace character is a hash mark (``#'') are ignored. .Pp The -.Nm +.Nm mtree utility exits with a status of 0 on success, 1 if any error occurred, and 2 if the file hierarchy did not match the specification. A status of 2 is converted to a status of 0 if the .Fl U option is used. -.\" .Sh EXAMPLES -.\" To detect system binaries that have been ``trojan horsed'', it is recommended -.\" that -.\" .Nm -.\" .Fl K -.\" .Cm sha1digest -.\" be run on the file systems, and a copy of the results stored on a different -.\" machine, or, at least, in encrypted form. -.\" The output file itself should be digested using the -.\" .Xr md5 1 -.\" utility. -.\" Then, periodically, -.\" .Nm -.\" and -.\" .Xr md5 1 -.\" should be run against the on-line specifications. -.\" While it is possible for the bad guys to change the on-line specifications -.\" to conform to their modified binaries, it is believed to be -.\" impractical for them to create a modified specification which has -.\" the same MD5 digest as the original. -.\" .Pp -.\" The -.\" .Fl d -.\" and -.\" .Fl u -.\" options can be used in combination to create directory hierarchies -.\" for distributions and other such things; the files in -.\" .Pa /etc/mtree -.\" were used to create almost all directories in this -.\" .Fx -.\" distribution. .Sh FILES .Bl -tag -width /etc/mtree -compact .It Pa /etc/mtree system specification directory .El -.Sh DIAGNOSTICS +.Sh EXIT STATUS .Ex -std +.Sh EXAMPLES +The +.Fl d +and +.Fl u +options can be used in combination to create directory hierarchies +for distributions and other such things; the files in +.Pa /etc/mtree +were used to create almost all directories in this +.Fx +distribution. .Sh SEE ALSO .Xr chflags 1 , .Xr chgrp 1 , .Xr chmod 1 , .Xr cksum 1 , -.\" .Xr md5 1 , +.Xr md5 1 , .Xr stat 2 , .Xr fts 3 , -.\" .Xr md5 3 , +.Xr md5 3 , .Xr chown 8 .Sh HISTORY The -.Nm +.Nm mtree utility appeared in .Bx 4.3 Reno . The diff --git a/mtree/mtree.c b/mtree/mtree.c index e43e50c..fe5a8b6 100644 --- a/mtree/mtree.c +++ b/mtree/mtree.c @@ -10,11 +10,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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,6 +27,7 @@ * SUCH DAMAGE. */ +#if 0 #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1989, 1990, 1993\n\ @@ -38,12 +35,11 @@ static const char copyright[] = #endif /* not lint */ #ifndef lint -#if 0 static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93"; -#endif -static const char rcsid[] = - "$FreeBSD: src/usr.sbin/mtree/mtree.c,v 1.8.2.2 2001/01/12 19:17:18 phk Exp $"; #endif /* not lint */ +#endif +#include +__FBSDID("$FreeBSD: src/usr.sbin/mtree/mtree.c,v 1.29 2004/06/04 19:29:28 ru Exp $"); #include #include @@ -51,33 +47,33 @@ static const char rcsid[] = #include #include #include +#include #include #include "mtree.h" #include "extern.h" -extern long int crc_total; - int ftsoptions = FTS_PHYSICAL; -int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag; +int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag, wflag; u_int keys; char fullpath[MAXPATHLEN]; -static void usage __P((void)); +static void usage(void); int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char *argv[]) { int ch; char *dir, *p; int status; + FILE *spec1, *spec2; dir = NULL; keys = KEYDEFAULT; init_excludes(); + spec1 = stdin; + spec2 = NULL; - while ((ch = getopt(argc, argv, "cdef:iK:k:LnPp:qrs:UuxX:")) != -1) + while ((ch = getopt(argc, argv, "cdef:iK:k:LnPp:qrs:UuwxX:")) != -1) switch((char)ch) { case 'c': cflag = 1; @@ -89,8 +85,16 @@ main(argc, argv) eflag = 1; break; case 'f': - if (!(freopen(optarg, "r", stdin))) - err(1, "%s", optarg); + if (spec1 == stdin) { + spec1 = fopen(optarg, "r"); + if (spec1 == NULL) + err(1, "%s", optarg); + } else if (spec2 == NULL) { + spec2 = fopen(optarg, "r"); + if (spec2 == NULL) + err(1, "%s", optarg); + } else + usage(); break; case 'i': iflag = 1; @@ -128,9 +132,10 @@ main(argc, argv) break; case 's': sflag = 1; - crc_total = ~strtol(optarg, &p, 0); + crc_total = ~strtoul(optarg, &p, 0); if (*p) errx(1, "illegal seed value -- %s", optarg); + break; case 'U': Uflag = 1; uflag = 1; @@ -138,6 +143,9 @@ main(argc, argv) case 'u': uflag = 1; break; + case 'w': + wflag = 1; + break; case 'x': ftsoptions |= FTS_XDEV; break; @@ -164,17 +172,20 @@ main(argc, argv) cwalk(); exit(0); } - status = verify(); + if (spec2 != NULL) + status = mtree_specspec(spec1, spec2); + else + status = mtree_verifyspec(spec1); if (Uflag & (status == MISMATCHEXIT)) status = 0; exit(status); } static void -usage() +usage(void) { (void)fprintf(stderr, -"usage: mtree [-LPUcdeinqrux] [-f spec] [-K key] [-k key] [-p path] [-s seed]\n" +"usage: mtree [-LPUcdeinqruxw] [-f spec] [-f spec] [-K key] [-k key] [-p path] [-s seed]\n" "\t[-X excludes]\n"); exit(1); } diff --git a/mtree/mtree.h b/mtree/mtree.h index 3398b05..2b99797 100644 --- a/mtree/mtree.h +++ b/mtree/mtree.h @@ -10,11 +10,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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 +27,7 @@ * SUCH DAMAGE. * * @(#)mtree.h 8.1 (Berkeley) 6/6/93 - * $FreeBSD: src/usr.sbin/mtree/mtree.h,v 1.5 1999/12/09 20:38:35 joe Exp $ + * $FreeBSD: src/usr.sbin/mtree/mtree.h,v 1.7 2005/03/29 11:44:17 tobez Exp $ */ #include @@ -50,6 +46,7 @@ typedef struct _node { u_long cksum; /* check sum */ char *md5digest; /* MD5 digest */ char *sha1digest; /* SHA-1 digest */ + char *sha256digest; /* SHA-256 digest */ char *rmd160digest; /* RIPEMD160 digest */ char *slink; /* symbolic link reference */ uid_t st_uid; /* uid */ @@ -80,6 +77,7 @@ typedef struct _node { #define F_SHA1 0x20000 /* SHA-1 digest */ #define F_RMD160 0x40000 /* RIPEMD160 digest */ #define F_FLAGS 0x80000 /* file flags */ +#define F_SHA256 0x100000 /* SHA-256 digest */ u_int flags; /* items set */ #define F_BLOCK 0x001 /* block special */ diff --git a/mtree/spec.c b/mtree/spec.c index 2b9dfed..ae958ae 100644 --- a/mtree/spec.c +++ b/mtree/spec.c @@ -10,11 +10,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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,13 +27,13 @@ * SUCH DAMAGE. */ -#ifndef lint #if 0 +#ifndef lint static char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 6/6/93"; -#endif -static const char rcsid[] = - "$FreeBSD: src/usr.sbin/mtree/spec.c,v 1.13.2.1 2000/06/28 02:33:17 joe Exp $"; #endif /* not lint */ +#endif +#include +__FBSDID("$FreeBSD: src/usr.sbin/mtree/spec.c,v 1.22 2005/03/29 11:44:17 tobez Exp $"); #include #include @@ -48,6 +44,7 @@ static const char rcsid[] = #include #include #include +#include #include #include #include "mtree.h" @@ -55,14 +52,14 @@ static const char rcsid[] = int lineno; /* Current spec line number. */ -static void set __P((char *, NODE *)); -static void unset __P((char *, NODE *)); +static void set(char *, NODE *); +static void unset(char *, NODE *); NODE * -spec() +mtree_readspec(FILE *fi) { - register NODE *centry, *last; - register char *p; + NODE *centry, *last; + char *p; NODE ginfo, *root; int c_cur, c_next; char buf[2048]; @@ -70,7 +67,7 @@ spec() centry = last = root = NULL; bzero(&ginfo, sizeof(ginfo)); c_cur = c_next = 0; - for (lineno = 1; fgets(buf, sizeof(buf), stdin); + for (lineno = 1; fgets(buf, sizeof(buf), fi); ++lineno, c_cur = c_next, c_next = 0) { /* Skip empty lines. */ if (buf[0] == '\n') @@ -147,11 +144,8 @@ noparent: errx(1, "line %d: no parent node", lineno); #define MAGIC "?*[" if (strpbrk(p, MAGIC)) centry->flags |= F_MAGIC; - if (strunvis(centry->name, p) == -1) { - warnx("filename %s is ill-encoded and literally used", - p); - strcpy(centry->name, p); - } + if (strunvis(centry->name, p) == -1) + errx(1, "filename %s is ill-encoded", p); set(NULL, centry); if (!root) { @@ -170,11 +164,9 @@ noparent: errx(1, "line %d: no parent node", lineno); } static void -set(t, ip) - char *t; - NODE *ip; +set(char *t, NODE *ip) { - register int type; + int type; char *kw, *val = NULL; struct group *gr; struct passwd *pw; @@ -195,21 +187,23 @@ set(t, ip) break; case F_MD5: ip->md5digest = strdup(val); - if(!ip->md5digest) { + if(!ip->md5digest) errx(1, "strdup"); - } break; case F_SHA1: ip->sha1digest = strdup(val); - if(!ip->sha1digest) { + if(!ip->sha1digest) + errx(1, "strdup"); + break; + case F_SHA256: + ip->sha256digest = strdup(val); + if(!ip->sha256digest) errx(1, "strdup"); - } break; case F_RMD160: ip->rmd160digest = strdup(val); - if(!ip->rmd160digest) { + if(!ip->rmd160digest) errx(1, "strdup"); - } break; case F_FLAGS: if (strcmp("none", val) == 0) @@ -250,8 +244,11 @@ set(t, ip) lineno, val); break; case F_SLINK: - if ((ip->slink = strdup(val)) == NULL) - errx(1, "strdup"); + ip->slink = malloc(strlen(val) + 1); + if (ip->slink == NULL) + errx(1, "malloc"); + if (strunvis(ip->slink, val) == -1) + errx(1, "symlink %s is ill-encoded", val); break; case F_TIME: ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10); @@ -312,11 +309,9 @@ set(t, ip) } static void -unset(t, ip) - char *t; - register NODE *ip; +unset(char *t, NODE *ip) { - register char *p; + char *p; while ((p = strtok(t, "\n\t "))) ip->flags &= ~parsekey(p, NULL); diff --git a/mtree/specspec.c b/mtree/specspec.c new file mode 100644 index 0000000..9aa66f0 --- /dev/null +++ b/mtree/specspec.c @@ -0,0 +1,257 @@ +/*- + * Copyright (c) 2003 Poul-Henning Kamp + * 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 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 AUTHOR 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 +__FBSDID("$FreeBSD: src/usr.sbin/mtree/specspec.c,v 1.6 2005/03/29 11:44:17 tobez Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include "mtree.h" +#include "extern.h" + +#define FF(a, b, c, d) \ + (((a)->flags & (c)) && ((b)->flags & (c)) && ((a)->d) != ((b)->d)) +#define FS(a, b, c, d) \ + (((a)->flags & (c)) && ((b)->flags & (c)) && strcmp((a)->d,(b)->d)) +#define FM(a, b, c, d) \ + (((a)->flags & (c)) && ((b)->flags & (c)) && memcmp(&(a)->d,&(b)->d, sizeof (a)->d)) + +static void +shownode(NODE *n, int f, char const *path) +{ + struct group *gr; + struct passwd *pw; + + printf("%s%s %s", path, n->name, ftype(n->type)); + if (f & F_CKSUM) + printf(" cksum=%lu", n->cksum); + if (f & F_GID) + printf(" gid=%d", n->st_gid); + if (f & F_GNAME) { + gr = getgrgid(n->st_gid); + if (gr == NULL) + printf(" gid=%d", n->st_gid); + else + printf(" gname=%s", gr->gr_name); + } + if (f & F_MODE) + printf(" mode=%o", n->st_mode); + if (f & F_NLINK) + printf(" nlink=%d", n->st_nlink); + if (f & F_SIZE) + printf(" size=%jd", (intmax_t)n->st_size); + if (f & F_UID) + printf(" uid=%d", n->st_uid); + if (f & F_UNAME) { + pw = getpwuid(n->st_uid); + if (pw == NULL) + printf(" uid=%d", n->st_uid); + else + printf(" uname=%s", pw->pw_name); + } + if (f & F_MD5) + printf(" md5digest=%s", n->md5digest); + if (f & F_SHA1) + printf(" sha1digest=%s", n->sha1digest); + if (f & F_RMD160) + printf(" rmd160digest=%s", n->rmd160digest); + if (f & F_SHA256) + printf(" sha256digest=%s", n->sha256digest); + if (f & F_FLAGS) + printf(" flags=%s", flags_to_string(n->st_flags)); + printf("\n"); +} + +static int +mismatch(NODE *n1, NODE *n2, int differ, char const *path) +{ + + if (n2 == NULL) { + shownode(n1, differ, path); + return (1); + } + if (n1 == NULL) { + printf("\t"); + shownode(n2, differ, path); + return (1); + } + if (!(differ & keys)) + return(0); + printf("\t\t"); + shownode(n1, differ, path); + printf("\t\t"); + shownode(n2, differ, path); + return (1); +} + +static int +compare_nodes(NODE *n1, NODE *n2, char const *path) +{ + int differs; + + if (n1 != NULL && n1->type == F_LINK) + n1->flags &= ~F_MODE; + if (n2 != NULL && n2->type == F_LINK) + n2->flags &= ~F_MODE; + differs = 0; + if (n1 == NULL && n2 != NULL) { + differs = n2->flags; + mismatch(n1, n2, differs, path); + return (1); + } + if (n1 != NULL && n2 == NULL) { + differs = n1->flags; + mismatch(n1, n2, differs, path); + return (1); + } + if (n1->type != n2->type) { + differs = 0; + mismatch(n1, n2, differs, path); + return (1); + } + if (FF(n1, n2, F_CKSUM, cksum)) + differs |= F_CKSUM; + if (FF(n1, n2, F_GID, st_gid)) + differs |= F_GID; + if (FF(n1, n2, F_GNAME, st_gid)) + differs |= F_GNAME; + if (FF(n1, n2, F_MODE, st_mode)) + differs |= F_MODE; + if (FF(n1, n2, F_NLINK, st_nlink)) + differs |= F_NLINK; + if (FF(n1, n2, F_SIZE, st_size)) + differs |= F_SIZE; + if (FS(n1, n2, F_SLINK, slink)) + differs |= F_SLINK; + if (FM(n1, n2, F_TIME, st_mtimespec)) + differs |= F_TIME; + if (FF(n1, n2, F_UID, st_uid)) + differs |= F_UID; + if (FF(n1, n2, F_UNAME, st_uid)) + differs |= F_UNAME; + if (FS(n1, n2, F_MD5, md5digest)) + differs |= F_MD5; + if (FS(n1, n2, F_SHA1, sha1digest)) + differs |= F_SHA1; + if (FS(n1, n2, F_RMD160, rmd160digest)) + differs |= F_RMD160; + if (FS(n1, n2, F_SHA256, sha256digest)) + differs |= F_SHA256; + if (FF(n1, n2, F_FLAGS, st_flags)) + differs |= F_FLAGS; + if (differs) { + mismatch(n1, n2, differs, path); + return (1); + } + return (0); +} +static int +walk_in_the_forest(NODE *t1, NODE *t2, char const *path) +{ + int r, i; + NODE *c1, *c2, *n1, *n2; + char *np; + + r = 0; + + if (t1 != NULL) + c1 = t1->child; + else + c1 = NULL; + if (t2 != NULL) + c2 = t2->child; + else + c2 = NULL; + while (c1 != NULL || c2 != NULL) { + n1 = n2 = NULL; + if (c1 != NULL) + n1 = c1->next; + if (c2 != NULL) + n2 = c2->next; + if (c1 != NULL && c2 != NULL) { + if (c1->type != F_DIR && c2->type == F_DIR) { + n2 = c2; + c2 = NULL; + } else if (c1->type == F_DIR && c2->type != F_DIR) { + n1 = c1; + c1 = NULL; + } else { + i = strcmp(c1->name, c2->name); + if (i > 0) { + n1 = c1; + c1 = NULL; + } else if (i < 0) { + n2 = c2; + c2 = NULL; + } + } + } + if (c1 == NULL && c2->type == F_DIR) { + asprintf(&np, "%s%s/", path, c2->name); + i = walk_in_the_forest(c1, c2, np); + free(np); + i += compare_nodes(c1, c2, path); + } else if (c2 == NULL && c1->type == F_DIR) { + asprintf(&np, "%s%s/", path, c1->name); + i = walk_in_the_forest(c1, c2, np); + free(np); + i += compare_nodes(c1, c2, path); + } else if (c1 == NULL || c2 == NULL) { + i = compare_nodes(c1, c2, path); + } else if (c1->type == F_DIR && c2->type == F_DIR) { + asprintf(&np, "%s%s/", path, c1->name); + i = walk_in_the_forest(c1, c2, np); + free(np); + i += compare_nodes(c1, c2, path); + } else { + i = compare_nodes(c1, c2, path); + } + r += i; + c1 = n1; + c2 = n2; + } + return (r); +} + +int +mtree_specspec(FILE *fi, FILE *fj) +{ + int rval; + NODE *root1, *root2; + + root1 = mtree_readspec(fi); + root2 = mtree_readspec(fj); + rval = walk_in_the_forest(root1, root2, ""); + rval += compare_nodes(root1, root2, ""); + if (rval > 0) + return (MISMATCHEXIT); + return (0); +} diff --git a/mtree/verify.c b/mtree/verify.c index 201d237..cefdbd5 100644 --- a/mtree/verify.c +++ b/mtree/verify.c @@ -10,11 +10,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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,13 +27,13 @@ * SUCH DAMAGE. */ -#ifndef lint #if 0 +#ifndef lint static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93"; -#endif -static const char rcsid[] = - "$FreeBSD: src/usr.sbin/mtree/verify.c,v 1.10.2.2 2001/01/12 19:17:18 phk Exp $"; #endif /* not lint */ +#endif +#include +__FBSDID("$FreeBSD: src/usr.sbin/mtree/verify.c,v 1.24 2005/08/11 15:43:55 brian Exp $"); #include #include @@ -47,43 +43,39 @@ static const char rcsid[] = #include #include #include +#include #include #include "mtree.h" #include "extern.h" -extern long int crc_total; -extern int ftsoptions; -extern int dflag, eflag, qflag, rflag, sflag, uflag; -extern char fullpath[MAXPATHLEN]; -extern int lineno; - static NODE *root; static char path[MAXPATHLEN]; -static void miss __P((NODE *, char *)); -static int vwalk __P((void)); +static void miss(NODE *, char *); +static int vwalk(void); int -verify() +mtree_verifyspec(FILE *fi) { int rval; - root = spec(); + root = mtree_readspec(fi); rval = vwalk(); miss(root, path); return (rval); } static int -vwalk() +vwalk(void) { - register FTS *t; - register FTSENT *p; - register NODE *ep, *level; + FTS *t; + FTSENT *p; + NODE *ep, *level; int specdepth, rval; char *argv[2]; + char dot[] = "."; - argv[0] = "."; + argv[0] = dot; argv[1] = NULL; if ((t = fts_open(argv, ftsoptions, NULL)) == NULL) err(1, "line %d: fts_open", lineno); @@ -154,18 +146,17 @@ extra: } (void)fts_close(t); if (sflag) - warnx("%s checksum: %lu", fullpath, crc_total); + warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total); return (rval); } static void -miss(p, tail) - register NODE *p; - register char *tail; +miss(NODE *p, char *tail) { - register int create; - register char *tp; - const char *type; + int create; + char *tp; + const char *type, *what; + int serr; for (; p; p = p->next) { if (p->type != F_DIR && (dflag || p->flags & F_VISIT)) @@ -175,7 +166,7 @@ miss(p, tail) /* Don't print missing message if file exists as a symbolic link and the -q flag is set. */ struct stat statbuf; - + if (qflag && stat(path, &statbuf) == 0) p->flags |= F_VISIT; else @@ -202,11 +193,20 @@ miss(p, tail) strerror(errno)); else (void)printf(" (created)\n"); -#if 0 /* lchown() does not exist on Darwin. */ - if (lchown(path, p->st_uid, p->st_gid)) - (void)printf("%s: user/group not modified: %s\n", - path, strerror(errno)); -#endif + if (lchown(path, p->st_uid, p->st_gid) == -1) { + serr = errno; + if (p->st_uid == (uid_t)-1) + what = "group"; + else if (lchown(path, (uid_t)-1, + p->st_gid) == -1) + what = "user & group"; + else { + what = "user"; + errno = serr; + } + (void)printf("%s: %s not modified: %s" + "\n", path, what, strerror(errno)); + } continue; } else if (!(p->flags & F_MODE)) (void)printf(" (directory not created: mode not specified)"); @@ -228,12 +228,18 @@ miss(p, tail) if (!create) continue; - if (chown(path, p->st_uid, p->st_gid)) { - (void)printf("%s: user/group/mode not modified: %s\n", - path, strerror(errno)); - (void)printf("%s: warning: file mode %snot set\n", path, - (p->flags & F_FLAGS) ? "and file flags " : ""); - continue; + if (chown(path, p->st_uid, p->st_gid) == -1) { + serr = errno; + if (p->st_uid == (uid_t)-1) + what = "group"; + else if (chown(path, (uid_t)-1, p->st_gid) == -1) + what = "user & group"; + else { + what = "user"; + errno = serr; + } + (void)printf("%s: %s not modified: %s\n", + path, what, strerror(errno)); } if (chmod(path, p->st_mode)) (void)printf("%s: permissions not set: %s\n", diff --git a/mv/mv.1 b/mv/mv.1 index 6439600..3c57d15 100644 --- a/mv/mv.1 +++ b/mv/mv.1 @@ -42,17 +42,17 @@ .Nm mv .Nd move files .Sh SYNOPSIS -.Nm +.Nm mv .Op Fl f | i | n .Op Fl v .Ar source target -.Nm +.Nm mv .Op Fl f | i | n .Op Fl v .Ar source ... directory .Sh DESCRIPTION In its first form, the -.Nm +.Nm mv utility renames the file named by the .Ar source operand to the destination path named by the @@ -62,7 +62,7 @@ This form is assumed when the last operand does not name an already existing directory. .Pp In its second form, -.Nm +.Nm mv moves each file named by a .Ar source operand to a destination file in the existing directory named by the @@ -86,7 +86,7 @@ or options.) .It Fl i Cause -.Nm +.Nm mv to write a prompt to standard error before moving a file that would overwrite an existing file. If the response from the standard input begins with the character @@ -112,7 +112,7 @@ or options.) .It Fl v Cause -.Nm +.Nm mv to be verbose, showing files after they are moved. .El .Pp @@ -121,7 +121,7 @@ It is an error for either the operand or the destination path to specify a directory unless both do. .Pp If the destination path does not have a mode which permits writing, -.Nm +.Nm mv prompts the user for confirmation as specified for the .Fl i option. @@ -129,7 +129,7 @@ option. As the .Xr rename 2 call does not work across file systems, -.Nm +.Nm mv uses .Xr cp 1 and @@ -143,6 +143,11 @@ rm -rf source_file .Ed .Sh DIAGNOSTICS .Ex -std +.Pp +The command "mv dir/afile dir" will abort with an error message. +.Sh LEGACY DIAGNOSTICS +In legacy mode, the command "mv dir/afile dir" will fail silently, +returning an exit code of 0. .Sh SEE ALSO .Xr cp 1 , .Xr rm 1 , @@ -153,14 +158,24 @@ The and .Fl v options are non-standard and their use in scripts is not recommended. +.Pp +The +.Nm mv +utility now supports HFS+ Finder and Extended Attributes and resource forks. +The +.Nm mv +utility will no longer strip resource forks off of HFS files. +For an alternative method, +refer to +.Xr cp 1 . .Sh STANDARDS The -.Nm +.Nm mv utility is expected to be .St -p1003.2 compatible. .Sh HISTORY A -.Nm +.Nm mv command appeared in .At v1 . diff --git a/mv/mv.c b/mv/mv.c index b8f275f..31acc39 100644 --- a/mv/mv.c +++ b/mv/mv.c @@ -72,6 +72,12 @@ __RCSID("$FreeBSD: src/bin/mv/mv.c,v 1.39 2002/07/09 17:45:13 johan Exp $"); #include #endif +#ifdef __APPLE__ +#include +#else +#define COMPAT_MODE(a,b) (1) +#endif /* __APPLE__ */ + #include "pathnames.h" int fflg, iflg, nflg, vflg; @@ -201,8 +207,27 @@ main(int argc, char *argv[]) rval = 1; } else { memmove(endp, p, (size_t)len + 1); - if (do_move(*argv, path)) - rval = 1; + if (COMPAT_MODE("bin/mv", "unix2003")) { + /* + * For Unix 2003 compatibility, check if old and new are + * same file, and produce an error * (like on Sun) that + * conformance test 66 in mv.ex expects. + */ + if (!stat(*argv, &fsb) && !stat(path, &tsb) && + fsb.st_ino == tsb.st_ino && + fsb.st_dev == tsb.st_dev && + fsb.st_gen == tsb.st_gen) { + (void)fprintf(stderr, "mv: %s and %s are identical\n", + *argv, path); + rval = 2; /* Like the Sun */ + } else { + if (do_move(*argv, path)) + rval = 1; + } + } else { + if (do_move(*argv, path)) + rval = 1; + } } } exit(rval); @@ -324,25 +349,25 @@ fastcopy(char *from, char *to, struct stat *sbp) return (1); } #ifdef __APPLE__ - { - struct statfs sfs; - - /* - * Pre-allocate blocks for the destination file if it - * resides on Xsan. - */ - if (fstatfs(to_fd, &sfs) == 0 && - strcmp(sfs.f_fstypename, "acfs") == 0) { - fstore_t fst; - - fst.fst_flags = 0; - fst.fst_posmode = F_PEOFPOSMODE; - fst.fst_offset = 0; - fst.fst_length = sbp->st_size; - - (void) fcntl(to_fd, F_PREALLOCATE, &fst); - } - } + { + struct statfs sfs; + + /* + * Pre-allocate blocks for the destination file if it + * resides on Xsan. + */ + if (fstatfs(to_fd, &sfs) == 0 && + strcmp(sfs.f_fstypename, "acfs") == 0) { + fstore_t fst; + + fst.fst_flags = 0; + fst.fst_posmode = F_PEOFPOSMODE; + fst.fst_offset = 0; + fst.fst_length = sbp->st_size; + + (void) fcntl(to_fd, F_PREALLOCATE, &fst); + } + } #endif /* __APPLE__ */ while ((nread = read(from_fd, bp, (size_t)blen)) > 0) if (write(to_fd, bp, (size_t)nread) != nread) { @@ -358,7 +383,11 @@ err: if (unlink(to)) return (1); } #ifdef __APPLE__ - copyfile(from, to, 0, COPYFILE_ACL | COPYFILE_XATTR); + /* XATTR can fail if to_fd has mode 000 */ + if (fcopyfile(from_fd, to_fd, NULL, COPYFILE_ACL | COPYFILE_XATTR) < 0) { + warn("%s: unable to move extended attributes and ACL from %s", + to, from); + } #endif (void)close(from_fd); @@ -384,7 +413,7 @@ err: if (unlink(to)) */ errno = 0; if (fchflags(to_fd, (u_long)sbp->st_flags)) - if (errno != EOPNOTSUPP || sbp->st_flags != 0) + if (errno != ENOTSUP || sbp->st_flags != 0) warn("%s: set flags (was: 0%07o)", to, sbp->st_flags); tval[0].tv_sec = sbp->st_atime; diff --git a/pax/Makefile b/pax/Makefile index 59d1825..85168df 100644 --- a/pax/Makefile +++ b/pax/Makefile @@ -17,7 +17,7 @@ HFILES = cache.h cpio.h extern.h ftree.h options.h pat_rep.h pax.h\ CFILES = 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 + sel_subs.c tables.c tar.c tty_subs.c pax_format.c OTHERSRCS = Makefile Makefile.preamble Makefile.postamble pax.1 cpio.1 diff --git a/pax/ar_io.c b/pax/ar_io.c index 74e13ca..caff56c 100644 --- a/pax/ar_io.c +++ b/pax/ar_io.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ar_io.c,v 1.17 1997/09/01 18:29:42 deraadt Exp $ */ +/* $OpenBSD: ar_io.c,v 1.36 2004/06/20 16:22:08 niklas Exp $ */ /* $NetBSD: ar_io.c,v 1.5 1996/03/26 23:54:13 mrg Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)ar_io.c 8.2 (Berkeley) 4/18/94"; +static const char sccsid[] = "@(#)ar_io.c 8.2 (Berkeley) 4/18/94"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ar_io.c,v 1.17 1997/09/01 18:29:42 deraadt Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ar_io.c,v 1.36 2004/06/20 16:22:08 niklas Exp $"; #endif #endif /* not lint */ @@ -52,6 +48,7 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ar_io.c,v 1.17 1997 #include #include #include +#include #include #include #include @@ -72,8 +69,8 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ar_io.c,v 1.17 1997 #define EXT_MODE O_RDONLY /* open mode for list/extract */ #define AR_MODE (O_WRONLY | O_CREAT | O_TRUNC) /* mode for archive */ #define APP_MODE O_RDWR /* mode for append */ -#define STDO "" /* psuedo name for stdout */ -#define STDN "" /* psuedo name for stdin */ +#define STDO "" /* pseudo name for stdout */ +#define STDN "" /* pseudo name for stdin */ static int arfd = -1; /* archive file descriptor */ static int artyp = ISREG; /* archive type: file/FIFO/tape */ static int arvol = 1; /* archive volume number */ @@ -85,12 +82,14 @@ static struct stat arsb; /* stat of archive device at open */ static int invld_rec; /* tape has out of spec record size */ static int wr_trail = 1; /* trailer was rewritten in append */ static int can_unlnk = 0; /* do we unlink null archives? */ -char *arcname; /* printable name of archive */ -char *gzip_program; /* name of gzip program */ +const char *arcname; /* printable name of archive */ +const char *gzip_program; /* name of gzip program */ +static pid_t zpid = -1; /* pid of child process */ +int force_one_volume; /* 1 if we ignore volume changes */ -static int get_phys __P((void)); +static int get_phys(void); extern sigset_t s_mask; -static void ar_start_gzip __P((int)); +static void ar_start_gzip(int, const char *, int); /* * ar_open() @@ -101,14 +100,8 @@ static void ar_start_gzip __P((int)); * -1 on failure, 0 otherwise */ -#ifdef __STDC__ int -ar_open(char *name) -#else -int -ar_open(name) - char *name; -#endif +ar_open(const char *name) { struct mtget mb; @@ -128,32 +121,28 @@ ar_open(name) if (name == NULL) { arfd = STDIN_FILENO; arcname = STDN; - } else if ((arfd = open(name, EXT_MODE, DMOD)) < 0) { - syswarn(0, errno, "Failed open to read on %s", name); - exit(1); - } - if (zflag) - ar_start_gzip(arfd); + } else if ((arfd = open(name, EXT_MODE, DMOD)) < 0) + syswarn(1, errno, "Failed open to read on %s", name); + if (arfd != -1 && gzip_program != NULL) + ar_start_gzip(arfd, gzip_program, 0); break; case ARCHIVE: if (name == NULL) { arfd = STDOUT_FILENO; arcname = STDO; } else if ((arfd = open(name, AR_MODE, DMOD)) < 0) - syswarn(0, errno, "Failed open to write on %s", name); + syswarn(1, errno, "Failed open to write on %s", name); else can_unlnk = 1; - if (zflag) - ar_start_gzip(arfd); + if (arfd != -1 && gzip_program != NULL) + ar_start_gzip(arfd, gzip_program, 1); break; case APPND: - if (zflag) - err(1, "can not gzip while appending"); if (name == NULL) { arfd = STDOUT_FILENO; arcname = STDO; } else if ((arfd = open(name, APP_MODE, DMOD)) < 0) - syswarn(0, errno, "Failed open to read/write on %s", + syswarn(1, errno, "Failed open to read/write on %s", name); break; case COPY: @@ -168,8 +157,10 @@ ar_open(name) return(-1); if (chdname != NULL) - if (chdir(chdname) != 0) + if (chdir(chdname) != 0) { syswarn(1, errno, "Failed chdir to %s", chdname); + return(-1); + } /* * set up is based on device type */ @@ -216,11 +207,11 @@ ar_open(name) /* * set default blksz on read. APPNDs writes rdblksz on the last volume * On all new archive volumes, we shift to wrblksz (if the user - * specified one, otherwize we will continue to use rdblksz). We - * must to set blocksize based on what kind of device the archive is + * specified one, otherwise we will continue to use rdblksz). We + * must set blocksize based on what kind of device the archive is * stored. */ - switch(artyp) { + switch (artyp) { case ISTAPE: /* * Tape drives come in at least two flavors. Those that support @@ -283,7 +274,7 @@ ar_open(name) if ((arsb.st_size % rdblksz) == 0) break; /* - * When we cannont find a match, we may have a flawed archive. + * When we cannot find a match, we may have a flawed archive. */ if (rdblksz <= 0) rdblksz = FILEBLK; @@ -297,7 +288,7 @@ ar_open(name) break; default: /* - * should never happen, worse case, slow... + * should never happen, worst case, slow... */ blksz = rdblksz = BLKMULT; break; @@ -310,26 +301,16 @@ ar_open(name) * ar_close() * closes archive device, increments volume number, and prints i/o summary */ -#ifdef __STDC__ void ar_close(void) -#else -void -ar_close() -#endif { - FILE *outf; + int status; if (arfd < 0) { did_io = io_ok = flcnt = 0; return; } - if (act == LIST) - outf = stdout; - else - outf = stderr; - /* * Close archive file. This may take a LONG while on tapes (we may be * forced to wait for the rewind to complete) so tell the user what is @@ -338,11 +319,11 @@ ar_close() */ if (vflag && (artyp == ISTAPE)) { if (vfpart) - (void)putc('\n', outf); - (void)fprintf(outf, + (void)putc('\n', listf); + (void)fprintf(listf, "%s: Waiting for tape drive close to complete...", argv0); - (void)fflush(outf); + (void)fflush(listf); } /* @@ -355,12 +336,23 @@ ar_close() can_unlnk = 0; } + /* + * for a quick extract/list, pax frequently exits before the child + * process is done + */ + if ((act == LIST || act == EXTRACT) && nflag && zpid > 0) + kill(zpid, SIGINT); + (void)close(arfd); + /* Do not exit before child to ensure data integrity */ + if (zpid > 0) + waitpid(zpid, &status, 0); + if (vflag && (artyp == ISTAPE)) { - (void)fputs("done.\n", outf); + (void)fputs("done.\n", listf); vfpart = 0; - (void)fflush(outf); + (void)fflush(listf); } arfd = -1; @@ -386,7 +378,7 @@ ar_close() * Print out a summary of I/O for this archive volume. */ if (vfpart) { - (void)putc('\n', outf); + (void)putc('\n', listf); vfpart = 0; } @@ -396,28 +388,28 @@ ar_close() * could have written anything yet. */ if (frmt == NULL) { -# ifdef NET2_STAT - (void)fprintf(outf, "%s: unknown format, %lu bytes skipped.\n", +# ifdef LONG_OFF_T + (void)fprintf(listf, "%s: unknown format, %lu bytes skipped.\n", # else - (void)fprintf(outf, "%s: unknown format, %qu bytes skipped.\n", + (void)fprintf(listf, "%s: unknown format, %qu bytes skipped.\n", # endif argv0, rdcnt); - (void)fflush(outf); + (void)fflush(listf); flcnt = 0; return; } if (strcmp(NM_CPIO, argv0) == 0) - (void)fprintf(outf, "%qu blocks\n", (rdcnt ? rdcnt : wrcnt) / 5120); - else if (strcmp(NM_TAR, argv0) != 0) - (void)fprintf(outf, -# ifdef NET2_STAT + (void)fprintf(listf, "%qu blocks\n", (rdcnt ? rdcnt : wrcnt) / 5120); + else if (strcmp(NM_TAR, argv0) != 0 && strcmp(NM_PAX, argv0) != 0) + (void)fprintf(listf, +# ifdef LONG_OFF_T "%s: %s vol %d, %lu files, %lu bytes read, %lu bytes written.\n", # else "%s: %s vol %d, %lu files, %qu bytes read, %qu bytes written.\n", # endif argv0, frmt->name, arvol-1, flcnt, rdcnt, wrcnt); - (void)fflush(outf); + (void)fflush(listf); flcnt = 0; } @@ -428,15 +420,10 @@ ar_close() * other side of the pipe from getting a SIGPIPE (pax will stop * reading an archive once a format dependent trailer is detected). */ -#ifdef __STDC__ void ar_drain(void) -#else -void -ar_drain() -#endif { - register int res; + int res; char drbuf[MAXBLK]; /* @@ -465,13 +452,8 @@ ar_drain() * 0 if all ready to write, -1 otherwise */ -#ifdef __STDC__ int ar_set_wr(void) -#else -int -ar_set_wr() -#endif { off_t cpos; @@ -481,7 +463,7 @@ ar_set_wr() */ wr_trail = 0; - /* + /* * Add any device dependent code as required here */ if (artyp != ISREG) @@ -502,19 +484,14 @@ ar_set_wr() /* * ar_app_ok() * check if the last volume in the archive allows appends. We cannot check - * this until we are ready to write since there is no spec that says all + * this until we are ready to write since there is no spec that says all * volumes in a single archive have to be of the same type... * Return: * 0 if we can append, -1 otherwise. */ -#ifdef __STDC__ int ar_app_ok(void) -#else -int -ar_app_ok() -#endif { if (artyp == ISPIPE) { paxwarn(1, "Cannot append to an archive obtained from a pipe."); @@ -537,17 +514,10 @@ ar_app_ok() * Number of bytes in buffer. 0 for end of file, -1 for a read error. */ -#ifdef __STDC__ -int -ar_read(register char *buf, register int cnt) -#else int -ar_read(buf, cnt) - register char *buf; - register int cnt; -#endif +ar_read(char *buf, int cnt) { - register int res = 0; + int res = 0; /* * if last i/o was in error, no more reads until reset or new volume @@ -571,10 +541,10 @@ ar_read(buf, cnt) io_ok = 1; if (res != rdblksz) { /* - * Record size changed. If this is happens on + * Record size changed. If this happens on * any record after the first, we probably have * a tape drive which has a fixed record size - * we are getting multiple records in a single + * (we are getting multiple records in a single * read). Watch out for record blocking that * violates pax spec (must be a multiple of * BLKMULT). @@ -624,20 +594,13 @@ ar_read(buf, cnt) * Return: * Number of bytes written. 0 indicates end of volume reached and with no * flaws (as best that can be detected). A -1 indicates an unrecoverable - * error in the archive occured. + * error in the archive occurred. */ -#ifdef __STDC__ -int -ar_write(register char *buf, register int bsz) -#else int -ar_write(buf, bsz) - register char *buf; - register int bsz; -#endif +ar_write(char *buf, int bsz) { - register int res; + int res; off_t cpos; /* @@ -658,7 +621,7 @@ ar_write(buf, bsz) arfd = open("/dev/null", AR_MODE, DMOD); artyp = ISREG; return bsz; - } + } /* * write broke, see what we can do with it. We try to send any partial @@ -673,10 +636,10 @@ ar_write(buf, bsz) case ISREG: if ((res > 0) && (res % BLKMULT)) { /* - * try to fix up partial writes which are not BLKMULT + * try to fix up partial writes which are not BLKMULT * in size by forcing the runt record to next archive * volume - */ + */ if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0) break; cpos -= (off_t)res; @@ -721,7 +684,7 @@ ar_write(buf, bsz) /* * Better tell the user the bad news... * if this is a block aligned archive format, we may have a bad archive - * if the format wants the header to start at a BLKMULT boundry. While + * if the format wants the header to start at a BLKMULT boundary.. While * we can deal with the mis-aligned data, it violates spec and other * archive readers will likely fail. if the format is not block * aligned, the user may be lucky (and the archive is ok). @@ -760,13 +723,8 @@ ar_write(buf, bsz) * 0 when ok to try i/o again, -1 otherwise. */ -#ifdef __STDC__ int ar_rdsync(void) -#else -int -ar_rdsync() -#endif { long fsbz; off_t cpos; @@ -774,7 +732,7 @@ ar_rdsync() struct mtop mb; /* - * Fail resync attempts at user request (done) or this is going to be + * Fail resync attempts at user request (done) or if this is going to be * an update/append to a existing archive. if last i/o hit media end, * we need to go to the next volume not try a resync */ @@ -788,13 +746,13 @@ ar_rdsync() if (io_ok) did_io = 1; - switch(artyp) { + switch (artyp) { case ISTAPE: /* * if the last i/o was a successful data transfer, we assume * the fault is just a bad record on the tape that we are now * past. If we did not get any data since the last resync try - * to move the tape foward one PHYSICAL record past any + * to move the tape forward one PHYSICAL record past any * damaged tape section. Some tape drives are stubborn and need * to be pushed. */ @@ -843,7 +801,7 @@ ar_rdsync() /* * ar_fow() - * Move the I/O position within the archive foward the specified number of + * Move the I/O position within the archive forward the specified number of * bytes as supported by the device. If we cannot move the requested * number of bytes, return the actual number of bytes moved in skipped. * Return: @@ -851,15 +809,8 @@ ar_rdsync() * partial move (the amount moved is in skipped) */ -#ifdef __STDC__ int ar_fow(off_t sksz, off_t *skipped) -#else -int -ar_fow(sksz, skipped) - off_t sksz; - off_t *skipped; -#endif { off_t cpos; off_t mpos; @@ -869,7 +820,7 @@ ar_fow(sksz, skipped) return(0); /* - * we cannot move foward at EOF or error + * we cannot move forward at EOF or error */ if (lstrval <= 0) return(lstrval); @@ -878,7 +829,7 @@ ar_fow(sksz, skipped) * Safer to read forward on devices where it is hard to find the end of * the media without reading to it. With tapes we cannot be sure of the * number of physical blocks to skip (we do not know physical block - * size at this point), so we must only read foward on tapes! + * size at this point), so we must only read forward on tapes! */ if (artyp != ISREG) return(0); @@ -887,12 +838,12 @@ ar_fow(sksz, skipped) * figure out where we are in the archive */ if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) >= 0) { - /* - * we can be asked to move farther than there are bytes in this + /* + * we can be asked to move farther than there are bytes in this * volume, if so, just go to file end and let normal buf_fill() * deal with the end of file (it will go to next volume by * itself) - */ + */ if ((mpos = cpos + sksz) > arsb.st_size) { *skipped = arsb.st_size - cpos; mpos = arsb.st_size; @@ -901,7 +852,7 @@ ar_fow(sksz, skipped) if (lseek(arfd, mpos, SEEK_SET) >= 0) return(0); } - syswarn(1, errno, "Foward positioning operation on archive failed"); + syswarn(1, errno, "Forward positioning operation on archive failed"); lstrval = -1; return(-1); } @@ -917,18 +868,12 @@ ar_fow(sksz, skipped) * 0 if moved the requested distance, -1 on complete failure */ -#ifdef __STDC__ int ar_rev(off_t sksz) -#else -int -ar_rev(sksz) - off_t sksz; -#endif { off_t cpos; struct mtop mb; - register int phyblk; + int phyblk; /* * make sure we do not have try to reverse on a flawed archive @@ -936,7 +881,7 @@ ar_rev(sksz) if (lstrval < 0) return(lstrval); - switch(artyp) { + switch (artyp) { case ISPIPE: if (sksz <= 0) break; @@ -969,8 +914,8 @@ ar_rev(sksz) /* * we may try to go backwards past the start when the archive - * is only a single record. If this hapens and we are on a - * multi volume archive, we need to go to the end of the + * is only a single record. If this happens and we are on a + * multi-volume archive, we need to go to the end of the * previous volume and continue our movement backwards from * there. */ @@ -993,12 +938,12 @@ ar_rev(sksz) break; case ISTAPE: /* - * Calculate and move the proper number of PHYSICAL tape + * Calculate and move the proper number of PHYSICAL tape * blocks. If the sksz is not an even multiple of the physical * tape size, we cannot do the move (this should never happen). - * (We also cannot handler trailers spread over two vols). + * (We also cannot handle trailers spread over two vols.) * get_phys() also makes sure we are in front of the filemark. - */ + */ if ((phyblk = get_phys()) <= 0) { lstrval = -1; return(-1); @@ -1047,7 +992,7 @@ ar_rev(sksz) /* * get_phys() * Determine the physical block size on a tape drive. We need the physical - * block size so we know how many bytes we skip over when we move with + * block size so we know how many bytes we skip over when we move with * mtio commands. We also make sure we are BEFORE THE TAPE FILEMARK when * return. * This is one really SLOW routine... @@ -1055,17 +1000,12 @@ ar_rev(sksz) * physical block size if ok (ok > 0), -1 otherwise */ -#ifdef __STDC__ static int get_phys(void) -#else -static int -get_phys() -#endif { - register int padsz = 0; - register int res; - register int phyblk; + int padsz = 0; + int res; + int phyblk; struct mtop mb; char scbuf[MAXBLK]; @@ -1113,7 +1053,7 @@ get_phys() } /* - * read foward to the file mark, then back up in front of the filemark + * read forward to the file mark, then back up in front of the filemark * (this is a bit paranoid, but should be safe to do). */ while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0) @@ -1173,13 +1113,8 @@ get_phys() * 0 when ready to continue, -1 when all done */ -#ifdef __STDC__ int ar_next(void) -#else -int -ar_next() -#endif { char buf[PAXPATHLEN+2]; static int freeit = 0; @@ -1197,7 +1132,8 @@ ar_next() syswarn(0, errno, "Unable to restore signal mask"); /* Don't query for new volume if format is unknown */ - if (frmt == NULL || done || !wr_trail || strcmp(NM_TAR, argv0) == 0) + if (frmt == NULL || done || !wr_trail || force_one_volume || strcmp(NM_TAR, argv0) == 0 || + strcmp(NM_PAX, argv0) == 0) return(-1); tty_prnt("\nATTENTION! %s archive volume change required.\n", argv0); @@ -1223,7 +1159,7 @@ ar_next() else tty_prnt("\n"); - for(;;) { + for (;;) { tty_prnt("Type \"y\" to continue, \".\" to quit %s,", argv0); tty_prnt(" or \"s\" to switch to new device.\nIf you"); @@ -1302,7 +1238,7 @@ ar_next() */ if (ar_open(buf) >= 0) { if (freeit) { - (void)free(arcname); + (void)free((char *)arcname); freeit = 0; } if ((arcname = strdup(buf)) == NULL) { @@ -1326,57 +1262,38 @@ ar_next() * to keep the fd the same in the calling function (parent). */ void -#ifdef __STDC__ -ar_start_gzip(int fd) -#else -ar_start_gzip(fd) - int fd; -#endif +ar_start_gzip(int fd, const char *gzip_program, int wr) { - pid_t pid; int fds[2]; - char *gzip_flags=NULL; + const char *gzip_flags = NULL; if (pipe(fds) < 0) err(1, "could not pipe"); - pid = fork(); - if (pid < 0) + zpid = fork(); + if (zpid < 0) err(1, "could not fork"); /* parent */ - if (pid) { - switch (act) { - case ARCHIVE: + if (zpid) { + if (wr) dup2(fds[1], fd); - break; - case LIST: - case EXTRACT: + else dup2(fds[0], fd); - break; - default: - errx(1, "ar_start_gzip: impossible"); - } close(fds[0]); close(fds[1]); } else { - switch (act) { - case ARCHIVE: + if (wr) { dup2(fds[0], STDIN_FILENO); dup2(fd, STDOUT_FILENO); gzip_flags = "-c"; - break; - case LIST: - case EXTRACT: + } else { dup2(fds[1], STDOUT_FILENO); dup2(fd, STDIN_FILENO); gzip_flags = "-dc"; - break; - default: - errx(1, "ar_start_gzip: impossible"); } close(fds[0]); close(fds[1]); - if (execlp(gzip_program, gzip_program, gzip_flags, NULL) < 0) + if (execlp(gzip_program, gzip_program, gzip_flags, (char *)NULL) < 0) err(1, "could not exec"); /* NOTREACHED */ } diff --git a/pax/ar_subs.c b/pax/ar_subs.c index 8a455f2..afa11d2 100644 --- a/pax/ar_subs.c +++ b/pax/ar_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ar_subs.c,v 1.13 1997/09/16 21:20:35 niklas Exp $ */ +/* $OpenBSD: ar_subs.c,v 1.28 2004/04/16 22:50:23 deraadt Exp $ */ /* $NetBSD: ar_subs.c,v 1.5 1995/03/21 09:07:06 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)ar_subs.c 8.2 (Berkeley) 4/18/94"; +static const char sccsid[] = "@(#)ar_subs.c 8.2 (Berkeley) 4/18/94"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ar_subs.c,v 1.13 1997/09/16 21:20:35 niklas Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ar_subs.c,v 1.28 2004/04/16 22:50:23 deraadt Exp $"; #endif #endif /* not lint */ @@ -65,9 +61,9 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ar_subs.c,v 1.13 19 #include "pax.h" #include "extern.h" -static void wr_archive __P((register ARCHD *, int is_app)); -static int get_arc __P((void)); -static int next_head __P((register ARCHD *)); +static void wr_archive(ARCHD *, int is_app); +static int get_arc(void); +static int next_head(ARCHD *); extern sigset_t s_mask; char *chdname; @@ -86,16 +82,11 @@ u_long flcnt; /* number of files processed */ * (no pattern matches all). */ -#ifdef __STDC__ void list(void) -#else -void -list() -#endif { - register ARCHD *arcn; - register int res; + ARCHD *arcn; + int res; ARCHD archd; time_t now; @@ -120,6 +111,17 @@ list() * 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 == PAX_GLF + ? -1 : -2, &cnt)) + (void)rd_skip(cnt + arcn->pad); + continue; + } + /* * check for pattern, and user specified options match. * When all patterns are matched we are done. @@ -168,16 +170,11 @@ list() * pattern(s) (no patterns extracts all members) */ -#ifdef __STDC__ void extract(void) -#else -void -extract() -#endif { - register ARCHD *arcn; - register int res; + ARCHD *arcn; + int res; off_t cnt; ARCHD archd; struct stat sb; @@ -220,6 +217,15 @@ extract() * 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 + */ + if (!(*frmt->rd_data)(arcn, arcn->type == PAX_GLF + ? -1 : -2, &cnt)) + (void)rd_skip(cnt + arcn->pad); + continue; + } /* * check for pattern, and user specified options match. When @@ -239,7 +245,7 @@ extract() /* * 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 @@ -280,7 +286,7 @@ extract() } /* - * Non standard -Y and -Z flag. When the exisiting file is + * Non standard -Y and -Z flag. When the existing file is * same age or newer skip */ if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) { @@ -303,9 +309,9 @@ extract() if (vflag) { if (vflag > 1) - ls_list(arcn, now, stderr); + ls_list(arcn, now, listf); else { - (void)fputs(arcn->name, stderr); + (void)safe_print(arcn->name, listf); vfpart = 1; } } @@ -337,7 +343,7 @@ extract() purg_lnk(arcn); if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } continue; @@ -358,7 +364,7 @@ extract() res = (*frmt->rd_data)(arcn, fd, &cnt); file_close(arcn, fd); if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } if (!res) @@ -394,7 +400,7 @@ extract() #ifdef __APPLE__ LIST_FOREACH(cle, ©file_list, link) { - if(copyfile_disable || copyfile(cle->tmp, cle->dst, 0, + if(copyfile_disable || copyfile(cle->tmp, cle->dst, NULL, COPYFILE_UNPACK | COPYFILE_XATTR | COPYFILE_ACL)) rename(cle->tmp, cle->src); else @@ -423,21 +429,14 @@ extract() * previously written archive. */ -#ifdef __STDC__ -static void -wr_archive(register ARCHD *arcn, int is_app) -#else static void -wr_archive(arcn, is_app) - register ARCHD *arcn; - int is_app; -#endif +wr_archive(ARCHD *arcn, int is_app) { - register int res; - register int hlk; - register int wr_one; + int res; + int hlk; + int wr_one; off_t cnt; - int (*wrf)(); + int (*wrf)(ARCHD *); int fd = -1; time_t now; #ifdef __APPLE__ @@ -453,6 +452,7 @@ wr_archive(arcn, is_app) */ if (((hlk = frmt->hlk) == 1) && (lnk_start() < 0)) return; + if (hlk && want_linkdata) hlk=0; /* Treat hard links as individual files */ /* * start up the file traversal code and format specific write @@ -469,7 +469,8 @@ wr_archive(arcn, is_app) return; /* - * 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 not write a + * trailer */ wr_one = is_app; @@ -582,6 +583,7 @@ next: #else if ((fd = open(arcn->org_name, O_RDONLY, 0)) < 0) { #endif + /* suppress set if size==0 ?? */ syswarn(1,errno, "Unable to open %s to read", arcn->org_name); purg_lnk(arcn); @@ -605,7 +607,7 @@ next: if ((res > 0) || (docrc && (set_crc(arcn, fd) < 0))) { /* * unable to obtain the crc we need, close the file, - * purge link table entry + * purge link table entry */ rdfile_close(arcn, &fd); purg_lnk(arcn); @@ -614,9 +616,9 @@ next: if (vflag) { if (vflag > 1) - ls_list(arcn, now, stderr); + ls_list(arcn, now, listf); else { - (void)fputs(arcn->name, stderr); + (void)safe_print(arcn->name, listf); vfpart = 1; } } @@ -632,12 +634,12 @@ next: } wr_one = 1; if (res > 0) { - /* + /* * format write says no file data needs to be stored * so we are done messing with this file */ if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } rdfile_close(arcn, &fd); @@ -655,7 +657,7 @@ next: res = (*frmt->wr_data)(arcn, fd, &cnt); rdfile_close(arcn, &fd); if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } if (res < 0) @@ -667,14 +669,14 @@ next: if (((cnt > 0) && (wr_skip(cnt) < 0)) || ((arcn->pad > 0) && (wr_skip(arcn->pad) < 0))) break; -#if __APPLE__ +#ifdef __APPLE__ if (metadata) goto next; #endif } /* - * tell format to write trailer; pad to block boundry; reset directory + * tell format to write trailer; pad to block boundary; reset directory * mode/access times, and check if all patterns supplied by the user * were matched. block off signals to avoid chance for multiple entry * into the cleanup code @@ -699,7 +701,7 @@ next: * is called to add the new members. * PAX IMPLEMENTATION DETAIL NOTE: * -u is implemented by adding the new members to the end of the archive. - * Care is taken so that these do not end up as links to the older + * Care is taken so that these do not end up as links to the older * version of the same file already stored in the archive. It is expected * when extraction occurs these newer versions will over-write the older * ones stored "earlier" in the archive (this may be a bad assumption as @@ -712,16 +714,11 @@ next: * over write existing files that it creates. */ -#ifdef __STDC__ void append(void) -#else -void -append() -#endif { - register ARCHD *arcn; - register int res; + ARCHD *arcn; + int res; ARCHD archd; FSUB *orgfrmt; int udev; @@ -732,7 +729,7 @@ append() /* * Do not allow an append operation if the actual archive is of a - * different format than the user specified foramt. + * different format than the user specified format. */ if (get_arc() < 0) return; @@ -776,7 +773,7 @@ append() * reading the archive may take a long time. If verbose tell the user */ if (vflag) { - (void)fprintf(stderr, + (void)fprintf(listf, "%s: Reading archive to position at the end...", argv0); vfpart = 1; } @@ -828,7 +825,7 @@ append() lnk_end(); /* - * try to postion for write, if this fails quit. if any error occurs, + * try to position for write, if this fails quit. if any error occurs, * we will refuse to write */ if (appnd_start(tlen) < 0) @@ -838,10 +835,10 @@ append() * tell the user we are done reading. */ if (vflag && vfpart) { - (void)fputs("done.\n", stderr); + (void)fputs("done.\n", listf); vfpart = 0; } - + /* * go to the writing phase to add the new members */ @@ -853,13 +850,8 @@ append() * write a new archive */ -#ifdef __STDC__ void archive(void) -#else -void -archive() -#endif { ARCHD archd; @@ -884,37 +876,45 @@ archive() * (except the files are forced to be under the destination directory). */ -#ifdef __STDC__ void copy(void) -#else -void -copy() -#endif { - register ARCHD *arcn; - register int res; - register int fddest; - register char *dest_pt; - register int dlen; - register int drem; + ARCHD *arcn; + int res; + int fddest; + char *dest_pt; + int dlen; + int drem; int fdsrc = -1; struct stat sb; ARCHD archd; char dirbuf[PAXPATHLEN+1]; arcn = &archd; + + if (frmt && strcmp(frmt->name, "pax")==0) { + /* Copy using pax format: must check if any -o options */ + if ((*frmt->options)() < 0) + return; + if (pax_invalid_action==0) + pax_invalid_action = PAX_INVALID_ACTION_BYPASS; + } /* * 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] != '/')) { + paxwarn(1, "directory name is too long %s", dirptr); + return; + } dest_pt = dirbuf + dlen; if (*(dest_pt-1) != '/') { *dest_pt++ = '/'; + *dest_pt = '\0'; ++dlen; } - *dest_pt = '\0'; drem = PAXPATHLEN - dlen; if (stat(dirptr, &sb) < 0) { @@ -929,7 +929,7 @@ copy() /* * start up the hard link table; file traversal routines and the - * modification time and access mode database + * modification time and access mode database */ if ((lnk_start() < 0) || (ftree_start() < 0) || (dir_start() < 0)) return; @@ -953,6 +953,11 @@ copy() fdsrc = -1; /* + * Fill in arcn from any pax options + */ + adjust_copy_for_pax_options(arcn); + + /* * check if this file meets user specified options */ if (sel_chk(arcn) != 0) @@ -972,17 +977,12 @@ copy() /* * create the destination name */ - if (*(arcn->name) == '/') - res = 1; - else - res = 0; - if ((arcn->nlen - res) > drem) { + if (strlcpy(dest_pt, arcn->name + (*arcn->name == '/'), + drem + 1) > drem) { paxwarn(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 @@ -990,10 +990,10 @@ copy() 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) @@ -1020,7 +1020,7 @@ copy() } /* - * Non standard -Y and -Z flag. When the exisiting file is + * Non standard -Y and -Z flag. When the existing file is * same age or newer skip */ if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) { @@ -1036,7 +1036,7 @@ copy() } if (vflag) { - (void)fputs(arcn->name, stderr); + (void)safe_print(arcn->name, listf); vfpart = 1; } ++flcnt; @@ -1051,7 +1051,7 @@ copy() res = chk_same(arcn); if (res <= 0) { if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } continue; @@ -1070,8 +1070,14 @@ copy() res = node_creat(arcn); if (res < 0) purg_lnk(arcn); +#ifdef __APPLE__ + if (res >= 0 && + arcn->type == PAX_DIR && + copyfile(arcn->org_name, arcn->name, NULL, COPYFILE_ACL | COPYFILE_XATTR) < 0) + paxwarn(1, "Directory %s had metadata that could not be copied: %s", arcn->org_name, strerror(errno)); +#endif /* __APPLE__ */ if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } continue; @@ -1097,19 +1103,20 @@ copy() * copy source file data to the destination file */ cp_file(arcn, fdsrc, fddest); +#ifdef __APPLE__ + /* do this before file close so that mtimes are correct regardless */ + if (getenv(COPYFILE_DISABLE_VAR) == NULL) { + if (copyfile(arcn->org_name, arcn->name, NULL, COPYFILE_ACL | COPYFILE_XATTR) < 0) + paxwarn(1, "File %s had metadata that could not be copied", arcn->org_name); + } +#endif file_close(arcn, fddest); rdfile_close(arcn, &fdsrc); if (vflag && vfpart) { - (void)putc('\n', stderr); + (void)putc('\n', listf); vfpart = 0; } -#ifdef __APPLE__ - if (getenv(COPYFILE_DISABLE_VAR) == NULL) { - if (copyfile(arcn->org_name, arcn->name, 0, COPYFILE_ACL | COPYFILE_XATTR) < 0) - paxwarn(1, "File %s had metadata that could not be copied", arcn->org_name); - } -#endif } /* @@ -1142,21 +1149,15 @@ copy() * the specs for rd_wrbuf() for more details) */ -#ifdef __STDC__ -static int -next_head(register ARCHD *arcn) -#else static int -next_head(arcn) - register ARCHD *arcn; -#endif +next_head(ARCHD *arcn) { - register int ret; - register char *hdend; - register int res; - register int shftsz; - register int hsz; - register int in_resync = 0; /* set when we are in resync mode */ + int ret; + char *hdend; + int res; + int shftsz; + int hsz; + 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. */ @@ -1167,7 +1168,7 @@ next_head(arcn) res = hsz = frmt->hsz; hdend = hdbuf; shftsz = hsz - 1; - for(;;) { + for (;;) { /* * keep looping until we get a contiguous FULL buffer * (frmt->hsz is the proper size) @@ -1231,7 +1232,7 @@ next_head(arcn) /* * this format has trailers outside of valid headers */ - if ((ret = (*frmt->trail)(hdbuf,in_resync,&cnt)) == 0){ + if ((ret = (*frmt->trail)(arcn,hdbuf,in_resync,&cnt)) == 0){ /* * valid trailer found, drain input as required */ @@ -1278,7 +1279,7 @@ next_head(arcn) * the header. NOTE: the parameters are different than trailer routines * which encode trailers outside of the header! */ - if (frmt->inhead && ((*frmt->trail)(arcn) == 0)) { + if (frmt->inhead && ((*frmt->trail)(arcn,NULL,0,NULL) == 0)) { /* * valid trailer found, drain input as required */ @@ -1300,18 +1301,13 @@ next_head(arcn) * 0 if archive found -1 otherwise */ -#ifdef __STDC__ static int get_arc(void) -#else -static int -get_arc() -#endif { - register int i; - register int hdsz = 0; - register int res; - register int minhd = BLKMULT; + int i; + int hdsz = 0; + int res; + int minhd = BLKMULT; char *hdend; int notice = 0; @@ -1328,7 +1324,7 @@ get_arc() res = BLKMULT; hdsz = 0; hdend = hdbuf; - for(;;) { + for (;;) { for (;;) { /* * fill the buffer with at least the smallest header @@ -1374,7 +1370,7 @@ get_arc() if ((*fsub[ford[i]].id)(hdbuf, hdsz) < 0) continue; frmt = &(fsub[ford[i]]); - /* + /* * yuck, to avoid slow special case code in the extract * routines, just push this header back as if it was * not seen. We have left extra space at start of the diff --git a/pax/buf_subs.c b/pax/buf_subs.c index 6e13e8f..501b9fb 100644 --- a/pax/buf_subs.c +++ b/pax/buf_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: buf_subs.c,v 1.7 1997/09/01 18:29:46 deraadt Exp $ */ +/* $OpenBSD: buf_subs.c,v 1.20 2004/04/16 22:50:23 deraadt Exp $ */ /* $NetBSD: buf_subs.c,v 1.5 1995/03/21 09:07:08 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)buf_subs.c 8.2 (Berkeley) 4/18/94"; +static const char sccsid[] = "@(#)buf_subs.c 8.2 (Berkeley) 4/18/94"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: buf_subs.c,v 1.7 1997/09/01 18:29:46 deraadt Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: buf_subs.c,v 1.20 2004/04/16 22:50:23 deraadt Exp $"; #endif #endif /* not lint */ @@ -89,13 +85,8 @@ off_t rdcnt; /* # of bytes read on current vol */ * 0 if ok, -1 if the user specified write block size violates pax spec */ -#ifdef __STDC__ int wr_start(void) -#else -int -wr_start() -#endif { buf = &(bufmem[BLKMULT]); /* @@ -124,7 +115,7 @@ wr_start() } /* - * we only allow wrblksz to be used with all archive operations + * we only allow wrblksz to be used with all archive operations */ blksz = rdblksz = wrblksz; if ((ar_open(arcname) < 0) && (ar_next() < 0)) @@ -142,13 +133,8 @@ wr_start() * 0 if ok, -1 otherwise */ -#ifdef __STDC__ int rd_start(void) -#else -int -rd_start() -#endif { /* * leave space for the header pushback (see get_arc()). If we are @@ -164,7 +150,7 @@ rd_start() } if (wrblksz % BLKMULT) { paxwarn(1, "Write block size %d is not a %d byte multiple", - wrblksz, BLKMULT); + wrblksz, BLKMULT); return(-1); } } @@ -185,13 +171,8 @@ rd_start() * set up buffer system for copying within the file system */ -#ifdef __STDC__ void cp_start(void) -#else -void -cp_start() -#endif { buf = &(bufmem[BLKMULT]); rdblksz = blksz = MAXBLK; @@ -206,13 +187,13 @@ cp_start() * 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 position 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 @@ -220,25 +201,19 @@ cp_start() * 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, - * so it may not be feasable to append archives stored on all types of - * devices. + * Often devices restrict the conditions where writes can be made, + * so it may not be feasible to append archives stored on all types of + * devices. * Return: * 0 for success, -1 for failure */ -#ifdef __STDC__ int appnd_start(off_t skcnt) -#else -int -appnd_start(skcnt) - off_t skcnt; -#endif { - register int res; + int res; off_t cnt; if (exit_val != 0) { @@ -322,7 +297,7 @@ appnd_start(skcnt) paxwarn(1, "Unable to rewrite archive trailer, cannot append."); return(-1); } - + /* * rd_sync() * A read error occurred on this archive volume. Resync the buffer and @@ -334,16 +309,11 @@ appnd_start(skcnt) * 0 on success, and -1 on failure */ -#ifdef __STDC__ int rd_sync(void) -#else -int -rd_sync() -#endif { - register int errcnt = 0; - register int res; + int errcnt = 0; + int res; /* * if the user says bail out on first fault, we are out of here... @@ -400,22 +370,15 @@ rd_sync() * 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 * pback space is increased. */ -#ifdef __STDC__ void pback(char *pt, int cnt) -#else -void -pback(pt, cnt) - char *pt; - int cnt; -#endif { bufpt -= cnt; memcpy(bufpt, pt, cnt); @@ -424,27 +387,21 @@ pback(pt, cnt) /* * rd_skip() - * skip foward in the archive during a archive read. Used to get quickly + * skip forward in the archive during a 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. */ -#ifdef __STDC__ int rd_skip(off_t skcnt) -#else -int -rd_skip(skcnt) - off_t skcnt; -#endif { off_t res; off_t cnt; 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. @@ -497,21 +454,16 @@ rd_skip(skcnt) return(0); } -/* +/* * wr_fin() * flush out any data (and pad if required) the last block. We always pad * with zero (even though we do not have to). Padding with 0 makes it a - * lot easier to recover if the archive is damaged. zero paddding SHOULD + * lot easier to recover if the archive is damaged. zero padding SHOULD * BE a requirement.... */ -#ifdef __STDC__ void wr_fin(void) -#else -void -wr_fin() -#endif { if (bufpt > buf) { memset(bufpt, 0, bufend - bufpt); @@ -526,22 +478,15 @@ wr_fin() * by format specific write routines to pass a file header). On failure we * punt. We do not allow the user to continue to write flawed archives. * We assume these headers are not very large (the memory copy we use is - * a bit expensive). + * a bit expensive). * Return: * 0 if buffer was filled ok, -1 o.w. (buffer flush failure) */ -#ifdef __STDC__ int -wr_rdbuf(register char *out, register int outcnt) -#else -int -wr_rdbuf(out, outcnt) - register char *out; - register int outcnt; -#endif +wr_rdbuf(char *out, int outcnt) { - register int cnt; + int cnt; /* * while there is data to copy copy into the write buffer. when the @@ -574,19 +519,12 @@ wr_rdbuf(out, outcnt) * -1 is a read error */ -#ifdef __STDC__ int -rd_wrbuf(register char *in, register int cpcnt) -#else -int -rd_wrbuf(in, cpcnt) - register char *in; - register int cpcnt; -#endif +rd_wrbuf(char *in, int cpcnt) { - register int res; - register int cnt; - register int incnt = cpcnt; + int res; + int cnt; + int incnt = cpcnt; /* * loop until we fill the buffer with the requested number of bytes @@ -597,7 +535,7 @@ rd_wrbuf(in, 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) @@ -620,7 +558,7 @@ rd_wrbuf(in, cpcnt) /* * wr_skip() - * skip foward during a write. In other words add padding to the file. + * skip forward during a write. In other words add padding to the file. * we add zero filled padding as it makes flawed archives much easier to * recover from. the caller tells us how many bytes of padding to add * This routine was not designed to add HUGE amount of padding, just small @@ -629,16 +567,10 @@ rd_wrbuf(in, cpcnt) * 0 if ok, -1 if there was a buf_flush failure */ -#ifdef __STDC__ int wr_skip(off_t skcnt) -#else -int -wr_skip(skcnt) - off_t skcnt; -#endif { - register int cnt; + int cnt; /* * loop while there is more padding to add @@ -673,20 +605,12 @@ wr_skip(skcnt) * 0, but "left" is set to be greater than zero. */ -#ifdef __STDC__ int wr_rdfile(ARCHD *arcn, int ifd, off_t *left) -#else -int -wr_rdfile(arcn, ifd, left) - ARCHD *arcn; - int ifd; - off_t *left; -#endif { - register int cnt; - register int res = 0; - register off_t size = arcn->sb.st_size; + int cnt; + int res = 0; + off_t size = arcn->sb.st_size; struct stat sb; /* @@ -742,32 +666,26 @@ wr_rdfile(arcn, ifd, left) * we return a 0 but "left" is set to be the amount unwritten */ -#ifdef __STDC__ int rd_wrfile(ARCHD *arcn, int ofd, off_t *left) -#else -int -rd_wrfile(arcn, ofd, left) - ARCHD *arcn; - int ofd; - off_t *left; -#endif { - register int cnt = 0; - register off_t size = arcn->sb.st_size; - register int res = 0; - register char *fnm = arcn->name; + int cnt = 0; + off_t size = arcn->sb.st_size; + int res = 0; + char *fnm = arcn->name; 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 (ofd < 0) + sz = PAXPATHLEN + 1; /* GNU tar long link/file */ + else if (fstat(ofd, &sb) == 0) { if (sb.st_blksize > 0) sz = (int)sb.st_blksize; } else @@ -810,7 +728,7 @@ rd_wrfile(arcn, ofd, left) /* * if the last block has a file hole (all zero), we must make sure this * gets updated in the file. We force the last block of zeros to be - * written. just closing with the file offset moved foward may not put + * 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)) @@ -838,22 +756,14 @@ rd_wrfile(arcn, ofd, left) * destination file so we can properly copy files with holes. */ -#ifdef __STDC__ void cp_file(ARCHD *arcn, int fd1, int fd2) -#else -void -cp_file(arcn, fd1, fd2) - ARCHD *arcn; - int fd1; - int fd2; -#endif { - register int cnt; - register off_t cpcnt = 0L; - register int res = 0; - register char *fnm = arcn->name; - register int no_hole = 0; + int cnt; + off_t cpcnt = 0L; + int res = 0; + char *fnm = arcn->name; + int no_hole = 0; int isem = 1; int rem; int sz = MINFBSZ; @@ -880,7 +790,7 @@ cp_file(arcn, fd1, fd2) /* * read the source file and copy to destination file until EOF */ - for(;;) { + for (;;) { if ((cnt = read(fd1, buf, blksz)) <= 0) break; if (no_hole) @@ -910,7 +820,7 @@ cp_file(arcn, fd1, fd2) /* * if the last block has a file hole (all zero), we must make sure this * gets updated in the file. We force the last block of zeros to be - * written. just closing with the file offset moved foward may not put + * written. just closing with the file offset moved forward may not put * a hole at the end of the file. */ if (!no_hole && isem && (arcn->sb.st_size > 0L)) @@ -927,21 +837,16 @@ cp_file(arcn, fd1, fd2) * 0 when finished (user specified termination in ar_next()). */ -#ifdef __STDC__ int buf_fill(void) -#else -int -buf_fill() -#endif { - register int cnt; + int cnt; static int fini = 0; if (fini) return(0); - for(;;) { + for (;;) { /* * try to fill the buffer. on error the next archive volume is * opened and we try again. @@ -977,22 +882,16 @@ buf_fill() * 0 if all is ok, -1 when a write error occurs. */ -#ifdef __STDC__ int -buf_flush(register int bufcnt) -#else -int -buf_flush(bufcnt) - register int bufcnt; -#endif +buf_flush(int bufcnt) { - register int cnt; - register int push = 0; - register int totcnt = 0; + int cnt; + int push = 0; + int totcnt = 0; /* * 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. */ diff --git a/pax/cache.c b/pax/cache.c index df58ec4..44eda1f 100644 --- a/pax/cache.c +++ b/pax/cache.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cache.c,v 1.6 1997/07/25 18:58:27 mickey Exp $ */ +/* $OpenBSD: cache.c,v 1.17 2004/03/16 03:28:34 tedu Exp $ */ /* $NetBSD: cache.c,v 1.4 1995/03/21 09:07:10 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93"; +static const char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: cache.c,v 1.6 1997/07/25 18:58:27 mickey Exp $"; +static const char rcsid[] = "$OpenBSD: cache.c,v 1.17 2004/03/16 03:28:34 tedu Exp $"; #endif #endif /* not lint */ @@ -76,18 +72,13 @@ static GIDC **grptb = NULL; /* group name to gid cache */ /* * uidtb_start - * creates an an empty uidtb + * creates an empty uidtb * Return: * 0 if ok, -1 otherwise */ -#ifdef __STDC__ int uidtb_start(void) -#else -int -uidtb_start() -#endif { static int fail = 0; @@ -105,18 +96,13 @@ uidtb_start() /* * gidtb_start - * creates an an empty gidtb + * creates an empty gidtb * Return: * 0 if ok, -1 otherwise */ -#ifdef __STDC__ int gidtb_start(void) -#else -int -gidtb_start() -#endif { static int fail = 0; @@ -134,18 +120,13 @@ gidtb_start() /* * usrtb_start - * creates an an empty usrtb + * creates an empty usrtb * Return: * 0 if ok, -1 otherwise */ -#ifdef __STDC__ int usrtb_start(void) -#else -int -usrtb_start() -#endif { static int fail = 0; @@ -163,18 +144,13 @@ usrtb_start() /* * grptb_start - * creates an an empty grptb + * creates an empty grptb * Return: * 0 if ok, -1 otherwise */ -#ifdef __STDC__ int grptb_start(void) -#else -int -grptb_start() -#endif { static int fail = 0; @@ -198,27 +174,19 @@ grptb_start() * Pointer to stored name (or a empty string) */ -#ifdef __STDC__ char * name_uid(uid_t uid, int frc) -#else -char * -name_uid(uid, frc) - uid_t uid; - int frc; -#endif { - register struct passwd *pw; - register UIDC *ptr; - register int hash; + struct passwd *pw; + UIDC *ptr; + if ((uidtb == NULL) && (uidtb_start() < 0)) return(""); /* * see if we have this uid cached */ - hash = uid % UID_SZ; - ptr = uidtb[hash]; + ptr = uidtb[uid % UID_SZ]; if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) { /* * have an entry for this uid @@ -236,24 +204,19 @@ name_uid(uid, frc) ++pwopn; } if (ptr == NULL) - ptr = (UIDC *)malloc(sizeof(UIDC)); + ptr = uidtb[uid % UID_SZ] = 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 numberic format + * 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 - uidtb[hash] = ptr; if (frc == 0) return(""); } else { @@ -263,10 +226,8 @@ name_uid(uid, frc) if (ptr == NULL) return(pw->pw_name); ptr->uid = uid; - (void)strncpy(ptr->name, pw->pw_name, UNMLEN-1); - ptr->name[UNMLEN-1] = '\0'; + (void)strlcpy(ptr->name, pw->pw_name, sizeof(ptr->name)); ptr->valid = VALID; - uidtb[hash] = ptr; } return(ptr->name); } @@ -279,19 +240,11 @@ name_uid(uid, frc) * Pointer to stored name (or a empty string) */ -#ifdef __STDC__ char * name_gid(gid_t gid, int frc) -#else -char * -name_gid(gid, frc) - gid_t gid; - int frc; -#endif { - register struct group *gr; - register GIDC *ptr; - register int hash; + struct group *gr; + GIDC *ptr; if ((gidtb == NULL) && (gidtb_start() < 0)) return(""); @@ -299,8 +252,7 @@ name_gid(gid, frc) /* * see if we have this gid cached */ - hash = gid % GID_SZ; - ptr = gidtb[hash]; + ptr = gidtb[gid % GID_SZ]; if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) { /* * have an entry for this gid @@ -318,7 +270,7 @@ name_gid(gid, frc) ++gropn; } if (ptr == NULL) - ptr = (GIDC *)malloc(sizeof(GIDC)); + ptr = gidtb[gid % GID_SZ] = malloc(sizeof(GIDC)); if ((gr = getgrgid(gid)) == NULL) { /* @@ -329,13 +281,8 @@ name_gid(gid, frc) 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 - gidtb[hash] = ptr; if (frc == 0) return(""); } else { @@ -345,10 +292,8 @@ name_gid(gid, frc) if (ptr == NULL) return(gr->gr_name); ptr->gid = gid; - (void)strncpy(ptr->name, gr->gr_name, GNMLEN-1); - ptr->name[GNMLEN-1] = '\0'; + (void)strlcpy(ptr->name, gr->gr_name, sizeof(ptr->name)); ptr->valid = VALID; - gidtb[hash] = ptr; } return(ptr->name); } @@ -360,20 +305,12 @@ name_gid(gid, frc) * the uid (if any) for a user name, or a -1 if no match can be found */ -#ifdef __STDC__ int uid_name(char *name, uid_t *uid) -#else -int -uid_name(name, uid) - char *name; - uid_t *uid; -#endif { - register struct passwd *pw; - register UIDC *ptr; - register int namelen; - register int hash; + struct passwd *pw; + UIDC *ptr; + int namelen; /* * return -1 for mangled names @@ -387,8 +324,7 @@ uid_name(name, uid) * look up in hash table, if found and valid return the uid, * if found and invalid, return a -1 */ - hash = st_hash(name, namelen, UNM_SZ); - ptr = usrtb[hash]; + ptr = usrtb[st_hash(name, namelen, UNM_SZ)]; if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { if (ptr->valid == INVALID) return(-1); @@ -402,7 +338,8 @@ uid_name(name, uid) } if (ptr == NULL) - ptr = (UIDC *)malloc(sizeof(UIDC)); + ptr = usrtb[st_hash(name, namelen, UNM_SZ)] = + (UIDC *)malloc(sizeof(UIDC)); /* * no match, look it up, if no match store it as an invalid entry, @@ -414,9 +351,7 @@ uid_name(name, uid) *uid = pw->pw_uid; return(0); } - usrtb[hash] = ptr; - (void)strncpy(ptr->name, name, UNMLEN-1); - ptr->name[UNMLEN-1] = '\0'; + (void)strlcpy(ptr->name, name, sizeof(ptr->name)); if ((pw = getpwnam(name)) == NULL) { ptr->valid = INVALID; return(-1); @@ -433,20 +368,12 @@ uid_name(name, uid) * the gid (if any) for a group name, or a -1 if no match can be found */ -#ifdef __STDC__ int gid_name(char *name, gid_t *gid) -#else -int -gid_name(name, gid) - char *name; - gid_t *gid; -#endif { - register struct group *gr; - register GIDC *ptr; - register int namelen; - register int hash; + struct group *gr; + GIDC *ptr; + int namelen; /* * return -1 for mangled names @@ -460,8 +387,7 @@ gid_name(name, gid) * look up in hash table, if found and valid return the uid, * if found and invalid, return a -1 */ - hash = st_hash(name, namelen, GID_SZ); - ptr = grptb[hash]; + ptr = grptb[st_hash(name, namelen, GID_SZ)]; if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { if (ptr->valid == INVALID) return(-1); @@ -474,7 +400,8 @@ gid_name(name, gid) ++gropn; } if (ptr == NULL) - ptr = (GIDC *)malloc(sizeof(GIDC)); + ptr = grptb[st_hash(name, namelen, GID_SZ)] = + (GIDC *)malloc(sizeof(GIDC)); /* * no match, look it up, if no match store it as an invalid entry, @@ -487,9 +414,7 @@ gid_name(name, gid) return(0); } - grptb[hash] = ptr; - (void)strncpy(ptr->name, name, GNMLEN-1); - ptr->name[GNMLEN-1] = '\0'; + (void)strlcpy(ptr->name, name, sizeof(ptr->name)); if ((gr = getgrnam(name)) == NULL) { ptr->valid = INVALID; return(-1); diff --git a/pax/cache.h b/pax/cache.h index 01283ef..5c7b9b8 100644 --- a/pax/cache.h +++ b/pax/cache.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cache.h,v 1.2 1996/06/23 14:20:31 deraadt Exp $ */ +/* $OpenBSD: cache.h,v 1.4 2003/10/20 06:22:27 jmc Exp $ */ /* $NetBSD: cache.h,v 1.3 1995/03/21 09:07:12 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -45,7 +41,7 @@ * 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 adress this problem, these routines + * 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 diff --git a/pax/cpio.1 b/pax/cpio.1 index 639bc07..296205a 100644 --- a/pax/cpio.1 +++ b/pax/cpio.1 @@ -1,3 +1,4 @@ +.\" $OpenBSD: cpio.1,v 1.20 2003/11/21 20:54:02 jmc 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,7 +23,7 @@ .\" (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.3 1997/04/06 06:11:11 millert Exp $ +.\" $OpenBSD: cpio.1,v 1.20 2003/11/21 20:54:02 jmc Exp $ .\" .Dd February 16, 1997 .Dt CPIO 1 @@ -36,7 +32,7 @@ .Nm cpio .Nd copy file archives in and out .Sh SYNOPSIS -.Nm +.Nm cpio .Fl o .Op Fl aABcLvzZ .Op Fl C Ar bytes @@ -45,7 +41,7 @@ .Op Fl O Ar archive .Ar "< name-list" .Op Ar "> archive" -.Nm +.Nm cpio .Fl i .Op Fl bBcdfmrsStuvzZ6 .Op Fl C Ar bytes @@ -55,52 +51,59 @@ .Op Fl I Ar archive .Op Ar "pattern ..." .Op Ar "< archive" -.Nm +.Nm cpio .Fl p .Op Fl adlLmuv .Ar destination-directory .Ar "< name-list" .Sh DESCRIPTION The -.Nm +.Nm cpio command copies files to and from a -.Nm +.Nm cpio archive. .Pp -The following options are supported: -.Bl -tag -width Fl +The options are as follows: +.Bl -tag -width Ds .It Fl o -Create an archive. Reads the list of files to store in the +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 Fl -.It Fl a -Reset the access times on files that has been copied to the -archive. +.Bl -tag -width Ds .It Fl A Append to the specified archive. +.It Fl a +Reset the access times on files that have been copied to the +archive. .It Fl B Set block size of output to 5120 bytes. -.It Fl c -Use ASCII format for -.Nm -header for portability. .It Fl C Ar bytes Set the block size of output to .Ar bytes . +.It Fl c +Use ASCII format for +.Nm cpio +header for portability. .It Fl F Ar archive -.It Fl O Ar archive Use the specified file name as the archive to write to. .It Fl H Ar format -Write the archive in the specified format. Recognized -formats are: -.Bl -tag -width Ds +Write the archive in the specified format. +Recognized formats are: +.Pp +.Bl -tag -width sv4cpio -compact .It Ar bcpio -Old binary cpio format. +Old binary +.Nm cpio +format. .It Ar cpio -Old octal character cpio format. +Old octal character +.Nm cpio +format. .It Ar sv4cpio -SVR4 hex cpio format. +SVR4 hex +.Nm cpio +format. .It Ar tar Old tar format. .It Ar ustar @@ -108,71 +111,86 @@ POSIX ustar format. .El .It Fl L Follow symbolic links. +.It Fl O Ar archive +Use the specified file name as the archive to write to. .It Fl v -Be verbose about operations. List filenames as they are -written to the archive. -.It Fl z -Compress archive using -.Xr gzip 1 -format. +Be verbose about operations. +List filenames as they are written to the archive. .It Fl Z Compress archive using .Xr compress 1 format. +.It Fl z +Compress archive using +.Xr gzip 1 +format. .El .It Fl i -Restore files from an archive. Reads the archive file from +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 Fl -.It Fl b -Do byte- and word swapping after reading in data from the -archive, for restoring archives created on systems with -different byte order. +.Bl -tag -width Ds +.It Fl 6 +Process old-style +.Nm cpio +format archives. .It Fl B Set the block size of the archive being read to 5120 bytes. -.It Fl c -Expect the archive headers to be in ASCII format. +.It Fl b +Do byte and word swapping after reading in data from the +archive, for restoring archives created on systems with +a different byte order. .It Fl C Ar bytes -Read archive written with a blocksize of +Read archive written with a block size of .Ar bytes . +.It Fl c +Expect the archive headers to be in ASCII format. .It Fl d Create any intermediate directories as needed during restore. .It Fl E Ar file -Read list of file name patters to extract or list from +Read list of file name patterns to extract or list from .Ar file . +.It Fl F Ar archive +Use the specified file as the input for the archive. .It Fl f Restore all files except those matching the .Ar patterns given on the command line. -.It Fl F Ar archive -.It Fl I Ar archive -Use the specified file as the input for the archive. .It Fl H Ar format -Read an archive of the specified format. Recognized -formats are: -.Bl -tag -width Ds +Read an archive of the specified format. +Recognized formats are: +.Pp +.Bl -tag -width sv4cpio -compact .It Ar bcpio -Old binary cpio format. +Old binary +.Nm cpio +format. .It Ar cpio -Old octal character cpio format. +Old octal character +.Nm cpio +format. .It Ar sv4cpio -SVR4 hex cpio format. +SVR4 hex +.Nm cpio +format. .It Ar tar Old tar format. .It Ar ustar POSIX ustar format. .El +.It Fl I Ar archive +Use the specified file as the input for the archive. .It Fl m Restore modification times on files. .It Fl r Rename restored files interactively. -.It Fl s -Swap bytes after reading data from the archive. .It Fl S Swap words after reading data from the archive. +.It Fl s +Swap bytes after reading data from the archive. .It Fl t Only list the contents of the archive, no files or directories will be created. @@ -180,73 +198,78 @@ directories will be created. Overwrite files even when the file in the archive is older than the one that will be overwritten. .It Fl v -Be verbose about operations. List filenames as they are -copied in from the archive. -.It Fl z -Uncompress archive using -.Xr gzip 1 -format. +Be verbose about operations. +List filenames as they are copied in from the archive. .It Fl Z Uncompress archive using .Xr compress 1 format. -.It Fl 6 -Process old-style \*Qcpio\*U format archives. +.It Fl z +Uncompress archive using +.Xr gzip 1 +format. .El .It Fl p Copy files from one location to another in a single pass. -The list of files to copy are read from standard in and +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 Fl +By default, an older file will not replace a newer file with the same name. +.Bl -tag -width Ds .It Fl a -Reset the access times on files that has been copied. +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 +Follow symbolic links. .It Fl l When possible, link files rather than creating an extra copy. -.It Fl L -Follow symbolic links. .It Fl m Restore modification times on files. .It Fl u Overwrite files even when the original file being copied is older than the one that will be overwritten. .It Fl v -Be verbose about operations. List filenames as they are -copied. +Be verbose about operations. +List filenames as they are copied. +.El .El +.Sh ENVIRONMENT +.Bl -tag -width Fl +.It Ev TMPDIR +Path in which to store temporary files. .El .Sh ERRORS -.Nm +.Nm cpio will exit with one of the following values: .Bl -tag -width 2n .It 0 All files were processed successfully. .It 1 -An error occured. +An error occurred. .El .Pp Whenever -.Nm +.Nm cpio cannot create a file or a link when extracting an archive or cannot find a file while writing an archive, or cannot preserve the user -ID, group ID, file mode or access and modification times when the +ID, group ID, file mode, or access and modification times when the .Fl p -options is specified, a diagnostic message is written to standard +option is specified, a diagnostic message is written to standard error and a non-zero exit value will be returned, but processing -will continue. In the case where -.Nm +will continue. +In the case where +.Nm cpio cannot create a link to a file, -.Nm +.Nm cpio will not create a second copy of the file. .Pp If the extraction of a file from an archive is prematurely terminated by a signal or error, -.Nm +.Nm cpio may have only partially extracted the file the user wanted. Additionally, the file modes of extracted files and directories may have incorrect file bits, and the modification and access times may @@ -254,17 +277,17 @@ be wrong. .Pp If the creation of an archive is prematurely terminated by a signal or error, -.Nm -may have only partially created the archive which may violate the +.Nm cpio +may have only partially created the archive, which may violate the specific archive format specification. .Sh SEE ALSO .Xr pax 1 , .Xr tar 1 +.Sh AUTHORS +Keith Muller at the University of California, San Diego. .Sh BUGS -The +The .Fl s and .Fl S options are currently not implemented. -.Sh AUTHOR -Keith Muller at the University of California, San Diego diff --git a/pax/cpio.c b/pax/cpio.c index 43feb64..058b8e3 100644 --- a/pax/cpio.c +++ b/pax/cpio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpio.c,v 1.5 1997/07/25 18:58:28 mickey Exp $ */ +/* $OpenBSD: cpio.c,v 1.17 2004/04/16 22:50:23 deraadt Exp $ */ /* $NetBSD: cpio.c,v 1.5 1995/03/21 09:07:13 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)cpio.c 8.1 (Berkeley) 5/31/93"; +static const char sccsid[] = "@(#)cpio.c 8.1 (Berkeley) 5/31/93"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: cpio.c,v 1.5 1997/07/25 18:58:28 mickey Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: cpio.c,v 1.17 2004/04/16 22:50:23 deraadt Exp $"; #endif #endif /* not lint */ @@ -58,9 +54,9 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: cpio.c,v 1.5 1997/0 #include "cpio.h" #include "extern.h" -static int rd_nm __P((register ARCHD *, int)); -static int rd_ln_nm __P((register ARCHD *)); -static int com_rd __P((register ARCHD *)); +static int rd_nm(ARCHD *, int); +static int rd_ln_nm(ARCHD *); +static int com_rd(ARCHD *); /* * Routines which support the different cpio versions @@ -79,13 +75,8 @@ static int swp_head; /* binary cpio header byte swap */ * 0 if ok -1 otherwise (the return values of lnk_start()) */ -#ifdef __STDC__ int cpio_strd(void) -#else -int -cpio_strd() -#endif { return(lnk_start()); } @@ -97,17 +88,11 @@ cpio_strd() * mode; looking for a valid header), and cnt (which starts at zero) * which is used to count the number of empty blocks we have seen so far. * Return: - * 0 if a valid trailer, -1 if not a valid trailer, + * 0 if a valid trailer, -1 if not a valid trailer, */ -#ifdef __STDC__ -int -cpio_trail(register ARCHD *arcn) -#else int -cpio_trail(arcn) - register ARCHD *arcn; -#endif +cpio_trail(ARCHD *arcn, char *notused, int notused2, int *notused3) { /* * look for trailer id in file we are about to process @@ -124,19 +109,13 @@ cpio_trail(arcn) * 0 */ -#ifdef __STDC__ -static int -com_rd(register ARCHD *arcn) -#else static int -com_rd(arcn) - register ARCHD *arcn; -#endif +com_rd(ARCHD *arcn) { arcn->skip = 0; arcn->pat = NULL; arcn->org_name = arcn->name; - switch(arcn->sb.st_mode & C_IFMT) { + switch (arcn->sb.st_mode & C_IFMT) { case C_ISFIFO: arcn->type = PAX_FIF; break; @@ -179,13 +158,8 @@ com_rd(arcn) * result of the write of the trailer from the cpio specific write func */ -#ifdef __STDC__ int cpio_endwr(void) -#else -int -cpio_endwr() -#endif { ARCHD last; @@ -196,7 +170,7 @@ cpio_endwr() last.nlen = sizeof(TRAILER) - 1; last.type = PAX_REG; last.sb.st_nlink = 1; - (void)strcpy(last.name, TRAILER); + (void)strlcpy(last.name, TRAILER, sizeof(last.name)); return((*frmt->wr)(&last)); } @@ -207,15 +181,8 @@ cpio_endwr() * 0 if ok, -1 otherwise */ -#ifdef __STDC__ static int -rd_nm(register ARCHD *arcn, int nsz) -#else -static int -rd_nm(arcn, nsz) - register ARCHD *arcn; - int nsz; -#endif +rd_nm(ARCHD *arcn, int nsz) { /* * do not even try bogus values @@ -244,21 +211,15 @@ rd_nm(arcn, nsz) * 0 if ok, -1 otherwise */ -#ifdef __STDC__ -static int -rd_ln_nm(register ARCHD *arcn) -#else static int -rd_ln_nm(arcn) - register ARCHD *arcn; -#endif +rd_ln_nm(ARCHD *arcn) { /* * check the length specified for bogus values */ if ((arcn->sb.st_size == 0) || (arcn->sb.st_size >= sizeof(arcn->ln_name))) { -# ifdef NET2_STAT +# ifdef LONG_OFF_T paxwarn(1, "Cpio link name length is invalid: %lu", arcn->sb.st_size); # else @@ -301,15 +262,8 @@ rd_ln_nm(arcn) * 0 if a valid header, -1 otherwise */ -#ifdef __STDC__ int cpio_id(char *blk, int size) -#else -int -cpio_id(blk, size) - char *blk; - int size; -#endif { if ((size < sizeof(HD_CPIO)) || (strncmp(blk, AMAGIC, sizeof(AMAGIC) - 1) != 0)) @@ -325,18 +279,11 @@ cpio_id(blk, size) * 0 if a valid header, -1 otherwise. */ -#ifdef __STDC__ -int -cpio_rd(register ARCHD *arcn, register char *buf) -#else int -cpio_rd(arcn, buf) - register ARCHD *arcn; - register char *buf; -#endif +cpio_rd(ARCHD *arcn, char *buf) { - register int nsz; - register HD_CPIO *hd; + int nsz; + HD_CPIO *hd; /* * check that this is a valid header, if not return -1 @@ -361,7 +308,7 @@ cpio_rd(arcn, buf) arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime, sizeof(hd->c_mtime), OCT); arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; -# ifdef NET2_STAT +# ifdef LONG_OFF_T arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,sizeof(hd->c_filesize), OCT); # else @@ -381,8 +328,8 @@ cpio_rd(arcn, buf) 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)); @@ -408,13 +355,8 @@ cpio_rd(arcn, buf) * size of trailer header in this format */ -#ifdef __STDC__ off_t cpio_endrd(void) -#else -off_t -cpio_endrd() -#endif { return((off_t)(sizeof(HD_CPIO) + sizeof(TRAILER))); } @@ -426,13 +368,8 @@ cpio_endrd() * 0 if ok, -1 otherwise (what dev_start() returns) */ -#ifdef __STDC__ int cpio_stwr(void) -#else -int -cpio_stwr() -#endif { return(dev_start()); } @@ -446,17 +383,11 @@ cpio_stwr() * data to write after the header, -1 if archive write failed */ -#ifdef __STDC__ int -cpio_wr(register ARCHD *arcn) -#else -int -cpio_wr(arcn) - register ARCHD *arcn; -#endif +cpio_wr(ARCHD *arcn) { - register HD_CPIO *hd; - register int nsz; + HD_CPIO *hd; + int nsz; char hdblk[sizeof(HD_CPIO)]; /* @@ -471,14 +402,14 @@ cpio_wr(arcn) if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR)) arcn->sb.st_rdev = 0; - switch(arcn->type) { + switch (arcn->type) { case PAX_CTG: case PAX_REG: case PAX_HRG: /* * set data size for file data */ -# ifdef NET2_STAT +# ifdef LONG_OFF_T if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize, sizeof(hd->c_filesize), OCT)) { # else @@ -576,21 +507,14 @@ cpio_wr(arcn) /* * vcpio_id() * 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 + * WITHOUT crc. WATCH it the magic cookies are in OCTAL, the header * uses HEX * Return: * 0 if a valid header, -1 otherwise */ -#ifdef __STDC__ int vcpio_id(char *blk, int size) -#else -int -vcpio_id(blk, size) - char *blk; - int size; -#endif { if ((size < sizeof(HD_VCPIO)) || (strncmp(blk, AVMAGIC, sizeof(AVMAGIC) - 1) != 0)) @@ -606,15 +530,8 @@ vcpio_id(blk, size) * 0 if a valid header, -1 otherwise */ -#ifdef __STDC__ int crc_id(char *blk, int size) -#else -int -crc_id(blk, size) - char *blk; - int size; -#endif { if ((size < sizeof(HD_VCPIO)) || (strncmp(blk, AVCMAGIC, sizeof(AVCMAGIC) - 1) != 0)) @@ -629,13 +546,8 @@ crc_id(blk, size) * 0 if ok -1 otherwise (the return values of lnk_start()) */ -#ifdef __STDC__ int crc_strd(void) -#else -int -crc_strd() -#endif { docrc = 1; return(lnk_start()); @@ -649,20 +561,13 @@ crc_strd() * 0 if a valid header, -1 otherwise. */ -#ifdef __STDC__ -int -vcpio_rd(register ARCHD *arcn, register char *buf) -#else int -vcpio_rd(arcn, buf) - register ARCHD *arcn; - register char *buf; -#endif +vcpio_rd(ARCHD *arcn, char *buf) { - register HD_VCPIO *hd; + HD_VCPIO *hd; dev_t devminor; dev_t devmajor; - register int nsz; + int nsz; /* * during the id phase it was determined if we were using CRC, use the @@ -688,7 +593,7 @@ vcpio_rd(arcn, buf) arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), HEX); arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime,sizeof(hd->c_mtime),HEX); arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; -# ifdef NET2_STAT +# ifdef LONG_OFF_T arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize, sizeof(hd->c_filesize), HEX); # else @@ -716,7 +621,7 @@ vcpio_rd(arcn, buf) 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); @@ -755,13 +660,8 @@ vcpio_rd(arcn, buf) * size of trailer header in this format */ -#ifdef __STDC__ off_t vcpio_endrd(void) -#else -off_t -vcpio_endrd() -#endif { return((off_t)(sizeof(HD_VCPIO) + sizeof(TRAILER) + (VCPIO_PAD(sizeof(HD_VCPIO) + sizeof(TRAILER))))); @@ -774,13 +674,8 @@ vcpio_endrd() * 0 if ok, -1 otherwise (what dev_start() returns) */ -#ifdef __STDC__ int crc_stwr(void) -#else -int -crc_stwr() -#endif { docrc = 1; return(dev_start()); @@ -795,16 +690,10 @@ crc_stwr() * NO data to write after the header, -1 if archive write failed */ -#ifdef __STDC__ -int -vcpio_wr(register ARCHD *arcn) -#else int -vcpio_wr(arcn) - register ARCHD *arcn; -#endif +vcpio_wr(ARCHD *arcn) { - register HD_VCPIO *hd; + HD_VCPIO *hd; unsigned int nsz; char hdblk[sizeof(HD_VCPIO)]; @@ -825,18 +714,18 @@ vcpio_wr(arcn) */ if (docrc) { if (ul_asc((u_long)VCMAGIC, hd->c_magic, sizeof(hd->c_magic), - OCT) || + OCT) || ul_asc((u_long)arcn->crc,hd->c_chksum,sizeof(hd->c_chksum), - HEX)) + HEX)) goto out; } else { if (ul_asc((u_long)VMAGIC, hd->c_magic, sizeof(hd->c_magic), - OCT) || + OCT) || ul_asc((u_long)0L, hd->c_chksum, sizeof(hd->c_chksum),HEX)) goto out; } - switch(arcn->type) { + switch (arcn->type) { case PAX_CTG: case PAX_REG: case PAX_HRG: @@ -845,7 +734,7 @@ vcpio_wr(arcn) * much to pad. */ arcn->pad = VCPIO_PAD(arcn->sb.st_size); -# ifdef NET2_STAT +# ifdef LONG_OFF_T if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize, sizeof(hd->c_filesize), HEX)) { # else @@ -888,11 +777,11 @@ vcpio_wr(arcn) ul_asc((u_long)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) || + HEX) || ul_asc((u_long)arcn->sb.st_mtime, hd->c_mtime, sizeof(hd->c_mtime), - HEX) || + HEX) || ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink), - HEX) || + HEX) || ul_asc((u_long)MAJOR(arcn->sb.st_dev),hd->c_maj, sizeof(hd->c_maj), HEX) || ul_asc((u_long)MINOR(arcn->sb.st_dev),hd->c_min, sizeof(hd->c_min), @@ -958,15 +847,8 @@ vcpio_wr(arcn) * 0 if a valid header, -1 otherwise */ -#ifdef __STDC__ int bcpio_id(char *blk, int size) -#else -int -bcpio_id(blk, size) - char *blk; - int size; -#endif { if (size < sizeof(HD_BCPIO)) return(-1); @@ -993,18 +875,11 @@ bcpio_id(blk, size) * 0 if a valid header, -1 otherwise. */ -#ifdef __STDC__ -int -bcpio_rd(register ARCHD *arcn, register char *buf) -#else int -bcpio_rd(arcn, buf) - register ARCHD *arcn; - register char *buf; -#endif +bcpio_rd(ARCHD *arcn, char *buf) { - register HD_BCPIO *hd; - register int nsz; + HD_BCPIO *hd; + int nsz; /* * check the header @@ -1016,7 +891,7 @@ bcpio_rd(arcn, buf) hd = (HD_BCPIO *)buf; if (swp_head) { /* - * header has swapped bytes on 16 bit boundries + * header has swapped bytes on 16 bit boundaries */ arcn->sb.st_dev = (dev_t)(RSHRT_EXT(hd->h_dev)); arcn->sb.st_ino = (ino_t)(RSHRT_EXT(hd->h_ino)); @@ -1061,7 +936,7 @@ bcpio_rd(arcn, buf) 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); @@ -1097,13 +972,8 @@ bcpio_rd(arcn, buf) * size of trailer header in this format */ -#ifdef __STDC__ off_t bcpio_endrd(void) -#else -off_t -bcpio_endrd() -#endif { return((off_t)(sizeof(HD_BCPIO) + sizeof(TRAILER) + (BCPIO_PAD(sizeof(HD_BCPIO) + sizeof(TRAILER))))); @@ -1113,24 +983,18 @@ bcpio_endrd() * 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 * data to write after the header, -1 if archive write failed */ -#ifdef __STDC__ int -bcpio_wr(register ARCHD *arcn) -#else -int -bcpio_wr(arcn) - register ARCHD *arcn; -#endif +bcpio_wr(ARCHD *arcn) { - register HD_BCPIO *hd; - register int nsz; + HD_BCPIO *hd; + int nsz; char hdblk[sizeof(HD_BCPIO)]; off_t t_offt; int t_int; @@ -1147,7 +1011,7 @@ bcpio_wr(arcn) arcn->sb.st_rdev = 0; hd = (HD_BCPIO *)hdblk; - switch(arcn->type) { + switch (arcn->type) { case PAX_CTG: case PAX_REG: case PAX_HRG: diff --git a/pax/cpio.h b/pax/cpio.h index 811f8f3..dfbd03f 100644 --- a/pax/cpio.h +++ b/pax/cpio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpio.h,v 1.2 1996/06/23 14:20:32 deraadt Exp $ */ +/* $OpenBSD: cpio.h,v 1.4 2003/06/02 23:32:08 millert Exp $ */ /* $NetBSD: cpio.h,v 1.3 1995/03/21 09:07:15 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -73,7 +69,7 @@ typedef struct { char c_mtime[11]; /* modification time */ char c_namesize[6]; /* length of pathname */ char c_filesize[11]; /* length of file in bytes */ -} HD_CPIO; +} HD_CPIO; #define MAGIC 070707 /* transportable archive id */ @@ -84,7 +80,7 @@ typedef struct { #endif /* _PAX_ */ /* - * Binary cpio header structure + * Binary cpio header structure * * CAUTION! CAUTION! CAUTION! * Each field really represents a 16 bit short (NOT ASCII). Described as @@ -104,7 +100,7 @@ typedef struct { u_char h_namesize[2]; u_char h_filesize_1[2]; u_char h_filesize_2[2]; -} HD_BCPIO; +} HD_BCPIO; #ifdef _PAX_ /* @@ -142,7 +138,7 @@ typedef struct { char c_rmin[8]; /* special file minor # */ char c_namesize[8]; /* length of pathname */ char c_chksum[8]; /* 0 OR CRC of bytes of FILE data */ -} HD_VCPIO; +} HD_VCPIO; #define VMAGIC 070701 /* sVr4 new portable archive id */ #define VCMAGIC 070702 /* sVr4 new portable archive id CRC */ diff --git a/pax/extern.h b/pax/extern.h dissimilarity index 65% index 478152c..01f4f2a 100644 --- a/pax/extern.h +++ b/pax/extern.h @@ -1,299 +1,331 @@ -/* $OpenBSD: extern.h,v 1.14 1997/07/24 23:19:18 millert Exp $ */ -/* $NetBSD: extern.h,v 1.5 1996/03/26 23:54:16 mrg Exp $ */ - -/*- - * Copyright (c) 1992 Keith Muller. - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Keith Muller of the University of California, San Diego. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. - * - * @(#)extern.h 8.2 (Berkeley) 4/18/94 - */ - -/* - * External references from each source file - */ - -#include - -/* - * ar_io.c - */ -extern char *arcname; -extern char *gzip_program; -int ar_open __P((char *)); -void ar_close __P((void)); -void ar_drain __P((void)); -int ar_set_wr __P((void)); -int ar_app_ok __P((void)); -int ar_read __P((register char *, register int)); -int ar_write __P((register char *, register int)); -int ar_rdsync __P((void)); -int ar_fow __P((off_t, off_t *)); -int ar_rev __P((off_t )); -int ar_next __P((void)); - -/* - * ar_subs.c - */ -extern u_long flcnt; -void list __P((void)); -void extract __P((void)); -void append __P((void)); -void archive __P((void)); -void copy __P((void)); - -/* - * buf_subs.c - */ -extern int blksz; -extern int wrblksz; -extern int maxflt; -extern int rdblksz; -extern off_t wrlimit; -extern off_t rdcnt; -extern off_t wrcnt; -int wr_start __P((void)); -int rd_start __P((void)); -void cp_start __P((void)); -int appnd_start __P((off_t)); -int rd_sync __P((void)); -void pback __P((char *, int)); -int rd_skip __P((off_t)); -void wr_fin __P((void)); -int wr_rdbuf __P((register char *, register int)); -int rd_wrbuf __P((register char *, register int)); -int wr_skip __P((off_t)); -int wr_rdfile __P((ARCHD *, int, off_t *)); -int rd_wrfile __P((ARCHD *, int, off_t *)); -void cp_file __P((ARCHD *, int, int)); -int buf_fill __P((void)); -int buf_flush __P((register int)); - -/* - * cache.c - */ -int uidtb_start __P((void)); -int gidtb_start __P((void)); -int usrtb_start __P((void)); -int grptb_start __P((void)); -char * name_uid __P((uid_t, int)); -char * name_gid __P((gid_t, int)); -int uid_name __P((char *, uid_t *)); -int gid_name __P((char *, gid_t *)); - -/* - * cpio.c - */ -int cpio_strd __P((void)); -int cpio_trail __P((register ARCHD *)); -int cpio_endwr __P((void)); -int cpio_id __P((char *, int)); -int cpio_rd __P((register ARCHD *, register char *)); -off_t cpio_endrd __P((void)); -int cpio_stwr __P((void)); -int cpio_wr __P((register ARCHD *)); -int vcpio_id __P((char *, int)); -int crc_id __P((char *, int)); -int crc_strd __P((void)); -int vcpio_rd __P((register ARCHD *, register char *)); -off_t vcpio_endrd __P((void)); -int crc_stwr __P((void)); -int vcpio_wr __P((register ARCHD *)); -int bcpio_id __P((char *, int)); -int bcpio_rd __P((register ARCHD *, register char *)); -off_t bcpio_endrd __P((void)); -int bcpio_wr __P((register ARCHD *)); - -/* - * file_subs.c - */ -int file_creat __P((register ARCHD *)); -void file_close __P((register ARCHD *, int)); -int lnk_creat __P((register ARCHD *)); -int cross_lnk __P((register ARCHD *)); -int chk_same __P((register ARCHD *)); -int node_creat __P((register ARCHD *)); -int unlnk_exist __P((register char *, register int)); -int chk_path __P((register char *, uid_t, gid_t)); -void set_ftime __P((char *fnm, time_t mtime, time_t atime, int frc)); -int set_ids __P((char *, uid_t, gid_t)); -int set_lids __P((char *, uid_t, gid_t)); -void set_pmode __P((char *, mode_t)); -int file_write __P((int, char *, register int, int *, int *, int, char *)); -void file_flush __P((int, char *, int)); -void rdfile_close __P((register ARCHD *, register int *)); -int set_crc __P((register ARCHD *, register int)); - -/* - * ftree.c - */ -int ftree_start __P((void)); -int ftree_add __P((register char *, int)); -void ftree_sel __P((register ARCHD *)); -void ftree_chk __P((void)); -int next_file __P((register ARCHD *)); - -/* - * gen_subs.c - */ -void ls_list __P((register ARCHD *, time_t, FILE *)); -void ls_tty __P((register ARCHD *)); -int l_strncpy __P((register char *, register char *, int)); -u_long asc_ul __P((register char *, int, register int)); -int ul_asc __P((u_long, register char *, register int, register int)); -#ifndef NET2_STAT -u_quad_t asc_uqd __P((register char *, int, register int)); -int uqd_asc __P((u_quad_t, register char *, register int, register int)); -#endif - -/* - * getoldopt.c - */ -int getoldopt __P((int, char **, char *)); - -/* - * options.c - */ -extern FSUB fsub[]; -extern int ford[]; -void options __P((register int, register char **)); -OPLIST * opt_next __P((void)); -int opt_add __P((register char *)); -int bad_opt __P((void)); -extern char *chdname; - -/* - * pat_rep.c - */ -int rep_add __P((register char *)); -int pat_add __P((char *, char *)); -void pat_chk __P((void)); -int pat_sel __P((register ARCHD *)); -int pat_match __P((register ARCHD *)); -int mod_name __P((register ARCHD *)); -int set_dest __P((register ARCHD *, char *, int)); - -/* - * pax.c - */ -extern int act; -extern FSUB *frmt; -extern int cflag; -extern int cwdfd; -extern int dflag; -extern int iflag; -extern int kflag; -extern int lflag; -extern int nflag; -extern int tflag; -extern int uflag; -extern int vflag; -extern int zflag; -extern int Dflag; -extern int Hflag; -extern int Lflag; -extern int Xflag; -extern int Yflag; -extern int Zflag; -extern int vfpart; -extern int patime; -extern int pmtime; -extern int nodirs; -extern int pmode; -extern int pids; -extern int rmleadslash; -extern int exit_val; -extern int docrc; -extern char *dirptr; -extern char *ltmfrmt; -extern char *argv0; -int main __P((int, char **)); -void sig_cleanup __P((int)); - -/* - * sel_subs.c - */ -int sel_chk __P((register ARCHD *)); -int grp_add __P((register char *)); -int usr_add __P((register char *)); -int trng_add __P((register char *)); - -/* - * tables.c - */ -int lnk_start __P((void)); -int chk_lnk __P((register ARCHD *)); -void purg_lnk __P((register ARCHD *)); -void lnk_end __P((void)); -int ftime_start __P((void)); -int chk_ftime __P((register ARCHD *)); -int name_start __P((void)); -int add_name __P((register char *, int, char *)); -void sub_name __P((register char *, int *, size_t)); -int dev_start __P((void)); -int add_dev __P((register ARCHD *)); -int map_dev __P((register ARCHD *, u_long, u_long)); -int atdir_start __P((void)); -void atdir_end __P((void)); -void add_atdir __P((char *, dev_t, ino_t, time_t, time_t)); -int get_atdir __P((dev_t, ino_t, time_t *, time_t *)); -int dir_start __P((void)); -void add_dir __P((char *, int, struct stat *, int)); -void proc_dir __P((void)); -u_int st_hash __P((char *, int, int)); - -/* - * tar.c - */ -int tar_endwr __P((void)); -off_t tar_endrd __P((void)); -int tar_trail __P((register char *, register int, register int *)); -int tar_id __P((register char *, int)); -int tar_opt __P((void)); -int tar_rd __P((register ARCHD *, register char *)); -int tar_wr __P((register ARCHD *)); -int ustar_strd __P((void)); -int ustar_stwr __P((void)); -int ustar_id __P((char *, int)); -int ustar_rd __P((register ARCHD *, register char *)); -int ustar_wr __P((register ARCHD *)); - -/* - * tty_subs.c - */ -int tty_init __P((void)); -void tty_prnt __P((char *, ...)); -int tty_read __P((char *, int)); -void paxwarn __P((int, char *, ...)); -void syswarn __P((int, int, char *, ...)); +/* $OpenBSD: extern.h,v 1.29 2004/11/29 16:23:22 otto Exp $ */ +/* $NetBSD: extern.h,v 1.5 1996/03/26 23:54:16 mrg Exp $ */ + +/*- + * Copyright (c) 1992 Keith Muller. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.2 (Berkeley) 4/18/94 + */ + +/* + * External references from each source file + */ + +#include + +/* + * ar_io.c + */ +extern const char *arcname; +extern const char *gzip_program; +extern int force_one_volume; +int ar_open(const char *); +void ar_close(void); +void ar_drain(void); +int ar_set_wr(void); +int ar_app_ok(void); +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); + +/* + * ar_subs.c + */ +extern u_long flcnt; +void list(void); +void extract(void); +void append(void); +void archive(void); +void copy(void); + +/* + * buf_subs.c + */ +extern int blksz; +extern int wrblksz; +extern int maxflt; +extern int rdblksz; +extern off_t wrlimit; +extern off_t rdcnt; +extern off_t wrcnt; +int wr_start(void); +int rd_start(void); +void cp_start(void); +int appnd_start(off_t); +int rd_sync(void); +void pback(char *, int); +int rd_skip(off_t); +void wr_fin(void); +int wr_rdbuf(char *, int); +int rd_wrbuf(char *, int); +int wr_skip(off_t); +int wr_rdfile(ARCHD *, int, off_t *); +int rd_wrfile(ARCHD *, int, off_t *); +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); +char * name_uid(uid_t, int); +char * name_gid(gid_t, int); +int uid_name(char *, uid_t *); +int gid_name(char *, gid_t *); + +/* + * cpio.c + */ +int cpio_strd(void); +int cpio_trail(ARCHD *, char *, int, int *); +int cpio_endwr(void); +int cpio_id(char *, int); +int cpio_rd(ARCHD *, char *); +off_t cpio_endrd(void); +int cpio_stwr(void); +int cpio_wr(ARCHD *); +int vcpio_id(char *, int); +int crc_id(char *, int); +int crc_strd(void); +int vcpio_rd(ARCHD *, char *); +off_t vcpio_endrd(void); +int crc_stwr(void); +int vcpio_wr(ARCHD *); +int bcpio_id(char *, int); +int bcpio_rd(ARCHD *, char *); +off_t bcpio_endrd(void); +int bcpio_wr(ARCHD *); + +/* + * file_subs.c + */ +extern char *gnu_name_string, *gnu_link_string; +int file_creat(ARCHD *); +void file_close(ARCHD *, int); +int lnk_creat(ARCHD *); +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, char **); +void set_ftime(char *fnm, time_t mtime, time_t atime, int frc); +int set_ids(char *, uid_t, gid_t); +int set_lids(char *, uid_t, gid_t); +void set_pmode(char *, mode_t); +int file_write(int, char *, int, int *, int *, int, char *); +void file_flush(int, char *, int); +void rdfile_close(ARCHD *, int *); +int set_crc(ARCHD *, int); + +/* + * ftree.c + */ +int ftree_start(void); +int ftree_add(char *, int); +void ftree_sel(ARCHD *); +void ftree_chk(void); +int next_file(ARCHD *); + +/* + * gen_subs.c + */ +void ls_list(ARCHD *, time_t, FILE *); +void ls_tty(ARCHD *); +void safe_print(const char *, FILE *); +u_long asc_ul(char *, int, int); +int ul_asc(u_long, char *, int, int); +#ifndef LONG_OFF_T +u_quad_t asc_uqd(char *, int, int); +int uqd_asc(u_quad_t, char *, int, int); +#endif + +/* + * getoldopt.c + */ +int getoldopt(int, char **, const char *); + +/* + * options.c + */ +extern FSUB fsub[]; +extern int ford[]; +void options(int, char **); +OPLIST * opt_next(void); +int opt_add(const char *); +int bad_opt(void); +int pax_format_opt_add (char *); +int pax_opt(void); +extern char *chdname; + +/* + * pat_rep.c + */ +int rep_add(char *); +int pat_add(char *, char *); +void pat_chk(void); +int pat_sel(ARCHD *); +int pat_match(ARCHD *); +int mod_name(ARCHD *); +int set_dest(ARCHD *, char *, int); + +/* + * pax.c + */ +extern int act; +extern FSUB *frmt; +extern int cflag; +extern int cwdfd; +extern int dflag; +extern int iflag; +extern int kflag; +extern int lflag; +extern int nflag; +extern int tflag; +extern int uflag; +extern int vflag; +extern int Dflag; +extern int Hflag; +extern int Lflag; +extern int Xflag; +extern int Yflag; +extern int Zflag; +extern int zeroflag; +extern int vfpart; +extern int patime; +extern int pmtime; +extern int nodirs; +extern int pmode; +extern int pids; +extern int rmleadslash; +extern int exit_val; +extern int docrc; +extern char *dirptr; +extern char *ltmfrmt; +extern char *argv0; +extern FILE *listf; +extern char *tempfile; +extern char *tempbase; + +int main(int, char **); +void sig_cleanup(int); + +/* + * sel_subs.c + */ +int sel_chk(ARCHD *); +int grp_add(char *); +int usr_add(char *); +int trng_add(char *); + +/* + * tables.c + */ +int lnk_start(void); +int chk_lnk(ARCHD *); +void purg_lnk(ARCHD *); +void lnk_end(void); +int ftime_start(void); +int chk_ftime(ARCHD *); +int name_start(void); +int add_name(char *, int, char *); +void sub_name(char *, int *, size_t); +int dev_start(void); +int add_dev(ARCHD *); +int map_dev(ARCHD *, u_long, u_long); +int atdir_start(void); +void atdir_end(void); +void add_atdir(char *, dev_t, ino_t, time_t, time_t); +int get_atdir(dev_t, ino_t, time_t *, time_t *); +int dir_start(void); +void add_dir(char *, struct stat *, int); +void proc_dir(void); +u_int st_hash(char *, int, int); + +/* + * tar.c + */ +extern char *gnu_hack_string; +int tar_endwr(void); +off_t tar_endrd(void); +int tar_trail(ARCHD *, char *, int, int *); +int tar_id(char *, int); +int tar_opt(void); +int tar_rd(ARCHD *, char *); +int tar_wr(ARCHD *); +int ustar_strd(void); +int ustar_stwr(void); +int ustar_id(char *, int); +int ustar_rd(ARCHD *, char *); +int ustar_wr(ARCHD *); + +/* + * pax_format.c + */ +extern char *header_name_g; +extern int pax_read_or_list_mode; +#define PAX_INVALID_ACTION_BYPASS 1 +#define PAX_INVALID_ACTION_RENAME 2 +#define PAX_INVALID_ACTION_UTF8 3 +#define PAX_INVALID_ACTION_WRITE 4 +extern int want_linkdata; +extern int pax_invalid_action; +extern char * pax_list_opt_format; +extern char * pax_invalid_action_write_path; +extern char * pax_invalid_action_write_cwd; +void pax_format_list_output(ARCHD *, time_t, FILE *, int); +void cleanup_pax_invalid_action(void); +void record_pax_invalid_action_results(ARCHD *, char *); +int perform_pax_invalid_action(ARCHD *, int); +void adjust_copy_for_pax_options(ARCHD *); +/* +int pax_strd(void); +int pax_stwr(void); +*/ +int pax_id(char *, int); +int pax_rd(ARCHD *, char *); +int pax_wr(ARCHD *); + +/* + * tty_subs.c + */ +int tty_init(void); +void tty_prnt(const char *, ...); +int tty_read(char *, int); +void paxwarn(int, const char *, ...); +void syswarn(int, int, const char *, ...); diff --git a/pax/file_subs.c b/pax/file_subs.c index 234dcc3..02058f6 100644 --- a/pax/file_subs.c +++ b/pax/file_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file_subs.c,v 1.13 1997/09/01 18:29:48 deraadt Exp $ */ +/* $OpenBSD: file_subs.c,v 1.28 2004/11/29 16:23:22 otto Exp $ */ /* $NetBSD: file_subs.c,v 1.4 1995/03/21 09:07:18 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,29 +36,29 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)file_subs.c 8.1 (Berkeley) 5/31/93"; +static const char sccsid[] = "@(#)file_subs.c 8.1 (Berkeley) 5/31/93"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: file_subs.c,v 1.13 1997/09/01 18:29:48 deraadt Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: file_subs.c,v 1.28 2004/11/29 16:23:22 otto Exp $"; #endif #endif /* not lint */ -#include +#include #include #include -#include -#include +#include +#include +#include #include -#include #include -#include -#include #include +#include +#include #include "pax.h" #include "options.h" #include "extern.h" static int -mk_link __P((register char *,register struct stat *,register char *, int)); +mk_link(char *, struct stat *, char *, int); /* * routines that deal with file operations such as: creating, removing; @@ -80,26 +76,25 @@ mk_link __P((register char *,register struct stat *,register char *, int)); * file descriptor or -1 for failure */ -#ifdef __STDC__ int -file_creat(register ARCHD *arcn) -#else -int -file_creat(arcn) - register ARCHD *arcn; -#endif +file_creat(ARCHD *arcn) { int fd = -1; mode_t file_mode; int oerrno; + int rc = 0; + char *path_to_open; + char *new_path; + char *cwd; + char cwd_buff[MAXPATHLEN]; /* - * assume file doesn't exist, so just try to create it, most times this + * Assume file doesn't exist, so just try to create it, most times this * works. We have to take special handling when the file does exist. To * detect this, we use O_EXCL. For example when trying to create a * file and a character device or fifo exists with the same name, we - * can accidently open the device by mistake (or block waiting to open) - * If we find that the open has failed, then figure spend the effore to + * can accidently open the device by mistake (or block waiting to open). + * If we find that the open has failed, then spend the effort to * figure out why. This strategy was found to have better average * performance in common use than checking the file (and the path) * first with lstat. @@ -117,20 +112,44 @@ file_creat(arcn) if (unlnk_exist(arcn->name, arcn->type) != 0) return(-1); + path_to_open = arcn->name; + new_path = arcn->name; + cwd = getcwd(&cwd_buff[0],MAXPATHLEN); + if (cwd==NULL) return -1; for (;;) { /* * try to open it again, if this fails, check all the nodes in * the path and give it a final try. if chk_path() finds that * it cannot fix anything, we will skip the last attempt */ - if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC, - file_mode)) >= 0) + if ((fd = open(path_to_open, O_WRONLY | O_CREAT | O_TRUNC, + file_mode)) >= 0) { + /* clean up the invalid_action */ + if (pax_invalid_action>0) { + record_pax_invalid_action_results(arcn, path_to_open); + } break; + } oerrno = errno; - if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) { - syswarn(1, oerrno, "Unable to create %s", arcn->name); - return(-1); + if (pax_invalid_action>0) { + rc = perform_pax_invalid_action(arcn, oerrno); + if (rc == 0) continue; + if (rc == 1) { + fd = -1; + break; + } } + /* rc == 2 reserved for -o invalid_action=write */ + if (nodirs || chk_path(path_to_open,arcn->sb.st_uid,arcn->sb.st_gid, + (rc==2) ? &new_path: NULL) < 0) { + syswarn((pax_invalid_action==0), oerrno, "Unable to create %s", arcn->name); + fd = -1; + break; + } + if (new_path) path_to_open = new_path; /* try again */ + } + if (strcmp(new_path, arcn->name)!=0) { + chdir(cwd); /* go back to original directory */ } return(fd); } @@ -143,15 +162,8 @@ file_creat(arcn) * 0 for success, -1 for failure */ -#ifdef __STDC__ -void -file_close(register ARCHD *arcn, int fd) -#else void -file_close(arcn, fd) - register ARCHD *arcn; - int fd; -#endif +file_close(ARCHD *arcn, int fd) { int res = 0; @@ -164,17 +176,19 @@ file_close(arcn, fd) /* * set owner/groups first as this may strip off mode bits we want * then set file permission modes. Then set file access and - * modification times. + * modification times. */ if (pids) res = set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid); + else + res = 1; /* without pids, pax should NOT set s bits */ /* * IMPORTANT SECURITY NOTE: * if not preserving mode or we cannot set uid/gid, then PROHIBIT * set uid/gid bits */ - if (!pids || res) + if (!pmode || res) arcn->sb.st_mode &= ~(SETBITS); if (pmode) set_pmode(arcn->name, arcn->sb.st_mode); @@ -185,19 +199,13 @@ file_close(arcn, fd) /* * lnk_creat() * Create a hard link to arcn->ln_name from arcn->name. arcn->ln_name - * must exist; + * must exist; * Return: * 0 if ok, -1 otherwise */ -#ifdef __STDC__ int -lnk_creat(register ARCHD *arcn) -#else -int -lnk_creat(arcn) - register ARCHD *arcn; -#endif +lnk_creat(ARCHD *arcn) { struct stat sb; @@ -217,6 +225,23 @@ lnk_creat(arcn) return(-1); } + if (S_ISLNK(sb.st_mode)) { + int res; + char buff[NAME_MAX+1]; + /* + * Conformance: cannot make hard link to symlink - just make a + * symlink to the target of the symlink + */ + if ((res = readlink(arcn->ln_name, buff, sizeof(buff))) < 0) { + syswarn(1,errno,"Unable to symlink to %s from %s", arcn->ln_name, + arcn->name); + return(-1); + } + buff[res] = 0; + res = symlink(buff, arcn->name); + return res; + } + return(mk_link(arcn->ln_name, &sb, arcn->name, 0)); } @@ -230,22 +255,20 @@ lnk_creat(arcn) * 0 if cross_lnk() ok, -1 for fatal flaw (like linking to self). */ -#ifdef __STDC__ -int -cross_lnk(register ARCHD *arcn) -#else int -cross_lnk(arcn) - register ARCHD *arcn; -#endif +cross_lnk(ARCHD *arcn) { /* - * try to make a link to orginal file (-l flag in copy mode). make sure - * we do not try to link to directories in case we are running as root - * (and it might succeed). + * try to make a link to original file (-l flag in copy mode). make + * sure we do not try to link to directories in case we are running as + * root (and it might succeed). */ if (arcn->type == PAX_DIR) return(1); + if (arcn->type == PAX_SLK) { /* for Unix 03 conformance tests 202,203 */ + if (!Lflag) + return(1); + } return(mk_link(arcn->org_name, &(arcn->sb), arcn->name, 1)); } @@ -260,18 +283,12 @@ cross_lnk(arcn) * 0 skip it file exists (-k) or may be the same as source file */ -#ifdef __STDC__ int -chk_same(register ARCHD *arcn) -#else -int -chk_same(arcn) - register ARCHD *arcn; -#endif +chk_same(ARCHD *arcn) { struct stat sb; - /* + /* * if file does not exist, return. if file exists and -k, skip it * quietly */ @@ -303,18 +320,8 @@ chk_same(arcn) * allowed option). -1 an error occurred. */ -#ifdef __STDC__ -static int -mk_link(register char *to, register struct stat *to_sb, register char *from, - int ign) -#else static int -mk_link(to, to_sb, from, ign) - register char *to; - register struct stat *to_sb; - register char *from; - int ign; -#endif +mk_link(char *to, struct stat *to_sb, char *from, int ign) { struct stat sb; int oerrno; @@ -332,7 +339,7 @@ mk_link(to, to_sb, from, ign) */ if ((to_sb->st_dev==sb.st_dev)&&(to_sb->st_ino == sb.st_ino)) { paxwarn(1, "Unable to link file %s to itself", to); - return(-1);; + return(-1); } /* @@ -361,7 +368,7 @@ mk_link(to, to_sb, from, ign) if (link(to, from) == 0) break; oerrno = errno; - if (!nodirs && chk_path(from, to_sb->st_uid, to_sb->st_gid) == 0) + if (!nodirs && chk_path(from, to_sb->st_uid, to_sb->st_gid, NULL) == 0) continue; if (!ign) { syswarn(1, oerrno, "Could not link to %s from %s", to, @@ -385,21 +392,18 @@ mk_link(to, to_sb, from, ign) * 0 if ok, -1 otherwise */ -#ifdef __STDC__ -int -node_creat(register ARCHD *arcn) -#else int -node_creat(arcn) - register ARCHD *arcn; -#endif +node_creat(ARCHD *arcn) { - register int res; - register int ign = 0; - register int oerrno; - register int pass = 0; + int res; + int ign = 0; + int oerrno; + int pass = 0; mode_t file_mode; struct stat sb; + char target[MAXPATHLEN]; + char *nm = arcn->name; + int len; /* * create node based on type, if that fails try to unlink the node and @@ -410,22 +414,45 @@ node_creat(arcn) file_mode = arcn->sb.st_mode & FILEBITS; for (;;) { - switch(arcn->type) { + switch (arcn->type) { case PAX_DIR: - res = mkdir(arcn->name, file_mode); + /* + * If -h (or -L) was given in tar-mode, follow the + * potential symlink chain before trying to create the + * directory. + */ + if (strcmp(NM_TAR, argv0) == 0 && Lflag) { + while (lstat(nm, &sb) == 0 && + S_ISLNK(sb.st_mode)) { + len = readlink(nm, target, + sizeof target - 1); + if (len == -1) { + syswarn(0, errno, + "cannot follow symlink %s in chain for %s", + nm, arcn->name); + res = -1; + goto badlink; + } + target[len] = '\0'; + nm = target; + } + } + res = mkdir(nm, file_mode); + +badlink: if (ign) res = 0; break; case PAX_CHR: file_mode |= S_IFCHR; - res = mknod(arcn->name, file_mode, arcn->sb.st_rdev); + res = mknod(nm, file_mode, arcn->sb.st_rdev); break; case PAX_BLK: file_mode |= S_IFBLK; - res = mknod(arcn->name, file_mode, arcn->sb.st_rdev); + res = mknod(nm, file_mode, arcn->sb.st_rdev); break; case PAX_FIF: - res = mkfifo(arcn->name, file_mode); + res = mkfifo(nm, file_mode); break; case PAX_SCK: /* @@ -433,10 +460,10 @@ node_creat(arcn) */ paxwarn(0, "%s skipped. Sockets cannot be copied or extracted", - arcn->name); + nm); return(-1); case PAX_SLK: - res = symlink(arcn->ln_name, arcn->name); + res = symlink(arcn->ln_name, nm); break; case PAX_CTG: case PAX_HLK: @@ -447,7 +474,7 @@ node_creat(arcn) * we should never get here */ paxwarn(0, "%s has an unknown file type, skipping", - arcn->name); + nm); return(-1); } @@ -463,14 +490,14 @@ node_creat(arcn) * we failed to make the node */ oerrno = errno; - if ((ign = unlnk_exist(arcn->name, arcn->type)) < 0) + if ((ign = unlnk_exist(nm, arcn->type)) < 0) return(-1); if (++pass <= 1) continue; - if (nodirs || chk_path(arcn->name,arcn->sb.st_uid,arcn->sb.st_gid) < 0) { - syswarn(1, oerrno, "Could not create: %s", arcn->name); + if (nodirs || chk_path(nm,arcn->sb.st_uid,arcn->sb.st_gid, NULL) < 0) { + syswarn(1, oerrno, "Could not create: %s", nm); return(-1); } } @@ -481,14 +508,14 @@ node_creat(arcn) if (pids) res = ((arcn->type == PAX_SLK) ? #if defined(__APPLE__) - /* Mac OS X doesn't have lchown, so don't bother */ + /* Mac OS X doesn't have lchown, so don't bother */ 0 : #else - set_lids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid) : + set_lids(nm, arcn->sb.st_uid, arcn->sb.st_gid) : #endif - set_ids(arcn->name, arcn->sb.st_uid, arcn->sb.st_gid)); + set_ids(nm, arcn->sb.st_uid, arcn->sb.st_gid)); else - res = 0; + res = 1; /* without pids, pax should NOT set s bits */ /* * symlinks are done now. @@ -504,7 +531,7 @@ node_creat(arcn) if (!pmode || res) arcn->sb.st_mode &= ~(SETBITS); if (pmode) - set_pmode(arcn->name, arcn->sb.st_mode); + set_pmode(nm, arcn->sb.st_mode); if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) { /* @@ -516,11 +543,11 @@ node_creat(arcn) * and modes will be fixed after the entire archive is read and * before pax exits. */ - if (access(arcn->name, R_OK | W_OK | X_OK) < 0) { - if (lstat(arcn->name, &sb) < 0) { + if (access(nm, R_OK | W_OK | X_OK) < 0) { + if (lstat(nm, &sb) < 0) { syswarn(0, errno,"Could not access %s (stat)", arcn->name); - set_pmode(arcn->name,file_mode | S_IRWXU); + set_pmode(nm,file_mode | S_IRWXU); } else { /* * We have to add rights to the dir, so we make @@ -528,7 +555,7 @@ node_creat(arcn) * restored AS CREATED and not as stored if * pmode is not set. */ - set_pmode(arcn->name, + set_pmode(nm, ((sb.st_mode & FILEBITS) | S_IRWXU)); if (!pmode) arcn->sb.st_mode = sb.st_mode; @@ -538,13 +565,13 @@ node_creat(arcn) * we have to force the mode to what was set here, * since we changed it from the default as created. */ - add_dir(arcn->name, arcn->nlen, &(arcn->sb), 1); + add_dir(nm, &(arcn->sb), 1); } else if (pmode || patime || pmtime) - add_dir(arcn->name, arcn->nlen, &(arcn->sb), 0); + add_dir(nm, &(arcn->sb), 0); } if (patime || pmtime) - set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0); + set_ftime(nm, arcn->sb.st_mtime, arcn->sb.st_atime, 0); return(0); } @@ -560,15 +587,8 @@ node_creat(arcn) * 1 we found a directory and we were going to create a directory. */ -#ifdef __STDC__ int -unlnk_exist(register char *name, register int type) -#else -int -unlnk_exist(name, type) - register char *name; - register int type; -#endif +unlnk_exist(char *name, int type) { struct stat sb; @@ -621,18 +641,10 @@ unlnk_exist(name, type) * 0 otherwise */ -#ifdef __STDC__ -int -chk_path( register char *name, uid_t st_uid, gid_t st_gid) -#else int -chk_path(name, st_uid, st_gid) - register char *name; - uid_t st_uid; - gid_t st_gid; -#endif +chk_path(char *name, uid_t st_uid, gid_t st_gid, char ** new_name) { - register char *spt = name; + char *spt = name; struct stat sb; int retval = -1; @@ -642,9 +654,9 @@ chk_path(name, st_uid, st_gid) if (*spt == '/') ++spt; - for(;;) { + for (;;) { /* - * work foward from the first / and check each part of the path + * work forward from the first / and check each part of the path */ spt = strchr(spt, '/'); if (spt == NULL) @@ -662,7 +674,9 @@ chk_path(name, st_uid, st_gid) */ if (lstat(name, &sb) == 0) { *(spt++) = '/'; - continue; + if (new_name==NULL) continue; + retval = 0; /* accept it one directory at a time */ + break; } /* @@ -685,7 +699,7 @@ chk_path(name, st_uid, st_gid) (void)set_ids(name, st_uid, st_gid); /* - * make sure the user doen't have some strange umask that + * make sure the user doesn't have some strange umask that * causes this newly created directory to be unusable. We fix * the modes and restore them back to the creation default at * the end of pax @@ -693,37 +707,45 @@ chk_path(name, st_uid, st_gid) if ((access(name, R_OK | W_OK | X_OK) < 0) && (lstat(name, &sb) == 0)) { set_pmode(name, ((sb.st_mode & FILEBITS) | S_IRWXU)); - add_dir(name, spt - name, &sb, 1); + add_dir(name, &sb, 1); } *(spt++) = '/'; - continue; + if (new_name==NULL) continue; + break; + } + + if ((new_name != NULL) && retval==0) { + /* save the new path */ + *(--spt) = '\0'; + /* + printf ("chdir to %s\n", name); + */ + if(0==chdir(name)) { + *spt++ = '/'; + /* + printf ("remaining path: %s\n",spt); + */ + *new_name = spt; + } else + *spt++ = '/'; } return(retval); } /* * set_ftime() - * Set the access time and modification time for a named file. If frc is - * non-zero we force these times to be set even if the user did not + * Set the access time and modification time for a named file. If frc + * is non-zero we force these times to be set even if the user did not * request access and/or modification time preservation (this is also * used by -t to reset access times). - * When ign is zero, only those times the user has asked for are set, the + * When frc is zero, only those times the user has asked for are set, the * other ones are left alone. We do not assume the un-documented feature * of many utimes() implementations that consider a 0 time value as a do * not set request. */ -#ifdef __STDC__ void set_ftime(char *fnm, time_t mtime, time_t atime, int frc) -#else -void -set_ftime(fnm, mtime, atime, frc) - char *fnm; - time_t mtime; - time_t atime; - int frc; -#endif { static struct timeval tv[2] = {{0L, 0L}, {0L, 0L}}; struct stat sb; @@ -747,9 +769,22 @@ set_ftime(fnm, mtime, atime, frc) /* * set the times */ - if (utimes(fnm, tv) < 0) - syswarn(1, errno, "Access/modification time set failed on: %s", - fnm); + + if (pax_invalid_action_write_cwd) { + char cwd_buff[MAXPATHLEN]; + char * cwd; + cwd = getcwd(&cwd_buff[0],MAXPATHLEN); + chdir(pax_invalid_action_write_cwd); + if (utimes(pax_invalid_action_write_path, tv) < 0) + syswarn(1, errno, "Access/modification time set failed on: %s", + pax_invalid_action_write_path); + chdir(cwd); + cleanup_pax_invalid_action(); + } else { + if (utimes(fnm, tv) < 0) + syswarn(1, errno, "Access/modification time set failed on: %s", + fnm); + } return; } @@ -760,16 +795,8 @@ set_ftime(fnm, mtime, atime, frc) * 0 when set, -1 on failure */ -#ifdef __STDC__ int set_ids(char *fnm, uid_t uid, gid_t gid) -#else -int -set_ids(fnm, uid, gid) - char *fnm; - uid_t uid; - gid_t gid; -#endif { if (chown(fnm, uid, gid) < 0) { /* @@ -787,7 +814,6 @@ set_ids(fnm, uid, gid) #if !defined(__APPLE__) /* Mac OS X doesn't have lchown */ - /* * set_lids() * set the uid and gid of a file system node @@ -795,16 +821,8 @@ set_ids(fnm, uid, gid) * 0 when set, -1 on failure */ -#ifdef __STDC__ int set_lids(char *fnm, uid_t uid, gid_t gid) -#else -int -set_lids(fnm, uid, gid) - char *fnm; - uid_t uid; - gid_t gid; -#endif { if (lchown(fnm, uid, gid) < 0) { /* @@ -826,15 +844,8 @@ set_lids(fnm, uid, gid) * Set file access mode */ -#ifdef __STDC__ void set_pmode(char *fnm, mode_t mode) -#else -void -set_pmode(fnm, mode) - char *fnm; - mode_t mode; -#endif { mode &= ABITS; if (chmod(fnm, mode) < 0) @@ -861,11 +872,11 @@ set_pmode(fnm, mode) * uses lseek whenever it detects the input data is all 0 within that * file block. In more detail, the strategy is as follows: * While the input is all zero keep doing an lseek. Keep track of when we - * pass over file block boundries. Only write when we hit a non zero + * pass over file block boundaries. Only write when we hit a non zero * input. once we have written a file block, we continue to write it to * the end (we stop looking at the input). When we reach the start of the * next file block, start checking for zero blocks again. Working on file - * block boundries significantly reduces the overhead when copying files + * block boundaries significantly reduces the overhead when copying files * that are NOT very sparse. This overhead (when compared to a write) is * almost below the measurement resolution on many systems. Without it, * files with holes cannot be safely copied. It does has a side effect as @@ -890,26 +901,15 @@ set_pmode(fnm, mode) * number of bytes written, -1 on write (or lseek) error. */ -#ifdef __STDC__ int -file_write(int fd, char *str, register int cnt, int *rem, int *isempt, int sz, +file_write(int fd, char *str, int cnt, int *rem, int *isempt, int sz, char *name) -#else -int -file_write(fd, str, cnt, rem, isempt, sz, name) - int fd; - char *str; - register int cnt; - int *rem; - int *isempt; - int sz; - char *name; -#endif { - register char *pt; - register char *end; - register int wcnt; - register char *st = str; + char *pt; + char *end; + int wcnt; + char *st = str; + char **strp; /* * while we have data to process @@ -950,7 +950,8 @@ file_write(fd, str, cnt, rem, isempt, sz, name) /* * skip, buf is empty so far */ - if (lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) { + if (fd > -1 && + lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) { syswarn(1,errno,"File seek on %s", name); return(-1); @@ -967,7 +968,29 @@ file_write(fd, str, cnt, rem, isempt, sz, name) /* * have non-zero data in this file system block, have to write */ - if (write(fd, st, wcnt) != wcnt) { + switch (fd) { + case -1: + strp = &gnu_name_string; + break; + case -2: + strp = &gnu_link_string; + break; + default: + strp = NULL; + break; + } + if (strp) { + if (*strp) + err(1, "WARNING! Major Internal Error! GNU hack Failing!"); + *strp = malloc(wcnt + 1); + if (*strp == NULL) { + paxwarn(1, "Out of memory"); + return(-1); + } + memcpy(*strp, st, wcnt); + (*strp)[wcnt] = '\0'; + break; + } else if (write(fd, st, wcnt) != wcnt) { syswarn(1, errno, "Failed write to file %s", name); return(-1); } @@ -983,16 +1006,8 @@ file_write(fd, str, cnt, rem, isempt, sz, name) * write the last BYTE with a zero (back up one byte and write a zero). */ -#ifdef __STDC__ void file_flush(int fd, char *fname, int isempt) -#else -void -file_flush(fd, fname, isempt) - int fd; - char *fname; - int isempt; -#endif { static char blnk[] = "\0"; @@ -1022,15 +1037,8 @@ file_flush(fd, fname, isempt) * reset access time (tflag) do so (the times are stored in arcn). */ -#ifdef __STDC__ void -rdfile_close(register ARCHD *arcn, register int *fd) -#else -void -rdfile_close(arcn, fd) - register ARCHD *arcn; - register int *fd; -#endif +rdfile_close(ARCHD *arcn, int *fd) { /* * make sure the file is open @@ -1059,18 +1067,11 @@ rdfile_close(arcn, fd) * 0 if was able to calculate the crc, -1 otherwise */ -#ifdef __STDC__ -int -set_crc(register ARCHD *arcn, register int fd) -#else int -set_crc(arcn, fd) - register ARCHD *arcn; - register int fd; -#endif +set_crc(ARCHD *arcn, int fd) { - register int i; - register int res; + int i; + int res; off_t cpcnt = 0L; u_long size; unsigned long crc = 0L; @@ -1092,7 +1093,7 @@ set_crc(arcn, fd) * read all the bytes we think that there are in the file. If the user * is trying to archive an active file, forget this file. */ - for(;;) { + for (;;) { if ((res = read(fd, tbuf, size)) <= 0) break; cpcnt += res; @@ -1102,7 +1103,7 @@ set_crc(arcn, fd) /* * safety check. we want to avoid archiving files that are active as - * they can create inconsistant archive copies. + * they can create inconsistent archive copies. */ if (cpcnt != arcn->sb.st_size) paxwarn(1, "File changed size %s", arcn->org_name); diff --git a/pax/ftree.c b/pax/ftree.c index c5fcc44..14d1712 100644 --- a/pax/ftree.c +++ b/pax/ftree.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ftree.c,v 1.8 1997/09/01 18:29:49 deraadt Exp $ */ +/* $OpenBSD: ftree.c,v 1.25 2004/04/16 22:50:23 deraadt Exp $ */ /* $NetBSD: ftree.c,v 1.4 1995/03/21 09:07:21 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)ftree.c 8.2 (Berkeley) 4/18/94"; +static const char sccsid[] = "@(#)ftree.c 8.2 (Berkeley) 4/18/94"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ftree.c,v 1.8 1997/09/01 18:29:49 deraadt Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ftree.c,v 1.25 2004/04/16 22:50:23 deraadt Exp $"; #endif #endif /* not lint */ @@ -74,7 +70,7 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: ftree.c,v 1.8 1997/ * pax, they are read from stdin */ -static FTS *ftsp = NULL; /* curent FTS handle */ +static FTS *ftsp = NULL; /* current FTS handle */ static int ftsopts; /* options to be used on fts_open */ static char *farray[2]; /* array for passing each arg to fts */ static FTREE *fthead = NULL; /* head of linked list of file args */ @@ -83,7 +79,8 @@ 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 */ -static int ftree_arg __P((void)); +static int ftree_arg(void); +static char *getpathname(char *, int); /* * ftree_start() @@ -95,13 +92,8 @@ static int ftree_arg __P((void)); * 0 if there is at least one valid file arg to process, -1 otherwise */ -#ifdef __STDC__ int ftree_start(void) -#else -int -ftree_start() -#endif { /* * set up the operation mode of fts, open the first file arg. We must @@ -126,11 +118,7 @@ ftree_start() 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; @@ -154,24 +142,17 @@ ftree_start() * 0 if added to the linked list, -1 if failed */ -#ifdef __STDC__ -int -ftree_add(register char *str, int chflg) -#else int -ftree_add(str, chflg) - register char *str; - int chflg; -#endif +ftree_add(char *str, int chflg) { - register FTREE *ft; - register int len; + FTREE *ft; + int len; /* * simple check for bad args */ if ((str == NULL) || (*str == '\0')) { - paxwarn(0, "Invalid file name arguement"); + paxwarn(0, "Invalid file name argument"); return(-1); } @@ -206,14 +187,8 @@ ftree_add(str, chflg) * -n and -d processing. */ -#ifdef __STDC__ -void -ftree_sel(register ARCHD *arcn) -#else void -ftree_sel(arcn) - register ARCHD *arcn; -#endif +ftree_sel(ARCHD *arcn) { /* * set reference bit for this pattern. This linked list is only used @@ -245,16 +220,11 @@ ftree_sel(arcn) * have a selected member (reference count still 0) */ -#ifdef __STDC__ void ftree_chk(void) -#else -void -ftree_chk() -#endif { - register FTREE *ft; - register int wban = 0; + FTREE *ft; + int wban = 0; /* * make sure all dir access times were reset. @@ -287,15 +257,9 @@ ftree_chk() * stdin). */ -#ifdef __STDC__ static int ftree_arg(void) -#else -static int -ftree_arg() -#endif { - register char *pt; /* * close off the current file tree @@ -309,19 +273,17 @@ ftree_arg() * keep looping until we get a valid file tree to process. Stop when we * reach the end of the list (or get an eof on stdin) */ - for(;;) { + for (;;) { if (fthead == NULL) { /* * the user didn't supply any args, get the file trees - * to process from stdin; + * to process from stdin; */ - if (fgets(farray[0], PAXPATHLEN+1, stdin) == NULL) + if (getpathname(farray[0], PAXPATHLEN+1) == NULL) return(-1); - if ((pt = strchr(farray[0], '\n')) != NULL) - *pt = '\0'; } else { /* - * the user supplied the file args as arguements to pax + * the user supplied the file args as arguments to pax */ if (ftcur == NULL) ftcur = fthead; @@ -348,7 +310,7 @@ ftree_arg() * 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 cannnot pass all the file args to fts at one shot + * 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 * files (the -n and -d flags need this). If the open is * successful, return a 0. @@ -366,23 +328,17 @@ ftree_arg() * 0 when contents of arcn have been set with the next file, -1 when done. */ -#ifdef __STDC__ -int -next_file(register ARCHD *arcn) -#else int -next_file(arcn) - register ARCHD *arcn; -#endif +next_file(ARCHD *arcn) { - register int cnt; + int cnt; time_t atime; time_t mtime; /* * ftree_sel() might have set the ftree_skip flag if the user has the * -n option and a file was selected from this file arg tree. (-n says - * only one member is matched for each pattern) ftree_skip being 1 + * only one member is matched for each pattern) ftree_skip being 1 * forces us to go to the next arg now. */ if (ftree_skip) { @@ -397,7 +353,7 @@ next_file(arcn) /* * loop until we get a valid file to process */ - for(;;) { + for (;;) { if ((ftent = fts_read(ftsp)) == NULL) { /* * out of files in this tree, go to next arg, if none @@ -411,16 +367,23 @@ next_file(arcn) /* * handle each type of fts_read() flag */ - switch(ftent->fts_info) { + switch (ftent->fts_info) { case FTS_D: case FTS_DEFAULT: case FTS_F: case FTS_SL: - case FTS_SLNONE: /* * these are all ok */ break; + case FTS_SLNONE: /* was same as above cases except Unix + conformance requires this error check */ + if (Hflag || Lflag) { /* -H or -L was specified */ + if (ftent->fts_errno) + paxwarn(1, "%s: %s", + ftent->fts_name, strerror(ftent->fts_errno)); + } + break; case FTS_DP: /* * already saw this directory. If the user wants file @@ -430,13 +393,8 @@ next_file(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 continue; set_ftime(ftent->fts_path, mtime, atime, 1); continue; @@ -447,28 +405,16 @@ next_file(arcn) paxwarn(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 "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 "File system traversal error"); continue; case FTS_NS: case FTS_NSOK: -# ifdef NET2_FTS - syswarn(1, errno, -# else syswarn(1, ftent->fts_errno, -# endif "Unable to access %s", ftent->fts_path); continue; } @@ -481,11 +427,7 @@ next_file(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 + memcpy(&arcn->sb, ftent->fts_statp, sizeof(arcn->sb)); /* * file type based set up and copy into the arcn struct @@ -497,7 +439,7 @@ next_file(arcn) * end in case we cut short a file tree traversal). However * there is no way to reset access times on symlinks. */ - switch(S_IFMT & arcn->sb.st_mode) { + switch (S_IFMT & arcn->sb.st_mode) { case S_IFDIR: arcn->type = PAX_DIR; if (!tflag) @@ -535,7 +477,7 @@ next_file(arcn) } /* * set link name length, watch out readlink does not - * allways null terminate the link path + * always NUL terminate the link path */ arcn->ln_name[cnt] = '\0'; arcn->ln_nlen = cnt; @@ -558,8 +500,55 @@ next_file(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->nlen = strlcpy(arcn->name, ftent->fts_path, sizeof(arcn->name)); arcn->org_name = ftent->fts_path; return(0); } + +/* + * getpathname() + * Reads a pathname from stdin, handling NUL- or newline-termination. + * Return: + * NULL at end of file, otherwise the NUL-terminated buffer. + */ + +static char * +getpathname(char *buf, int buflen) +{ + char *bp, *ep; + int ch, term; + + if (zeroflag) { + /* + * Read a NUL-terminated pathname, being especially + * paranoid about proper termination and pathname length. + */ + for (bp = buf, ep = buf + buflen; bp < ep; bp++) { + if ((ch = getchar()) == EOF) { + if (bp != buf) + paxwarn(1, "Ignoring unterminated " + "pathname at EOF"); + return(NULL); + } + if ((*bp = ch) == '\0') + return(buf); + } + /* Too long - skip this path */ + *--bp = '\0'; + term = '\0'; + } else { + if (fgets(buf, buflen, stdin) == NULL) + return(NULL); + if ((bp = strchr(buf, '\n')) != NULL || feof(stdin)) { + if (bp != NULL) + *bp = '\0'; + return(buf); + } + /* Too long - skip this path */ + term = '\n'; + } + while ((ch = getchar()) != term && ch != EOF) + ; + paxwarn(1, "Ignoring too-long pathname: %s", buf); + return(NULL); +} diff --git a/pax/ftree.h b/pax/ftree.h index 5ac8ff9..0507aab 100644 --- a/pax/ftree.h +++ b/pax/ftree.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ftree.h,v 1.3 1996/10/27 06:45:11 downsj Exp $ */ +/* $OpenBSD: ftree.h,v 1.4 2003/06/02 23:32:08 millert Exp $ */ /* $NetBSD: ftree.h,v 1.3 1995/03/21 09:07:23 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * diff --git a/pax/gen_subs.c b/pax/gen_subs.c index 4f5f898..36bbb41 100644 --- a/pax/gen_subs.c +++ b/pax/gen_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gen_subs.c,v 1.8 1997/09/01 18:29:51 deraadt Exp $ */ +/* $OpenBSD: gen_subs.c,v 1.17 2003/06/13 17:51:14 millert Exp $ */ /* $NetBSD: gen_subs.c,v 1.5 1995/03/21 09:07:26 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)gen_subs.c 8.1 (Berkeley) 5/31/93"; +static const char sccsid[] = "@(#)gen_subs.c 8.1 (Berkeley) 5/31/93"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: gen_subs.c,v 1.8 1997/09/01 18:29:51 deraadt Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: gen_subs.c,v 1.17 2003/06/13 17:51:14 millert Exp $"; #endif #endif /* not lint */ @@ -56,6 +52,7 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: gen_subs.c,v 1.8 19 #include #include #include +#include #include "pax.h" #include "extern.h" @@ -71,80 +68,96 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: gen_subs.c,v 1.8 19 #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 +#define NAME_WIDTH 8 + +/* + * format_date + * format date of file for printing + */ + +static void +format_date(char * f_date, time_t file_time, time_t current) +{ + const char *timefrmt; + + if (ltmfrmt == NULL) { + /* + * no locale specified format. + */ + /* use the same format that ls -l uses */ + if ((file_time + SIXMONTHS) <= current || file_time > current) + timefrmt = OLDFRMT; + else + timefrmt = CURFRMT; + } else + timefrmt = ltmfrmt; + + /* + * convert time to string for printing + */ + if (strftime(f_date,DATELEN,timefrmt,localtime((const time_t *)&(file_time))) == 0) + *f_date = '\0'; +} /* * ls_list() * list the members of an archive in ls format */ -#ifdef __STDC__ void -ls_list(register ARCHD *arcn, time_t now, FILE *fp) -#else -void -ls_list(arcn, now, fp) - register ARCHD *arcn; - time_t now; - FILE *fp; -#endif +ls_list(ARCHD *arcn, time_t now, FILE *fp) { - register struct stat *sbp; + struct stat *sbp; char f_mode[MODELEN]; char f_date[DATELEN]; - char *timefrmt; + int term; + + term = zeroflag ? '\0' : '\n'; /* path termination character */ /* * if not verbose, just print the file name */ if (!vflag) { - (void)fprintf(fp, "%s\n", arcn->name); + if (zeroflag) + (void)fputs(arcn->name, fp); + else + safe_print(arcn->name, fp); + (void)putc(term, fp); (void)fflush(fp); return; } + if (pax_list_opt_format) { + pax_format_list_output(arcn, now, fp, term); + return; + } /* * user wants long mode */ sbp = &(arcn->sb); strmode(sbp->st_mode, f_mode); - if (ltmfrmt == NULL) { - /* - * no locale specified format. time format based on age - * compared to the time pax was started. - */ - if ((sbp->st_mtime + SIXMONTHS) <= now) - timefrmt = OLDFRMT; - else - timefrmt = CURFRMT; - } else - timefrmt = ltmfrmt; + format_date(&f_date[0], sbp->st_mtime, now); /* * print file mode, link count, uid, gid and time */ - if (strftime(f_date,DATELEN,timefrmt,localtime((const time_t *)&(sbp->st_mtime))) == 0) - 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)); + (void)fprintf(fp, "%s%2u %-*.*s %-*.*s ", f_mode, sbp->st_nlink, + NAME_WIDTH, UT_NAMESIZE, name_uid(sbp->st_uid, 1), + NAME_WIDTH, UT_NAMESIZE, name_gid(sbp->st_gid, 1)); /* * print device id's for devices, or sizes for other nodes */ if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK)) -# ifdef NET2_STAT +# ifdef LONG_OFF_T (void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev), # else (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev), # endif (unsigned long)MINOR(sbp->st_rdev)); else { -# ifdef NET2_STAT +# ifdef LONG_OFF_T (void)fprintf(fp, "%9lu ", sbp->st_size); # else (void)fprintf(fp, "%9qu ", sbp->st_size); @@ -154,88 +167,56 @@ ls_list(arcn, now, fp) /* * print name and link info for hard and soft links */ - (void)fprintf(fp, "%s %s", f_date, arcn->name); - 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); - else - (void)putc('\n', fp); + (void)fputs(f_date, fp); + (void)putc(' ', fp); + safe_print(arcn->name, fp); + if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) { + fputs(" == ", fp); + safe_print(arcn->ln_name, fp); + } else if (arcn->type == PAX_SLK) { + fputs(" => ", fp); + safe_print(arcn->ln_name, fp); + } + (void)putc(term, fp); (void)fflush(fp); return; } /* * tty_ls() - * print a short summary of file to tty. + * print a short summary of file to tty. */ -#ifdef __STDC__ -void -ls_tty(register ARCHD *arcn) -#else void -ls_tty(arcn) - register ARCHD *arcn; -#endif +ls_tty(ARCHD *arcn) { char f_date[DATELEN]; char f_mode[MODELEN]; - char *timefrmt; - if (ltmfrmt == NULL) { - /* - * no locale specified format - */ - if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL)) - timefrmt = OLDFRMT; - else - timefrmt = CURFRMT; - } else - timefrmt = ltmfrmt; + format_date(&f_date[0], arcn->sb.st_mtime, time(NULL)); - /* - * convert time to string, and print - */ - if (strftime(f_date, DATELEN, timefrmt, - localtime((const time_t *)&(arcn->sb.st_mtime))) == 0) - f_date[0] = '\0'; strmode(arcn->sb.st_mode, f_mode); 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()) - */ - -#ifdef __STDC__ -int -l_strncpy(register char *dest, register char *src, int len) -#else -int -l_strncpy(dest, src, len) - register char *dest; - register char *src; - int len; -#endif +void +safe_print(const char *str, FILE *fp) { - register char *stop; - register char *start; - - stop = dest + len; - start = dest; - while ((dest < stop) && (*src != '\0')) - *dest++ = *src++; - len = dest - start; - while (dest < stop) - *dest++ = '\0'; - return(len); + char visbuf[5]; + const char *cp; + + /* + * if printing to a tty, use vis(3) to print special characters. + */ + if (isatty(fileno(fp))) { + for (cp = str; *cp; cp++) { + (void)vis(visbuf, cp[0], VIS_CSTYLE, cp[1]); + (void)fputs(visbuf, fp); + } + } else { + (void)fputs(str, fp); + } } /* @@ -248,18 +229,10 @@ l_strncpy(dest, src, len) * unsigned long value */ -#ifdef __STDC__ -u_long -asc_ul(register char *str, int len, register int base) -#else u_long -asc_ul(str, len, base) - register char *str; - int len; - register int base; -#endif +asc_ul(char *str, int len, int base) { - register char *stop; + char *stop; u_long tval = 0; stop = str + len; @@ -286,7 +259,7 @@ asc_ul(str, len, base) break; } } else { - while ((str < stop) && (*str >= '0') && (*str <= '7')) + while ((str < stop) && (*str >= '0') && (*str <= '7')) tval = (tval << 3) + (*str++ - '0'); } return(tval); @@ -299,19 +272,10 @@ asc_ul(str, len, base) * NOTE: the string created is NOT TERMINATED. */ -#ifdef __STDC__ int -ul_asc(u_long val, register char *str, register int len, register int base) -#else -int -ul_asc(val, str, len, base) - u_long val; - register char *str; - register int len; - register int base; -#endif +ul_asc(u_long val, char *str, int len, int base) { - register char *pt; + char *pt; u_long digit; /* @@ -351,7 +315,7 @@ ul_asc(val, str, len, base) return(0); } -#ifndef NET2_STAT +#ifndef LONG_OFF_T /* * asc_uqd() * convert hex/octal character string into a u_quad_t. We do not have to @@ -362,18 +326,10 @@ ul_asc(val, str, len, base) * u_quad_t value */ -#ifdef __STDC__ -u_quad_t -asc_uqd(register char *str, int len, register int base) -#else u_quad_t -asc_uqd(str, len, base) - register char *str; - int len; - register int base; -#endif +asc_uqd(char *str, int len, int base) { - register char *stop; + char *stop; u_quad_t tval = 0; stop = str + len; @@ -400,7 +356,7 @@ asc_uqd(str, len, base) break; } } else { - while ((str < stop) && (*str >= '0') && (*str <= '7')) + while ((str < stop) && (*str >= '0') && (*str <= '7')) tval = (tval << 3) + (*str++ - '0'); } return(tval); @@ -413,19 +369,10 @@ asc_uqd(str, len, base) * NOTE: the string created is NOT TERMINATED. */ -#ifdef __STDC__ -int -uqd_asc(u_quad_t val, register char *str, register int len, register int base) -#else int -uqd_asc(val, str, len, base) - u_quad_t val; - register char *str; - register int len; - register int base; -#endif +uqd_asc(u_quad_t val, char *str, int len, int base) { - register char *pt; + char *pt; u_quad_t digit; /* diff --git a/pax/getoldopt.c b/pax/getoldopt.c index 8a15a2f..6b62092 100644 --- a/pax/getoldopt.c +++ b/pax/getoldopt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getoldopt.c,v 1.3 1997/09/01 18:29:52 deraadt Exp $ */ +/* $OpenBSD: getoldopt.c,v 1.8 2003/07/02 21:19:33 deraadt Exp $ */ /* $NetBSD: getoldopt.c,v 1.3 1995/03/21 09:07:28 cgd Exp $ */ /* @@ -7,25 +7,24 @@ * 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. */ #ifndef lint -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: getoldopt.c,v 1.3 1997/09/01 18:29:52 deraadt Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: getoldopt.c,v 1.8 2003/07/02 21:19:33 deraadt Exp $"; #endif /* not lint */ +#include +#include #include #include #include +#include "pax.h" +#include "extern.h" int -getoldopt(argc, argv, optstring) - int argc; - char **argv; - char *optstring; +getoldopt(int argc, char **argv, const char *optstring) { - extern char *optarg; /* Points to next arg */ - extern int optind; /* Global argv index */ static char *key; /* Points to next keyletter */ static char use_getopt; /* !=0 if argv[1][0] was '-' */ char c; @@ -34,7 +33,8 @@ getoldopt(argc, argv, 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++; @@ -43,18 +43,18 @@ getoldopt(argc, argv, optstring) } if (use_getopt) - return getopt(argc, argv, optstring); + return (getopt(argc, argv, optstring)); c = *key++; if (c == '\0') { key--; - return EOF; + return (-1); } place = strchr(optstring, c); if (place == NULL || c == ':') { fprintf(stderr, "%s: unknown option %c\n", argv[0], c); - return('?'); + return ('?'); } place++; @@ -65,9 +65,9 @@ getoldopt(argc, argv, optstring) } else { fprintf(stderr, "%s: %c argument missing\n", argv[0], c); - return('?'); + return ('?'); } } - return(c); + return (c); } diff --git a/pax/options.c b/pax/options.c index 0bbcaa9..feb97e2 100644 --- a/pax/options.c +++ b/pax/options.c @@ -1,4 +1,4 @@ -/* $OpenBSD: options.c,v 1.31 1998/01/22 06:21:29 millert Exp $ */ +/* $OpenBSD: options.c,v 1.61 2004/04/16 22:50:23 deraadt Exp $ */ /* $NetBSD: options.c,v 1.6 1996/03/26 23:54:18 mrg Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 4/18/94"; +static const char sccsid[] = "@(#)options.c 8.2 (Berkeley) 4/18/94"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: options.c,v 1.31 1998/01/22 06:21:29 millert Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: options.c,v 1.61 2004/04/16 22:50:23 deraadt Exp $"; #endif #endif /* not lint */ @@ -58,6 +54,7 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: options.c,v 1.31 19 #include #include #include +#include #include "pax.h" #include "options.h" #include "cpio.h" @@ -72,16 +69,23 @@ static char flgch[] = FLGCH; /* list of all possible flags */ static OPLIST *ophead = NULL; /* head for format specific options -x */ static OPLIST *optail = NULL; /* option tail */ -static int no_op __P((void)); -static void printflg __P((unsigned int)); -static int c_frmt __P((const void *, const void *)); -static off_t str_offt __P((char *)); -static void pax_options __P((register int, register char **)); -static void pax_usage __P((void)); -static void tar_options __P((register int, register char **)); -static void tar_usage __P((void)); -static void cpio_options __P((register int, register char **)); -static void cpio_usage __P((void)); +static int no_op(void); +static void printflg(unsigned int); +static int c_frmt(const void *, const void *); +static off_t str_offt(char *); +static char *getline(FILE *fp); +static void pax_options(int, char **); +void pax_usage(void); +static void tar_options(int, char **); +static void tar_usage(void); +static void cpio_options(int, char **); +static void cpio_usage(void); + +/* errors from getline */ +#define GETLINE_FILE_CORRUPT 1 +#define GETLINE_OUT_OF_MEM 2 +static int getline_error; + #define GZIP_CMD "gzip" /* command to run as gzip */ #define COMPRESS_CMD "compress" /* command to run as compress */ @@ -125,20 +129,26 @@ FSUB fsub[] = { {"ustar", 10240, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, ustar_strd, ustar_rd, tar_endrd, ustar_stwr, ustar_wr, tar_endwr, tar_trail, rd_wrfile, wr_rdfile, bad_opt}, + +/* 6: POSIX 3 PAX */ + {"pax", 5120, BLKMULT, 0, 1, BLKMULT, 0, pax_id, ustar_strd, + pax_rd, tar_endrd, ustar_stwr, pax_wr, tar_endwr, tar_trail, + rd_wrfile, wr_rdfile, pax_opt}, }; #define F_OCPIO 0 /* format when called as cpio -6 */ #define F_ACPIO 1 /* format when called as cpio -c */ #define F_CPIO 3 /* format when called as cpio */ #define F_OTAR 4 /* format when called as tar -o */ #define F_TAR 5 /* format when called as tar */ +#define F_PAX 6 /* format when called as pax -x pax */ #define DEFLT 5 /* default write format from list above */ /* * ford is the archive search order used by get_arc() to determine what kind - * of archive we are dealing with. This helps to properly id archive formats + * of archive we are dealing with. This helps to properly id archive formats * some formats may be subsets of others.... */ -int ford[] = {5, 4, 3, 2, 1, 0, -1 }; +int ford[] = {6, 5, 4, 3, 2, 1, 0, -1 }; /* * options() @@ -146,15 +156,8 @@ int ford[] = {5, 4, 3, 2, 1, 0, -1 }; * parser */ -#ifdef __STDC__ void -options(register int argc, register char **argv) -#else -void -options(argc, argv) - register int argc; - register char **argv; -#endif +options(int argc, char **argv) { /* @@ -165,15 +168,18 @@ options(argc, argv) else argv0 = argv[0]; - if (strcmp(NM_TAR, argv0) == 0) - return(tar_options(argc, argv)); - else if (strcmp(NM_CPIO, argv0) == 0) - return(cpio_options(argc, argv)); + if (strcmp(NM_TAR, argv0) == 0) { + tar_options(argc, argv); + return; + } else if (strcmp(NM_CPIO, argv0) == 0) { + cpio_options(argc, argv); + return; + } /* * assume pax as the default */ argv0 = NM_PAX; - return(pax_options(argc, argv)); + pax_options(argc, argv); } /* @@ -182,30 +188,24 @@ options(argc, argv) * the user specified a legal set of flags. If not, complain and exit */ -#ifdef __STDC__ static void -pax_options(register int argc, register char **argv) -#else -static void -pax_options(argc, argv) - register int argc; - register char **argv; -#endif +pax_options(int argc, char **argv) { - register int c; - register int i; + int c; + int i; unsigned int flg = 0; unsigned int bflg = 0; - register char *pt; + char *pt; FSUB tmp; - extern char *optarg; - extern int optind; + size_t n_fsub; + char * tmp_name; + listf = stderr; /* * process option flags */ - while ((c=getopt(argc,argv,"ab:cdf:iklno:p:rs:tuvwx:zB:DE:G:HLPT:U:XYZ")) - != EOF) { + while ((c=getopt(argc,argv,"ab:cdf:iklno:p:rs:tuvwx:zB:DE:G:HLPT:U:XYZ0")) + != -1) { switch (c) { case 'a': /* @@ -241,6 +241,13 @@ pax_options(argc, argv) /* * filename where the archive is stored */ + if ((optarg[0] == '-') && (optarg[1]== '\0')) { + /* + * treat a - as stdin (like tar) + */ + arcname = NULL; + break; + } arcname = optarg; flg |= FF; break; @@ -277,7 +284,7 @@ pax_options(argc, argv) * pass format specific options */ flg |= OF; - if (opt_add(optarg) < 0) + if (pax_format_opt_add(optarg) < 0) pax_usage(); break; case 'p': @@ -285,7 +292,7 @@ pax_options(argc, argv) * specify file characteristic options */ for (pt = optarg; *pt != '\0'; ++pt) { - switch(*pt) { + switch (*pt) { case 'a': /* * do not preserve access time @@ -316,7 +323,7 @@ pax_options(argc, argv) break; case 'p': /* - * preserver file mode bits + * preserve file mode bits */ pmode = 1; break; @@ -332,6 +339,7 @@ pax_options(argc, argv) /* * read the archive */ + pax_read_or_list_mode=1; flg |= RF; break; case 's': @@ -376,11 +384,13 @@ pax_options(argc, argv) * specify an archive format on write */ tmp.name = optarg; - if (0 == strcmp("pax", optarg)) { /* alias for ustar */ - tmp.name = "ustar"; - } +/* if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub, sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL) { +*/ + n_fsub = sizeof(fsub)/sizeof(FSUB); + if ((frmt = (FSUB *)lsearch((void *)&tmp, (void *)fsub, + &n_fsub, sizeof(FSUB), c_frmt)) != NULL) { flg |= XF; break; } @@ -395,7 +405,6 @@ pax_options(argc, argv) /* * use gzip. Non standard option. */ - zflag = 1; gzip_program = GZIP_CMD; break; case 'B': @@ -453,6 +462,8 @@ pax_options(argc, argv) */ Hflag = 1; flg |= CHF; + Lflag = 0; /* -H and -L are mutually exclusive */ + flg &= ~CLF; /* only use the last one seen */ break; case 'L': /* @@ -460,6 +471,14 @@ pax_options(argc, argv) */ Lflag = 1; flg |= CLF; + Hflag = 0; /* -H and -L are mutually exclusive */ + flg &= ~CHF; /* only use the last one seen */ + break; + case 'O': + /* + * Force one volume. Non standard option. + */ + force_one_volume = 1; break; case 'P': /* @@ -513,6 +532,14 @@ pax_options(argc, argv) Zflag = 1; flg |= CZF; break; + case '0': + /* + * Use \0 as pathname terminator. + * (For use with the -print0 option of find(1).) + */ + zeroflag = 1; + flg |= C0F; + break; default: pax_usage(); break; @@ -520,12 +547,22 @@ pax_options(argc, argv) } /* + * Fix for POSIX.cmd/pax/pax.ex test 132: force -wu options to look + * like -wua options were specified. + */ + if (uflag && (flg & WF) && !(flg & RF)) { /* -w but not -r -w */ + flg |= AF; + } + + /* * figure out the operation mode of pax read,write,extract,copy,append * or list. check that we have not been given a bogus set of flags * for the operation mode. */ if (ISLIST(flg)) { act = LIST; + pax_read_or_list_mode=1; + listf = stdout; bflg = flg & BDLIST; } else if (ISEXTRACT(flg)) { act = EXTRACT; @@ -555,6 +592,23 @@ pax_options(argc, argv) frmt = &(fsub[DEFLT]); /* + * if copying (-r and -w) and there is no -x specified, we act as + * if -x pax was specified. + */ + if (!(flg & XF) && (act == COPY)) + frmt = &(fsub[F_PAX]); + + /* + * Initialize the global extended header template. + */ + tmp_name = getenv("TMPDIR"); + if (tmp_name) { + asprintf(&header_name_g, "%s%s", tmp_name, "/GlobalHead.%p.%n"); + } else { + header_name_g = "/tmp/GlobalHead.%p.%n"; + } + + /* * process the args as they are interpreted by the operation mode */ switch (act) { @@ -592,19 +646,19 @@ pax_options(argc, argv) * the user specified a legal set of flags. If not, complain and exit */ -#ifdef __STDC__ static void -tar_options(register int argc, register char **argv) -#else -static void -tar_options(argc, argv) - register int argc; - register char **argv; -#endif +tar_options(int argc, char **argv) { - register int c; + int c; int fstdin = 0; int Oflag = 0; + int nincfiles = 0; + int incfiles_max = 0; + struct incfile { + char *file; + char *dir; + }; + struct incfile *incfiles = NULL; /* * Set default values. @@ -615,9 +669,8 @@ tar_options(argc, argv) * process option flags */ while ((c = getoldopt(argc, argv, - "b:cef:hmopruts:vwxzBC:HLOPXZ014578")) - != EOF) { - switch(c) { + "b:cef:hmopqruts:vwxzBC:HI:LOPXZ014578")) != -1) { + switch (c) { case 'b': /* * specify blocksize in 512-byte blocks @@ -667,21 +720,24 @@ tar_options(argc, argv) */ pmtime = 0; break; - case 'o': - if (opt_add("write_opt=nodir") < 0) - tar_usage(); case 'O': Oflag = 1; break; + case 'o': + Oflag = 2; + break; case 'p': /* - * preserve user id, group id, file - * mode, access/modification times + * preserve uid/gid and file mode, regardless of umask */ - pids = 1; pmode = 1; - patime = 1; - pmtime = 1; + pids = 1; + break; + case 'q': + /* + * select first match for a pattern only + */ + nflag = 1; break; case 'r': case 'u': @@ -719,17 +775,16 @@ tar_options(argc, argv) break; case 'x': /* - * write an archive, preserve ids if root + * extract an archive, preserving mode, + * and mtime if possible. */ act = EXTRACT; - if (geteuid() == 0) - pids = 1; + pmtime = 1; break; case 'z': /* * use gzip. Non standard option. */ - zflag = 1; gzip_program = GZIP_CMD; break; case 'B': @@ -746,6 +801,20 @@ tar_options(argc, argv) */ Hflag = 1; break; + case 'I': + if (++nincfiles > incfiles_max) { + incfiles_max = nincfiles + 3; + incfiles = realloc(incfiles, + sizeof(*incfiles) * incfiles_max); + if (incfiles == NULL) { + paxwarn(0, "Unable to allocate space " + "for option list"); + exit(1); + } + } + incfiles[nincfiles - 1].file = optarg; + incfiles[nincfiles - 1].dir = chdname; + break; case 'L': /* * follow symlinks @@ -768,7 +837,6 @@ tar_options(argc, argv) /* * use compress. */ - zflag = 1; gzip_program = COMPRESS_CMD; break; case '0': @@ -797,20 +865,15 @@ tar_options(argc, argv) argc -= optind; argv += optind; - /* Traditional tar behaviour (pax wants to read filelist from stdin) */ - if ((act == ARCHIVE || act == APPND) && argc == 0) - exit(0); + /* Traditional tar behaviour (pax uses stderr unless in list mode) */ + if (fstdin == 1 && act == ARCHIVE) + listf = stderr; + else + listf = stdout; - /* - * if we are writing (ARCHIVE) specify tar, otherwise run like pax - * (unless -o specified) - */ - if (act == ARCHIVE || act == APPND) - frmt = &(fsub[Oflag ? F_OTAR : F_TAR]); - else if (Oflag) { - paxwarn(1, "The -O/-o options are only valid when writing an archive"); - tar_usage(); /* only valid when writing */ - } + /* Traditional tar behaviour (pax wants to read file list from stdin) */ + if ((act == ARCHIVE || act == APPND) && argc == 0 && nincfiles == 0) + exit(0); /* * process the args as they are interpreted by the operation mode @@ -821,22 +884,61 @@ tar_options(argc, argv) default: { int sawpat = 0; + char *file, *dir; - while (*argv != NULL) { - if (strcmp(*argv, "-C") == 0) { - if(*++argv == NULL) + while (nincfiles || *argv != NULL) { + /* + * If we queued up any include files, + * pull them in now. Otherwise, check + * for -I and -C positional flags. + * Anything else must be a file to + * extract. + */ + if (nincfiles) { + file = incfiles->file; + dir = incfiles->dir; + incfiles++; + nincfiles--; + } else if (strcmp(*argv, "-I") == 0) { + if (*++argv == NULL) + break; + file = *argv++; + dir = chdname; + } else + file = NULL; + if (file != NULL) { + FILE *fp; + char *str; + + if (strcmp(file, "-") == 0) + fp = stdin; + else if ((fp = fopen(file, "r")) == NULL) { + paxwarn(1, "Unable to open file '%s' for read", file); + tar_usage(); + } + while ((str = getline(fp)) != NULL) { + if (pat_add(str, dir) < 0) + tar_usage(); + sawpat = 1; + } + if (strcmp(file, "-") != 0) + fclose(fp); + if (getline_error) { + paxwarn(1, "Problem with file '%s'", file); + tar_usage(); + } + } else if (strcmp(*argv, "-C") == 0) { + if (*++argv == NULL) break; chdname = *argv++; - - continue; - } - if (pat_add(*argv++, chdname) < 0) + } else if (pat_add(*argv++, chdname) < 0) tar_usage(); - sawpat++; + else + sawpat = 1; } /* * if patterns were added, we are doing chdir() - * on a file-by-file basis, else, just one + * on a file-by-file basis, else, just one * global chdir (if any) after opening input. */ if (sawpat > 0) @@ -845,21 +947,71 @@ tar_options(argc, argv) break; case ARCHIVE: case APPND: + frmt = &(fsub[Oflag ? F_OTAR : F_TAR]); + + if (Oflag == 2 && opt_add("write_opt=nodir") < 0) + tar_usage(); + if (chdname != NULL) { /* initial chdir() */ if (ftree_add(chdname, 1) < 0) tar_usage(); } - while (*argv != NULL) { - if (!strcmp(*argv, "-C")) { + while (nincfiles || *argv != NULL) { + char *file, *dir; + + /* + * If we queued up any include files, pull them in + * now. Otherwise, check for -I and -C positional + * flags. Anything else must be a file to include + * in the archive. + */ + if (nincfiles) { + file = incfiles->file; + dir = incfiles->dir; + incfiles++; + nincfiles--; + } else if (strcmp(*argv, "-I") == 0) { if (*++argv == NULL) break; - if (ftree_add(*argv++, 1) < 0) + file = *argv++; + dir = NULL; + } else + file = NULL; + if (file != NULL) { + FILE *fp; + char *str; + + /* Set directory if needed */ + if (dir) { + if (ftree_add(dir, 1) < 0) + tar_usage(); + } + + if (strcmp(file, "-") == 0) + fp = stdin; + else if ((fp = fopen(file, "r")) == NULL) { + paxwarn(1, "Unable to open file '%s' for read", file); + tar_usage(); + } + while ((str = getline(fp)) != NULL) { + if (ftree_add(str, 0) < 0) + tar_usage(); + } + if (strcmp(file, "-") != 0) + fclose(fp); + if (getline_error) { + paxwarn(1, "Problem with file '%s'", + file); tar_usage(); - } else { - if (ftree_add(*argv++, 0) < 0) + } + } else if (strcmp(*argv, "-C") == 0) { + if (*++argv == NULL) + break; + if (ftree_add(*argv++, 1) < 0) tar_usage(); - } + } else if (ftree_add(*argv++, 0) < 0) + tar_usage(); } /* * no read errors allowed on updates/append operation! @@ -874,12 +1026,14 @@ tar_options(argc, argv) } } +int mkpath(char *); + int mkpath(path) char *path; { struct stat sb; - register char *slash; + char *slash; int done = 0; slash = path; @@ -913,23 +1067,18 @@ mkpath(path) * the user specified a legal set of flags. If not, complain and exit */ -#ifdef __STDC__ -static void -cpio_options(register int argc, register char **argv) -#else static void -cpio_options(argc, argv) - register int argc; - register char **argv; -#endif +cpio_options(int argc, char **argv) { - register int c, i; - size_t len; + int c, i; char *str; FSUB tmp; FILE *fp; + size_t n_fsub; - kflag = 1; + listf = stderr; + kflag = 0; + uflag = 1; pids = 1; pmode = 1; pmtime = 0; @@ -937,7 +1086,7 @@ cpio_options(argc, argv) dflag = 1; act = -1; nodirs = 1; - while ((c=getopt(argc,argv,"abcdfiklmoprstuvzABC:E:F:H:I:LO:SZ6")) != EOF) + while ((c=getopt(argc,argv,"abcdfiklmoprstuvzABC:E:F:H:I:LO:SZ6")) != -1) switch (c) { case 'a': /* @@ -1017,12 +1166,13 @@ cpio_options(argc, argv) * list contents of archive */ act = LIST; + listf = stdout; break; case 'u': /* * replace newer files */ - kflag = 0; + uflag = 0; break; case 'v': /* @@ -1034,7 +1184,6 @@ cpio_options(argc, argv) /* * use gzip. Non standard option. */ - zflag = 1; gzip_program = GZIP_CMD; break; case 'A': @@ -1063,11 +1212,14 @@ cpio_options(argc, argv) paxwarn(1, "Unable to open file '%s' for read", optarg); cpio_usage(); } - while ((str = fgetln(fp, &len)) != NULL) { - str[len - 1] = '\0'; + while ((str = getline(fp)) != NULL) { pat_add(str, NULL); } fclose(fp); + if (getline_error) { + paxwarn(1, "Problem with file '%s'", optarg); + cpio_usage(); + } break; case 'F': case 'I': @@ -1089,8 +1241,13 @@ cpio_options(argc, argv) * specify an archive format on write */ tmp.name = optarg; +/* if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub, sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL) +*/ + n_fsub = sizeof(fsub)/sizeof(FSUB); + if ((frmt = (FSUB *)lsearch((void *)&tmp, (void *)fsub, + &n_fsub, sizeof(FSUB), c_frmt)) != NULL) break; paxwarn(1, "Unknown -H format: %s", optarg); (void)fputs("cpio: Known -H formats are:", stderr); @@ -1114,7 +1271,6 @@ cpio_options(argc, argv) /* * use compress. Non standard option. */ - zflag = 1; gzip_program = COMPRESS_CMD; break; case '6': @@ -1160,9 +1316,12 @@ cpio_options(argc, argv) * no read errors allowed on updates/append operation! */ maxflt = 0; - while ((str = fgetln(stdin, &len)) != NULL) { - str[len - 1] = '\0'; - ftree_add(strdup(str), NULL); + while ((str = getline(stdin)) != NULL) { + ftree_add(str, 0); + } + if (getline_error) { + paxwarn(1, "Problem while reading stdin"); + cpio_usage(); } break; default: @@ -1176,14 +1335,8 @@ cpio_options(argc, argv) * print out those invalid flag sets found to the user */ -#ifdef __STDC__ static void printflg(unsigned int flg) -#else -static void -printflg(flg) - unsigned int flg; -#endif { int nxt; int pos = 0; @@ -1203,15 +1356,8 @@ printflg(flg) * by the user */ -#ifdef __STDC__ static int c_frmt(const void *a, const void *b) -#else -static int -c_frmt(a, b) - void *a; - void *b; -#endif { return(strcmp(((FSUB *)a)->name, ((FSUB *)b)->name)); } @@ -1224,13 +1370,8 @@ c_frmt(a, b) * pointer to next OPLIST entry or NULL (end of list). */ -#ifdef __STDC__ OPLIST * opt_next(void) -#else -OPLIST * -opt_next() -#endif { OPLIST *opt; @@ -1245,15 +1386,10 @@ opt_next() * when the format does not support options. */ -#ifdef __STDC__ int bad_opt(void) -#else -int -bad_opt() -#endif { - register OPLIST *opt; + OPLIST *opt; if (ophead == NULL) return(0); @@ -1261,8 +1397,15 @@ bad_opt() * print all we were given */ paxwarn(1,"These format options are not supported"); - while ((opt = opt_next()) != NULL) - (void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value); + while ((opt = opt_next()) != NULL) { + if (opt->separator == SEP_EQ) { + (void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value); + } else if (opt->separator == SEP_COLONEQ ) { + (void)fprintf(stderr, "\t%s := %s\n", opt->name, opt->value); + } else { /* SEP_NONE */ + (void)fprintf(stderr, "\t%s\n", opt->name); + } + } pax_usage(); return(0); } @@ -1271,24 +1414,85 @@ bad_opt() * opt_add() * breaks the value supplied to -o into a option name and value. options * are given to -o in the form -o name-value,name=value - * mulltiple -o may be specified. + * multiple -o may be specified. * Return: * 0 if format in name=value format, -1 if -o is passed junk */ -#ifdef __STDC__ int -opt_add(register char *str) -#else +opt_add(const char *str) +{ + OPLIST *opt; + char *frpt; + char *pt; + char *endpt; + char *dstr; + + if ((str == NULL) || (*str == '\0')) { + paxwarn(0, "Invalid option name"); + return(-1); + } + if ((dstr = strdup(str)) == NULL) { + paxwarn(0, "Unable to allocate space for option list"); + return(-1); + } + frpt = endpt = dstr; + + /* + * break into name and values pieces and stuff each one into a + * OPLIST structure. When we know the format, the format specific + * option function will go through this list + */ + while ((frpt != NULL) && (*frpt != '\0')) { + if ((endpt = strchr(frpt, ',')) != NULL) + *endpt = '\0'; + if ((pt = strchr(frpt, '=')) == NULL) { + paxwarn(0, "Invalid options format"); + free(dstr); + return(-1); + } + if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) { + paxwarn(0, "Unable to allocate space for option list"); + free(dstr); + return(-1); + } + *pt++ = '\0'; + opt->name = frpt; + opt->value = pt; + opt->separator = SEP_EQ; + opt->fow = NULL; + if (endpt != NULL) + frpt = endpt + 1; + else + frpt = NULL; + if (ophead == NULL) { + optail = ophead = opt; + continue; + } + optail->fow = opt; + optail = opt; + } + return(0); +} + + +/* + * pax_format_opt_add() + * breaks the value supplied to -o into a option name and value. options + * are given to -o in the form -o name-value,name=value + * multiple -o may be specified. + * Return: + * 0 if format in name=value format, -1 if -o is passed junk + */ + int -opt_add(str) - register char *str; -#endif +pax_format_opt_add(register char *str) { register OPLIST *opt; register char *frpt; register char *pt; register char *endpt; + register int separator; if ((str == NULL) || (*str == '\0')) { paxwarn(0, "Invalid option name"); @@ -1308,19 +1512,25 @@ opt_add(str) while ((frpt != NULL) && (*frpt != '\0')) { if ((endpt = strchr(frpt, ',')) != NULL) *endpt = '\0'; - if ((pt = strchr(frpt, '=')) == NULL) { - paxwarn(0, "Invalid options format"); - free(str); - return(-1); + if ((pt = strstr(frpt, ":=")) != NULL) { + *pt++ = '\0'; + pt++; /* beyond the := */ + separator = SEP_COLONEQ; + } else if ((pt = strchr(frpt, '=')) != NULL) { + *pt++ = '\0'; + separator = SEP_EQ; + } else { + /* keyword with no value */ + separator = SEP_NONE; } if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) { paxwarn(0, "Unable to allocate space for option list"); free(str); return(-1); } - *pt++ = '\0'; opt->name = frpt; opt->value = pt; + opt->separator = separator; opt->fow = NULL; if (endpt != NULL) frpt = endpt + 1; @@ -1345,25 +1555,19 @@ opt_add(str) * 4) A positive decimal number followed by a m (mult by 512). * 5) A positive decimal number followed by a w (mult by sizeof int) * 6) Two or more positive decimal numbers (with/without k,b or w). - * seperated by x (also * for backwards compatibility), specifying + * separated by x (also * for backwards compatibility), specifying * the product of the indicated values. * Return: * 0 for an error, a positive value o.w. */ -#ifdef __STDC__ static off_t str_offt(char *val) -#else -static off_t -str_offt(val) - char *val; -#endif { char *expr; off_t num, t; -# ifdef NET2_STAT +# ifdef LONG_OFF_T num = strtol(val, &expr, 0); if ((num == LONG_MAX) || (num <= 0) || (expr == val)) # else @@ -1372,7 +1576,7 @@ str_offt(val) # endif return(0); - switch(*expr) { + switch (*expr) { case 'b': t = num; num *= 512; @@ -1403,7 +1607,7 @@ str_offt(val) break; } - switch(*expr) { + switch (*expr) { case '\0': break; case '*': @@ -1419,6 +1623,29 @@ str_offt(val) return(num); } +char * +getline(FILE *f) +{ + char *name, *temp; + size_t len; + + name = fgetln(f, &len); + if (!name) { + getline_error = ferror(f) ? GETLINE_FILE_CORRUPT : 0; + return(0); + } + if (name[len-1] != '\n') + len++; + temp = malloc(len); + if (!temp) { + getline_error = GETLINE_OUT_OF_MEM; + return(0); + } + memcpy(temp, name, len-1); + temp[len-1] = 0; + return(temp); +} + /* * no_op() * for those option functions where the archive format has nothing to do. @@ -1426,13 +1653,8 @@ str_offt(val) * 0 */ -#ifdef __STDC__ static int no_op(void) -#else -static int -no_op() -#endif { return(0); } @@ -1442,33 +1664,28 @@ no_op() * print the usage summary to the user */ -#ifdef __STDC__ void pax_usage(void) -#else -void -pax_usage() -#endif { - (void)fputs("usage: pax [-cdnv] [-E limit] [-f archive] ", stderr); + (void)fputs("usage: pax [-cdnvzO] [-E limit] [-f archive] ", stderr); (void)fputs("[-s replstr] ... [-U user] ...", stderr); (void)fputs("\n [-G group] ... ", stderr); (void)fputs("[-T [from_date][,to_date]] ... ", stderr); (void)fputs("[pattern ...]\n", stderr); - (void)fputs(" pax -r [-cdiknuvDYZ] [-E limit] ", stderr); + (void)fputs(" pax -r [-cdiknuvzDOYZ] [-E limit] ", stderr); (void)fputs("[-f archive] [-o options] ... \n", stderr); (void)fputs(" [-p string] ... [-s replstr] ... ", stderr); (void)fputs("[-U user] ... [-G group] ...\n ", stderr); (void)fputs("[-T [from_date][,to_date]] ... ", stderr); (void)fputs(" [pattern ...]\n", stderr); - (void)fputs(" pax -w [-dituvHLPX] [-b blocksize] ", stderr); + (void)fputs(" pax -w [-dituvzHLOPX] [-b blocksize] ", stderr); (void)fputs("[ [-a] [-f archive] ] [-x format] \n", stderr); (void)fputs(" [-B bytes] [-s replstr] ... ", stderr); (void)fputs("[-o options] ... [-U user] ...", stderr); (void)fputs("\n [-G group] ... ", stderr); (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr); (void)fputs("[file ...]\n", stderr); - (void)fputs(" pax -r -w [-diklntuvDHLPXYZ] ", stderr); + (void)fputs(" pax -r -w [-diklntuvDHLOPXYZ] ", stderr); (void)fputs("[-p string] ... [-s replstr] ...", stderr); (void)fputs("\n [-U user] ... [-G group] ... ", stderr); (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr); @@ -1481,17 +1698,12 @@ pax_usage() * print the usage summary to the user */ -#ifdef __STDC__ void tar_usage(void) -#else -void -tar_usage() -#endif { - (void)fputs("usage: tar -{txru}[cevfbmopswzBHLPXZ014578] [tapefile] ", + (void)fputs("usage: tar [-]{crtux}[-befhmopqsvwzHLOPXZ014578] [blocksize] ", stderr); - (void)fputs("[blocksize] [replstr] [-C directory] file1 file2...\n", + (void)fputs("[archive] [replstr] [-C directory] [-I file] [file ...]\n", stderr); exit(1); } @@ -1501,13 +1713,8 @@ tar_usage() * print the usage summary to the user */ -#ifdef __STDC__ void cpio_usage(void) -#else -void -cpio_usage() -#endif { (void)fputs("usage: cpio -o [-aABcLvVzZ] [-C bytes] [-H format] [-O archive]\n", stderr); (void)fputs(" [-F archive] < name-list [> archive]\n", stderr); diff --git a/pax/options.h b/pax/options.h index d45f54a..873d8d5 100644 --- a/pax/options.h +++ b/pax/options.h @@ -1,4 +1,4 @@ -/* $OpenBSD: options.h,v 1.2 1996/06/23 14:20:37 deraadt Exp $ */ +/* $OpenBSD: options.h,v 1.4 2003/06/13 17:51:14 millert Exp $ */ /* $NetBSD: options.h,v 1.3 1995/03/21 09:07:32 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -88,12 +84,13 @@ #define CXF 0x08000000 #define CYF 0x10000000 /* nonstandard extension */ #define CZF 0x20000000 /* nonstandard extension */ +#define C0F 0x40000000 /* 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 "abcdfiklnoprstuvwxBDEGHLPTUXYZ0" /* * legal pax operation bit patterns @@ -112,5 +109,5 @@ #define BDEXTR (AF|BF|LF|TF|WF|XF|CBF|CHF|CLF|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|CBF|CEF) +#define BDLIST (AF|BF|IF|KF|LF|PF|RF|TF|UF|WF|XF|CBF|CDF|CHF|CLF|CPF|CXF|CYF|CZF) diff --git a/pax/pat_rep.c b/pax/pat_rep.c index 9ff1dca..5f46864 100644 --- a/pax/pat_rep.c +++ b/pax/pat_rep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pat_rep.c,v 1.11 1997/09/01 18:29:56 deraadt Exp $ */ +/* $OpenBSD: pat_rep.c,v 1.28 2004/06/11 03:10:43 millert Exp $ */ /* $NetBSD: pat_rep.c,v 1.4 1995/03/21 09:07:33 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)pat_rep.c 8.2 (Berkeley) 4/18/94"; +static const char sccsid[] = "@(#)pat_rep.c 8.2 (Berkeley) 4/18/94"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: pat_rep.c,v 1.11 1997/09/01 18:29:56 deraadt Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: pat_rep.c,v 1.28 2004/06/11 03:10:43 millert Exp $"; #endif #endif /* not lint */ @@ -55,11 +51,7 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: pat_rep.c,v 1.11 19 #include #include #include -#ifdef NET2_REGEX -#include -#else #include -#endif #include "pax.h" #include "pat_rep.h" #include "extern.h" @@ -77,23 +69,19 @@ 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 __P((char *, int *, int)); -static int tty_rename __P((register ARCHD *)); -static int fix_path __P((char *, int *, char *, int)); -static int fn_match __P((register char *, register char *, char **)); -static char * range_match __P((register char *, register int)); -#ifdef NET2_REGEX -static int resub __P((regexp *, char *, char *, register char *)); -#else -static int resub __P((regex_t *, regmatch_t *, char *, char *, char *)); -#endif +static int rep_name(char *, size_t, int *, int); +int tty_rename(ARCHD *); +static int fix_path(char *, int *, char *, int); +static int fn_match(char *, char *, char **); +static char * range_match(char *, int); +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 * replacement string list. Input to this function is of the form: - * /old/new/pg + * /old/new/pg * The first char in the string specifies the delimiter used by this * replacement string. "Old" is a regular expression in "ed" format which * is compiled by regcomp() and is applied to filenames. "new" is the @@ -104,22 +92,14 @@ static int resub __P((regex_t *, regmatch_t *, char *, char *, char *)); * the list of replacement patterns; -1 otherwise. */ -#ifdef __STDC__ int -rep_add(register char *str) -#else -int -rep_add(str) - register char *str; -#endif +rep_add(char *str) { - register char *pt1; - register char *pt2; - register REPLACE *rep; -# ifndef NET2_REGEX - register int res; + char *pt1; + char *pt2; + REPLACE *rep; + int res; char rebuf[BUFSIZ]; -# endif /* * throw out the bad parameters @@ -133,7 +113,15 @@ rep_add(str) * first character in the string specifies what the delimiter is for * this expression */ - if ((pt1 = strchr(str+1, *str)) == NULL) { + for (pt1 = str+1; *pt1; pt1++) { + if (*pt1 == '\\') { + pt1++; + continue; + } + if (*pt1 == *str) + break; + } + if (*pt1 == '\0') { paxwarn(1, "Invalid replacement string %s", str); return(-1); } @@ -148,13 +136,9 @@ rep_add(str) } *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 (void)free((char *)rep); return(-1); } @@ -165,12 +149,16 @@ rep_add(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); @@ -185,7 +173,7 @@ rep_add(str) * set the options if any */ while (*pt2 != '\0') { - switch(*pt2) { + switch (*pt2) { case 'g': case 'G': rep->flgs |= GLOB; @@ -195,11 +183,7 @@ rep_add(str) rep->flgs |= PRNT; 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); @@ -232,17 +216,10 @@ rep_add(str) * 0 if the pattern was added to the list, -1 otherwise */ -#ifdef __STDC__ int pat_add(char *str, char *chdname) -#else -int -pat_add(str, chdname) - char *str; - char *chdname; -#endif { - register PATTERN *pt; + PATTERN *pt; /* * throw out the junk @@ -284,16 +261,11 @@ pat_add(str, chdname) * a selected archive member. */ -#ifdef __STDC__ void pat_chk(void) -#else -void -pat_chk() -#endif { - register PATTERN *pt; - register int wban = 0; + PATTERN *pt; + int wban = 0; /* * walk down the list checking the flags to make sure MTCH was set, @@ -318,26 +290,20 @@ pat_chk() * * 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 a archive member to NOT + * 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. */ -#ifdef __STDC__ int -pat_sel(register ARCHD *arcn) -#else -int -pat_sel(arcn) - register ARCHD *arcn; -#endif +pat_sel(ARCHD *arcn) { - register PATTERN *pt; - register PATTERN **ppt; - register int len; + PATTERN *pt; + PATTERN **ppt; + int len; /* * if no patterns just return @@ -356,7 +322,7 @@ pat_sel(arcn) /* * we reach this point only when we allow a single selected match per - * pattern, if the pattern matches a directory and we do not have -d + * pattern, if the pattern matches a directory and we do not have -d * (dflag) we are done with this pattern. We may also be handed a file * in the subtree of a directory. in that case when we are operating * with -d, this pattern was already selected and we are done @@ -415,7 +381,7 @@ pat_sel(arcn) * 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. */ @@ -430,7 +396,7 @@ pat_sel(arcn) /* * should never happen.... */ - paxwarn(1, "Pattern list inconsistant"); + paxwarn(1, "Pattern list inconsistent"); return(-1); } *ppt = pt->fow; @@ -446,21 +412,15 @@ pat_sel(arcn) * this archive member is "selected" we process and mark the pattern as * one which matched a selected archive member (see pat_sel()) * Return: - * 0 if this archive member should be processed, 1 if it should be + * 0 if this archive member should be processed, 1 if it should be * skipped and -1 if we are done with all patterns (and pax should quit * looking for more members) */ -#ifdef __STDC__ -int -pat_match(register ARCHD *arcn) -#else int -pat_match(arcn) - register ARCHD *arcn; -#endif +pat_match(ARCHD *arcn) { - register PATTERN *pt; + PATTERN *pt; arcn->pat = NULL; @@ -523,24 +483,16 @@ pat_match(arcn) /* * fn_match() * Return: - * 0 if this archive member should be processed, 1 if it should be + * 0 if this archive member should be processed, 1 if it should be * skipped and -1 if we are done with all patterns (and pax should quit * looking for more members) * Note: *pend may be changed to show where the prefix ends. */ -#ifdef __STDC__ static int -fn_match(register char *pattern, register char *string, char **pend) -#else -static int -fn_match(pattern, string, pend) - register char *pattern; - register char *string; - char **pend; -#endif +fn_match(char *pattern, char *string, char **pend) { - register char c; + char c; char test; *pend = NULL; @@ -572,7 +524,7 @@ fn_match(pattern, string, pend) case '*': c = *pattern; /* - * Collapse multiple *'s. + * Collapse multiple *'s. */ while (c == '*') c = *++pattern; @@ -610,18 +562,11 @@ fn_match(pattern, string, pend) /* NOTREACHED */ } -#ifdef __STDC__ static char * -range_match(register char *pattern, register int test) -#else -static char * -range_match(pattern, test) - register char *pattern; - register int test; -#endif +range_match(char *pattern, int test) { - register char c; - register char c2; + char c; + char c2; int negate; int ok = 0; @@ -657,19 +602,13 @@ range_match(pattern, test) * if we spot any file links to the old file name in the future, we will * know exactly how to fix the file link. * Return: - * 0 continue to process file, 1 skip this file, -1 pax is finished + * 0 continue to process file, 1 skip this file, -1 pax is finished */ -#ifdef __STDC__ int -mod_name(register ARCHD *arcn) -#else -int -mod_name(arcn) - register ARCHD *arcn; -#endif +mod_name(ARCHD *arcn) { - register int res = 0; + int res = 0; /* * Strip off leading '/' if appropriate. @@ -727,12 +666,12 @@ mod_name(arcn) * we have replacement strings, modify the name and the link * name if any. */ - if ((res = rep_name(arcn->name, &(arcn->nlen), 1)) != 0) + if ((res = rep_name(arcn->name, sizeof(arcn->name), &(arcn->nlen), 1)) != 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)) + ((res = rep_name(arcn->ln_name, sizeof(arcn->ln_name), &(arcn->ln_nlen), 0)) != 0)) return(res); } @@ -759,14 +698,8 @@ mod_name(arcn) * 0 process this file, 1 skip this file, -1 we need to exit pax */ -#ifdef __STDC__ -static int -tty_rename(register ARCHD *arcn) -#else -static int -tty_rename(arcn) - register ARCHD *arcn; -#endif +int +tty_rename(ARCHD *arcn) { char tmpname[PAXPATHLEN+2]; int res; @@ -816,8 +749,7 @@ tty_rename(arcn) */ tty_prnt("Processing continues, name changed to: %s\n", tmpname); res = add_name(arcn->name, arcn->nlen, tmpname); - arcn->nlen = l_strncpy(arcn->name, tmpname, 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); @@ -831,16 +763,8 @@ tty_rename(arcn) * 0 if ok, -1 if failure (name too long) */ -#ifdef __STDC__ -int -set_dest(register ARCHD *arcn, char *dest_dir, int dir_len) -#else int -set_dest(arcn, dest_dir, dir_len) - register ARCHD *arcn; - char *dest_dir; - int dir_len; -#endif +set_dest(ARCHD *arcn, char *dest_dir, int dir_len) { if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0) return(-1); @@ -866,21 +790,12 @@ set_dest(arcn, dest_dir, dir_len) * 0 if ok, -1 if the final name is too long */ -#ifdef __STDC__ -static int -fix_path( char *or_name, int *or_len, char *dir_name, int dir_len) -#else static int -fix_path(or_name, or_len, dir_name, dir_len) - char *or_name; - int *or_len; - char *dir_name; - int dir_len; -#endif +fix_path(char *or_name, int *or_len, char *dir_name, int dir_len) { - register char *src; - register char *dest; - register char *start; + char *src; + char *dest; + char *start; int len; /* @@ -903,7 +818,7 @@ fix_path(or_name, or_len, dir_name, dir_len) *or_len = len; /* - * enough space, shift + * enough space, shift */ while (src >= start) *dest-- = *src--; @@ -930,6 +845,7 @@ fix_path(or_name, or_len, dir_name, dir_len) * --Parameters-- * name is the file name we are going to apply the regular expressions to * (and may be modified) + * nsize is 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. @@ -938,27 +854,17 @@ fix_path(or_name, or_len, dir_name, dir_len) * ended up empty) */ -#ifdef __STDC__ -static int -rep_name(char *name, int *nlen, int prnt) -#else static int -rep_name(name, nlen, prnt) - char *name; - int *nlen; - int prnt; -#endif +rep_name(char *name, size_t nsize, int *nlen, int prnt) { - register REPLACE *pt; - register char *inpt; - register char *outpt; - register char *endpt; - register char *rpt; - register int found = 0; - register int res; -# ifndef NET2_REGEX + REPLACE *pt; + char *inpt; + char *outpt; + char *endpt; + char *rpt; + int found = 0; + int res; regmatch_t pm[MAXSUBEXP]; -# endif char nname[PAXPATHLEN+1]; /* final result of all replacements */ char buf1[PAXPATHLEN+1]; /* where we work on the name */ @@ -971,7 +877,7 @@ rep_name(name, nlen, prnt) * (the user already saw that substitution go by) */ pt = rephead; - (void)strcpy(buf1, name); + (void)strlcpy(buf1, name, sizeof(buf1)); inpt = buf1; outpt = nname; endpt = outpt + PAXPATHLEN; @@ -981,15 +887,12 @@ rep_name(name, nlen, prnt) */ while (pt != NULL) { do { + char *oinpt = inpt; /* * 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; /* @@ -1000,11 +903,7 @@ rep_name(name, nlen, 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++; @@ -1017,12 +916,8 @@ rep_name(name, nlen, 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)) + if ((res = resub(&(pt->rcmp),pm,pt->nstr,oinpt,outpt,endpt)) < 0) { -# endif if (prnt) paxwarn(1, "Replacement name error %s", name); @@ -1040,11 +935,7 @@ rep_name(name, nlen, 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; @@ -1097,98 +988,28 @@ rep_name(name, nlen, prnt) */ if (*nname == '\0') return(1); - *nlen = l_strncpy(name, nname, PAXPATHLEN + 1); - name[PAXPATHLEN] = '\0'; + *nlen = strlcpy(name, nname, nsize); } return(0); } -#ifdef NET2_REGEX /* * 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. */ -#ifdef __STDC__ -static int -resub(regexp *prog, char *src, char *dest, register char *destend) -#else static int -resub(prog, src, dest, destend) - regexp *prog; - char *src; - char *dest; - register char *destend; -#endif +resub(regex_t *rp, regmatch_t *pm, char *src, char *inpt, char *dest, + char *destend) { - register char *spt; - register char *dpt; - register char c; - register int no; - register int len; - - spt = src; - dpt = dest; - while ((dpt < destend) && ((c = *spt++) != '\0')) { - if (c == '&') - no = 0; - else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) - no = *spt++ - '0'; - else { - if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) - c = *spt++; - *dpt++ = c; - continue; - } - if ((prog->startp[no] == NULL) || (prog->endp[no] == NULL) || - ((len = prog->endp[no] - prog->startp[no]) <= 0)) - continue; - - /* - * copy the subexpression to the destination. - * fail if we run out of space or the match string is damaged - */ - if (len > (destend - dpt)) - len = destend - dpt; - if (l_strncpy(dpt, prog->startp[no], len) != len) - return(-1); - dpt += len; - } - return(dpt - dest); -} - -#else - -/* - * 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. - */ - -#ifdef __STDC__ -static int -resub(regex_t *rp, register regmatch_t *pm, char *src, char *dest, - register char *destend) -#else -static int -resub(rp, pm, src, dest, destend) - regex_t *rp; - register regmatch_t *pm; - char *src; - char *dest; - register char *destend; -#endif -{ - register char *spt; - register char *dpt; - register char c; - register regmatch_t *pmpt; - register int len; + char *spt; + char *dpt; + char c; + regmatch_t *pmpt; + int len; int subexcnt; spt = src; @@ -1209,12 +1030,12 @@ resub(rp, pm, src, dest, destend) return(-1); pmpt = pm + len; } else { - /* + /* * Ordinary character, just copy it */ - if ((c == '\\') && ((*spt == '\\') || (*spt == '&'))) - c = *spt++; - *dpt++ = c; + if ((c == '\\') && (*spt != '\0')) + c = *spt++; + *dpt++ = c; continue; } @@ -1230,11 +1051,9 @@ resub(rp, pm, src, dest, destend) * 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, inpt + pmpt->rm_so, len); dpt += len; } return(dpt - dest); } -#endif diff --git a/pax/pat_rep.h b/pax/pat_rep.h index b41f1e1..72b8bee 100644 --- a/pax/pat_rep.h +++ b/pax/pat_rep.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pat_rep.h,v 1.2 1996/06/23 14:20:38 deraadt Exp $ */ +/* $OpenBSD: pat_rep.h,v 1.4 2003/06/02 23:32:08 millert Exp $ */ /* $NetBSD: pat_rep.h,v 1.3 1995/03/21 09:07:35 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -45,13 +41,11 @@ */ 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 struct replace *fow; /* pointer to next pattern */ } REPLACE; + +int tty_rename(ARCHD *); /* Used for -o invalid=rename recovery */ diff --git a/pax/pax.1 b/pax/pax.1 index 8df49bd..0ad62b3 100644 --- a/pax/pax.1 +++ b/pax/pax.1 @@ -1,3 +1,6 @@ +.\" $OpenBSD: pax.1,v 1.44 2004/02/19 19:15:32 jmc Exp $ +.\" $NetBSD: pax.1,v 1.3 1995/03/21 09:07:37 cgd Exp $ +.\" .\" Copyright (c) 1992 Keith Muller. .\" Copyright (c) 1992, 1993 .\" The Regents of the University of California. All rights reserved. @@ -13,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. .\" @@ -30,31 +33,30 @@ .\" SUCH DAMAGE. .\" .\" @(#)pax.1 8.4 (Berkeley) 4/18/94 -.\" $FreeBSD: src/bin/pax/pax.1,v 1.33 2004/07/03 02:03:44 tjr Exp $ .\" -.Dd July 3, 2004 +.Dd April 18, 1994 .Dt PAX 1 .Os .Sh NAME .Nm pax .Nd read and write file archives and copy directory hierarchies .Sh SYNOPSIS -.Nm -.Op Fl cdnvz +.Nm pax +.Op Fl 0cdnvz .Bk -words .Op Fl f Ar archive .Ek .Bk -words .Op Fl s Ar replstr -.Ar ...\& +.Ar ... .Ek .Bk -words .Op Fl U Ar user -.Ar ...\& +.Ar ... .Ek .Bk -words .Op Fl G Ar group -.Ar ...\& +.Ar ... .Ek .Bk -words .Oo @@ -62,10 +64,10 @@ .Op Ar from_date .Op Ar ,to_date .Oc -.Ar ...\& +.Ar ... .Ek -.Op Ar pattern ...\& -.Nm +.Op Ar pattern ... +.Nm pax .Fl r .Op Fl cdiknuvzDYZ .Bk -words @@ -73,24 +75,24 @@ .Ek .Bk -words .Op Fl o Ar options -.Ar ...\& +.Ar ... .Ek .Bk -words .Op Fl p Ar string -.Ar ...\& +.Ar ... .Ek .Bk -words .Op Fl s Ar replstr -.Ar ...\& +.Ar ... .Ek .Op Fl E Ar limit .Bk -words .Op Fl U Ar user -.Ar ...\& +.Ar ... .Ek .Bk -words .Op Fl G Ar group -.Ar ...\& +.Ar ... .Ek .Bk -words .Oo @@ -98,12 +100,12 @@ .Op Ar from_date .Op Ar ,to_date .Oc -.Ar ...\& +.Ar ... .Ek -.Op Ar pattern ...\& -.Nm +.Op Ar pattern ... +.Nm pax .Fl w -.Op Fl dituvzHLPX +.Op Fl 0dituvzHLPX .Bk -words .Op Fl b Ar blocksize .Ek @@ -116,19 +118,19 @@ .Ek .Bk -words .Op Fl s Ar replstr -.Ar ...\& +.Ar ... .Ek .Bk -words .Op Fl o Ar options -.Ar ...\& +.Ar ... .Ek .Bk -words .Op Fl U Ar user -.Ar ...\& +.Ar ... .Ek .Bk -words .Op Fl G Ar group -.Ar ...\& +.Ar ... .Ek .Bk -words .Op Fl B Ar bytes @@ -140,28 +142,28 @@ .Op Ar ,to_date .Op Ar /[c][m] .Oc -.Ar ...\& +.Ar ... .Ek -.Op Ar -.Nm +.Op Ar file ... +.Nm pax .Fl r .Fl w -.Op Fl diklntuvDHLPXYZ +.Op Fl 0diklntuvDHLPXYZ .Bk -words .Op Fl p Ar string -.Ar ...\& +.Ar ... .Ek .Bk -words .Op Fl s Ar replstr -.Ar ...\& +.Ar ... .Ek .Bk -words .Op Fl U Ar user -.Ar ...\& +.Ar ... .Ek .Bk -words .Op Fl G Ar group -.Ar ...\& +.Ar ... .Ek .Bk -words .Oo @@ -170,17 +172,17 @@ .Op Ar ,to_date .Op Ar /[c][m] .Oc -.Ar ...\& +.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, +.Nm pax +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. +.Nm pax +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. @@ -190,7 +192,7 @@ The presence of the and the .Fl w options specifies which of the following functional modes -.Nm +.Nm pax will operate under: .Em list , read , write , and @@ -198,18 +200,18 @@ and .Bl -tag -width 6n .It .Em List . -Write to -.Dv standard output +.Nm pax +will write to standard output a table of contents of the members of the archive file read from -.Dv standard input , -whose pathnames match the specified +standard input, whose pathnames match the specified .Ar patterns . 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 -.Dv standard input , +.Nm pax +extracts the members of the archive file read from the standard input, with pathnames matching the specified .Ar patterns . The archive format and blocking is automatically determined on input. @@ -220,32 +222,34 @@ The setting of ownership, access and modification times, and file mode of the extracted files are discussed in more detail under the .Fl p option. +.\" ========== .It Fl w .Em Write . -Write an archive containing the +.Nm pax +writes an archive containing the .Ar file -operands to -.Dv standard output +operands to standard output using the specified archive format. When no .Ar file operands are specified, a list of files to copy with one per line is read from -.Dv standard input . +standard input. When a .Ar file 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 pax +copies the .Ar file operands to the destination .Ar directory . When no .Ar file operands are specified, a list of files to copy with one per line is read from -the -.Dv standard input . +the standard input. When a .Ar file operand is also a directory the entire file @@ -276,12 +280,12 @@ While processing a damaged archive during a or .Em list operation, -.Nm +.Nm pax will attempt to recover from media defects and will search through the archive to locate and process the largest number of archive members possible (see the .Fl E option for more details on error handling). -.Sh OPERANDS +.Pp The .Ar directory operand specifies a destination directory pathname. @@ -289,7 +293,7 @@ If the .Ar directory operand does not exist, or it is not writable by the user, or it is not of type directory, -.Nm +.Nm pax will exit with a non-zero exit status. .Pp The @@ -308,11 +312,10 @@ be selected. When a .Ar pattern operand does not select at least one archive member, -.Nm +.Nm pax will write these .Ar pattern -operands in a diagnostic message to -.Dv standard error +operands in a diagnostic message to standard error and then exit with a non-zero exit status. .Pp The @@ -321,47 +324,32 @@ operand specifies the pathname of a file to be copied or archived. When a .Ar file operand does not select at least one archive member, -.Nm +.Nm pax will write these .Ar file -operand pathnames in a diagnostic message to -.Dv standard error +operand pathnames in a diagnostic message to standard error and then exit with a non-zero exit status. -.Sh OPTIONS -The following options are supported: -.Bl -tag -width 4n -.It Fl r -Read an archive file from -.Dv standard input -and extract the specified -.Ar files . -If any intermediate directories are needed in order to extract an archive -member, these directories will be created as if -.Xr mkdir 2 -was called with the bitwise inclusive -.Dv OR -of -.Dv S_IRWXU , S_IRWXG , -and -.Dv S_IRWXO -as the mode argument. -When the selected archive format supports the specification of linked -files and these files cannot be linked while the archive is being extracted, -.Nm -will write a diagnostic message to -.Dv standard error -and exit with a non-zero exit status at the completion of operation. -.It Fl w -Write files to the -.Dv standard output -in the specified archive format. -When no -.Ar file -operands are specified, -.Dv standard input -is read for a list of pathnames with one per line without any leading or -trailing -.Aq blanks . +.Pp +The options are as follows: +.Bl -tag -width Ds +.\" ========== +.It Fl 0 +Use the NUL +.Pq Ql \e0 +character as a pathname terminator, instead of newline +.Pq Ql \en . +This applies only to the pathnames read from standard input in +the write and copy modes, +and to the pathnames written to standard output in list mode. +This option is expected to be used in concert with the +.Fl print0 +function in +.Xr find 1 +or the +.Fl 0 +flag in +.Xr xargs 1 . +.\" ========== .It Fl a Append .Ar files @@ -371,7 +359,7 @@ If an archive format is not specified with a option, the format currently being used in the archive will be selected. Any attempt to append to an archive in a format different from the format already used in the archive will cause -.Nm +.Nm pax to exit immediately with a non-zero exit status. The blocking size used in the archive volume where writing starts @@ -385,6 +373,30 @@ archive or have other unpredictable results. Tape drives in particular are more likely to not support an append operation. An archive stored in a regular file system file or on a disk device will usually support an append operation. +.\" ========== +.It Fl B Ar bytes +Limit the number of bytes written to a single archive volume to +.Ar bytes . +The +.Ar bytes +limit can end with +.Sq Li m , +.Sq Li k , +or +.Sq Li b +to specify multiplication by 1048576 (1M), 1024 (1K) or 512, respectively. +A pair of +.Ar bytes +limits can be separated by +.Sq Li x +to indicate a product. +.Pp +.Em Warning : +Only use this option when writing an archive to a device which supports +an end of file read condition based on last (or largest) write offset +(such as a regular file or a tape drive). +The use of this option with a floppy or hard disk is not recommended. +.\" ========== .It Fl b Ar blocksize When .Em writing @@ -400,14 +412,14 @@ standard and will not be portable to all systems. A .Ar blocksize can end with -.Li k +.Sq Li k or -.Li b +.Sq Li b to specify multiplication by 1024 (1K) or 512, respectively. A pair of .Ar blocksizes can be separated by -.Li x +.Sq Li x to indicate a product. A specific archive device may impose additional restrictions on the size of blocking it will support. @@ -416,6 +428,7 @@ When blocking is not specified, the default is dependent on the specific archive format being used (see the .Fl x option). +.\" ========== .It Fl c Match all file or archive members .Em except @@ -424,28 +437,88 @@ those specified by the and .Ar file operands. +.\" ========== +.It Fl D +This option is the same as the +.Fl u +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 +.Ar directory . +.\" ========== .It Fl d 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. +.\" ========== +.It Fl E Ar limit +Limit the number of consecutive read faults while trying to read a flawed +archive to +.Ar limit . +With a positive +.Ar limit , +.Nm pax +will attempt to recover from an archive read error and will +continue processing starting with the next file stored in the archive. +A +.Ar limit +of 0 will cause +.Nm pax +to stop operation after the first read error is detected on an archive volume. +A +.Ar limit +of +.Li NONE +will cause +.Nm pax +to attempt to recover from read errors forever. +The default +.Ar limit +is a small positive number of retries. +.Pp +.Em Warning : +Using this option with +.Li NONE +should be used with extreme caution as +.Nm pax +may get stuck in an infinite loop on a very badly flawed archive. +.\" ========== .It Fl f Ar archive Specify .Ar archive as the pathname of the input or output archive, overriding the default -.Dv standard input -(for +standard input (for .Em list and .Em read ) -or -.Dv standard output +or standard output (for .Em write ) . A single archive may span multiple files and different archive devices. When required, -.Nm +.Nm pax will prompt for the pathname of the file or device of the next volume in the archive. +.\" ========== +.It Fl G Ar group +Select a file based on its +.Ar group +name, or when starting with a +.Cm # , +a numeric gid. +A +.Ql \e +can be used to escape the +.Cm # . +Multiple +.Fl G +options may be supplied and checking stops with the first match. +.\" ========== +.It Fl H +Follow only command-line symbolic links while performing a physical file +system traversal. +.\" ========== .It Fl i Interactively rename files or archive members. For each archive member matching a @@ -453,36 +526,41 @@ For each archive member matching a operand or each file matching a .Ar file operand, -.Nm +.Nm pax 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 +giving the name of the file, its file mode, and its modification time. +.Nm pax +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 +.Nm pax +will immediately exit with a non-zero exit status if +.Dv EOF is encountered when reading a response or if .Pa /dev/tty cannot be opened for reading and writing. +.\" ========== .It Fl k Do not overwrite existing files. +.\" ========== +.It Fl L +Follow all symbolic links to perform a logical file system traversal. +.\" ========== .It Fl l +(The lowercase letter +.Dq ell. ) Link files. -(The letter ell). In the .Em copy mode -.Pq Fl r w , +.Pq Fl r Fl w , hard links are made between the source and destination file hierarchies whenever possible. +.\" ========== .It Fl n Select the first archive member that matches each .Ar pattern @@ -493,6 +571,15 @@ When members of type directory are matched, the file hierarchy rooted at that directory is also matched (unless .Fl d is also specified). +.\" ========== +.It Fl O +Force the archive to be one volume. +If a volume ends prematurely, +.Nm pax +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 o Ar options Information to modify the algorithm for extracting or writing archive files which is specific to the archive format specified by @@ -500,7 +587,56 @@ which is specific to the archive format specified by In general, .Ar options take the form: -.Cm name=value +.Ar name Ns = Ns Ar value . +.Pp +If the "-x pax" option is used, +the ":=" form of keyword specification is supported. +Also, the following new keywords are implemented: +.Bl -bullet +.It +delete= +.It +exthdr.name= +.It +globexhdr.name= +.It +invalid= for actions +bypass, rename, utf-8 (recognized, but ignored), and write +.It +linkdata +.It +listopt= +for the 'F' conversion specifier +(not the 'D', 'T', 'M', or 'L' specifiers) +.It +times +.It +all keywords in pax Extended Header, +with the following restrictions: +.Bl -tag +.It charset +keyword recognized, but ignored +.It realtime.any +keyword not recognized +.It security.any +keyword not recognized +.El +.El +.Pp +In "copy mode", only the following new keywords are supported: +.Bl -bullet +.It +delete= +.It +invalid= +.It +path= (from pax Extended Header description) +.El +.\" ========== +.It Fl P +Do not follow symbolic links, perform a physical file system traversal. +This is the default mode. +.\" ========== .It Fl p Ar string Specify one or more file characteristic options (privileges). The @@ -515,7 +651,7 @@ Multiple characteristics can be concatenated within the same string and multiple .Fl p options can be specified. -The meaning of the specification characters are as follows: +The meanings of the specification characters are as follows: .Bl -tag -width 2n .It Cm a Do not preserve file access times. @@ -543,7 +679,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. @@ -564,7 +700,7 @@ nor the .Cm o specification character is specified, or the user ID and group ID are not preserved for any reason, -.Nm +.Nm pax will not set the .Dv S_ISUID .Em ( setuid ) @@ -573,9 +709,8 @@ and .Em ( setgid ) bits of the file mode. If the preservation of any of these items fails for any reason, -.Nm -will write a diagnostic message to -.Dv standard error . +.Nm pax +will write a diagnostic message to standard error. Failure to preserve these items will affect the final exit status, but will not cause the extracted file to be deleted. If the file characteristic letters in any of the string option-arguments are @@ -584,6 +719,25 @@ precedence. For example, if .Dl Fl p Ar eme is specified, file modification times are still preserved. +.It Fl r +Read an archive file from standard input +and extract the specified +.Ar files . +If any intermediate directories are needed in order to extract an archive +member, these directories will be created as if +.Xr mkdir 2 +was called with the bitwise inclusive +.Tn OR +of +.Dv S_IRWXU , S_IRWXG , +and +.Dv S_IRWXO +as the mode argument. +When the selected archive format supports the specification of linked +files and these files cannot be linked while the archive is being extracted, +.Nm pax +will write a diagnostic message to standard error +and exit with a non-zero exit status at the completion of operation. .It Fl s Ar replstr Modify the file or archive member names specified by the .Ar pattern @@ -594,21 +748,28 @@ operands according to the substitution expression using the syntax of the .Xr ed 1 utility regular expressions. -The format of these regular expressions are: +The format of these regular expressions is: .Dl /old/new/[gp] As in .Xr ed 1 , .Cm old is a basic regular expression and .Cm new -can contain an ampersand (&), \\n (where n is a digit) back-references, +can contain an ampersand +.Pq Ql & , +.Ql \en +(where +.Ar n +is a digit) back-references, or subexpression matching. The .Cm old -string may also contain -.Dv -characters. -Any non-null character can be used as a delimiter (/ is shown here). +string may also contain newline characters. +Any non-null character can be used as a delimiter +.Po +.Ql / +is shown here +.Pc . Multiple .Fl s expressions can be specified. @@ -616,7 +777,7 @@ The expressions are applied in the order they are specified on the command line, terminating with the first successful substitution. The optional trailing .Cm g -continues to apply the substitution expression to the pathname substring +continues to apply the substitution expression to the pathname substring, which starts with the first character following the end of the last successful substitution. The first unsuccessful substitution stops the operation of the @@ -625,16 +786,127 @@ option. The optional trailing .Cm p will cause the final result of a successful substitution to be written to -.Dv standard error -in the following format: +standard error in the following format: .Dl >> File or archive member names that substitute to the empty string are not selected and will be skipped. +.It Fl T Ar [from_date][,to_date][/[c][m]] +Allow files to be selected based on a file modification or inode change +time falling within a specified time range of +.Ar from_date +to +.Ar to_date +(the dates are inclusive). +If only a +.Ar from_date +is supplied, all files with a modification or inode change time +equal to or younger are selected. +If only a +.Ar to_date +is supplied, all files with a modification or inode change time +equal to or older will be selected. +When the +.Ar from_date +is equal to the +.Ar to_date , +only files with a modification or inode change time of exactly that +time will be selected. +.Pp +When +.Nm pax +is in the +.Em write +or +.Em copy +mode, the optional trailing field +.Ar [c][m] +can be used to determine which file time (inode change, file modification or +both) are used in the comparison. +If neither is specified, the default is to use file modification time only. +The +.Ar m +specifies the comparison of file modification time (the time when +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). +When +.Ar c +and +.Ar m +are both specified, then the modification and inode change times are +both compared. +The inode change time comparison is useful in selecting files whose +attributes were recently changed or selecting files which were recently +created and had their modification time reset to an older time (as what +happens when a file is extracted from an archive and the modification time +is preserved). +Time comparisons using both file times is useful when +.Nm pax +is used to create a time based incremental archive (only files that were +changed during a specified time range will be archived). +.Pp +A time range is made up of six different fields and each field must contain two +digits. +The format is: +.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 +.Cm mm +is the month (from 01 to 12), +.Cm dd +is the day of the month (from 01 to 31), +.Cm HH +is the hour of the day (from 00 to 23), +.Cm MM +is the minute (from 00 to 59), +and +.Cm SS +is the seconds (from 00 to 59). +The minute field +.Cm MM +is required, while the other fields are optional and must be added in the +following order: +.br +.Cm \& HH , dd , mm , +.Cm yy , cc . +.br +The +.Cm SS +field may be added independently of the other fields. +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 +of 12:34 PM today or later. +Multiple +.Fl T +time range can be supplied and checking stops with the first match. +.\" ========== .It Fl t Reset the access times of any file or directory read or accessed by -.Nm +.Nm pax to be the same as they were before being read or accessed by -.Nm . +.Nm pax . +.\" ========== +.It Fl U Ar user +Select a file based on its +.Ar user +name, or when starting with a +.Cm # , +a numeric UID. +A +.Ql \e +can be used to escape the +.Cm # . +Multiple +.Fl U +options may be supplied and checking stops with the first match. +.\" ========== .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. @@ -651,6 +923,7 @@ During the file in the destination hierarchy is replaced by the file in the source hierarchy or by a link to the file in the source hierarchy if the file in the source hierarchy is newer. +.\" ========== .It Fl v During a .Em list @@ -670,62 +943,88 @@ utility when used with the .Fl l option. Otherwise for all the other operational modes -.Em ( read , write , -and -.Em copy ) , -pathnames are written and flushed to -.Dv standard error -without a trailing -.Dv +.Po Em read , write , Li and Em copy +.Pc , +pathnames are written and flushed to standard error +without a trailing newline as soon as processing begins on that file or archive member. -The trailing -.Dv , -is not buffered, and is written only after the file has been read or written. +The trailing newline +is not buffered and is written only after the file has been read or written. +.\" ========== +.It Fl w +Write files to the standard output +in the specified archive format. +When no +.Ar file +operands are specified, standard input +is read for a list of pathnames with one per line without any leading or +trailing +.Aq blanks . +.\" ========== +.It Fl X +When traversing the file hierarchy specified by a pathname, +do not descend into directories that have a different device ID. +See the +.Li st_dev +field as described in +.Xr stat 2 +for more information about device IDs. +.\" ========== .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: +.Nm pax +currently supports the following formats: .Bl -tag -width "sv4cpio" -.It Ar cpio -The extended cpio interchange format specified in the -.St -p1003.2 -standard. -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 bcpio The old binary cpio format. The default blocksize for this format is 5120 bytes. This format is not very portable and should not be used when other formats are available. 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 +by this format), which may be truncated by this format, is detected by +.Nm pax +and is repaired. +.\" ========== +.It Ar cpio +The extended cpio interchange format specified in the +.St -p1003.2 +standard. +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 pax and is repaired. +.\" ========== +.It Ar pax +"pax interchange format", described in the +EXTENDED DESCRIPTION of the pax interchange format +in The Open Group's SUSv3 specification. +Includes support for pax Header Block, +pax Extended Header, +pax Extended Header Keyword Precedence, and +pax Extended Header File Times. +.\" ========== .It Ar sv4cpio The System V release 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 +by this format), which may be truncated by this format, is detected by +.Nm pax and is repaired. +.\" ========== .It Ar sv4crc The System V release 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 -.Nm +by this format), which may be truncated by this format, is detected by +.Nm pax and is repaired. +.\" ========== .It Ar tar -The old -.Bx -tar format as found in -.Bx 4.3 . +The old BSD tar format as found in BSD4.3. The default blocksize for this format is 10240 bytes. Pathnames stored by this format must be 100 characters or less in length. Only @@ -740,232 +1039,46 @@ For backwards compatibility with even older tar formats, a option can be used when writing an archive to omit the storage of directories. This option takes the form: .Dl Fl o Cm write_opt=nodir +.\" ========== .It Ar ustar The extended tar interchange format specified in the .St -p1003.2 standard. The default blocksize for this format is 10240 bytes. -Pathnames stored by this format must be 250 characters or less in length. +Filenames stored by this format must be 100 characters or less in length; +the total pathname must be 255 characters or less. .El .Pp -The -.Nm -utility will detect and report any file that it is unable to store or extract +.Nm pax +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 z -Use -.Xr gzip 1 -to compress (decompress) the archive while writing (reading). -Incompatible with -.Fl a . -.It Fl B Ar bytes -Limit the number of bytes written to a single archive volume to -.Ar bytes . -The -.Ar bytes -limit can end with -.Li m , -.Li k , -or -.Li b -to specify multiplication by 1048576 (1M), 1024 (1K) or 512, respectively. -A pair of -.Ar bytes -limits can be separated by -.Li x -to indicate a product. -.Pp -.Em Warning : -Only use this option when writing an archive to a device which supports -an end of file read condition based on last (or largest) write offset -(such as a regular file or a tape drive). -The use of this option with a floppy or hard disk is not recommended. -.It Fl D -This option is the same as the -.Fl u -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 -.Ar directory . -.It Fl E Ar limit -Limit the number of consecutive read faults while trying to read a flawed -archives to -.Ar limit . -With a positive -.Ar limit , -.Nm -will attempt to recover from an archive read error and will -continue processing starting with the next file stored in the archive. -A -.Ar limit -of 0 will cause -.Nm -to stop operation after the first read error is detected on an archive volume. -A -.Ar limit -of -.Li NONE -will cause -.Nm -to attempt to recover from read errors forever. -The default -.Ar limit -is a small positive number of retries. -.Pp -.Em Warning : -Using this option with -.Li NONE -should be used with extreme caution as -.Nm -may get stuck in an infinite loop on a very badly flawed archive. -.It Fl G Ar group -Select a file based on its -.Ar group -name, or when starting with a -.Cm # , -a numeric gid. -A '\\' can be used to escape the -.Cm # . -Multiple -.Fl G -options may be supplied and checking stops with the first match. -.It Fl H -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 P -Do not follow symbolic links, perform a physical file system traversal. -This is the default mode. -.It Fl T Ar [from_date][,to_date][/[c][m]] -Allow files to be selected based on a file modification or inode change -time falling within a specified time range of -.Ar from_date -to -.Ar to_date -(the dates are inclusive). -If only a -.Ar from_date -is supplied, all files with a modification or inode change time -equal to or younger are selected. -If only a -.Ar to_date -is supplied, all files with a modification or inode change time -equal to or older will be selected. -When the -.Ar from_date -is equal to the -.Ar to_date , -only files with a modification or inode change time of exactly that -time will be selected. -.Pp -When -.Nm -is in the -.Em write -or -.Em copy -mode, the optional trailing field -.Ar [c][m] -can be used to determine which file time (inode change, file modification or -both) are used in the comparison. -If neither is specified, the default is to use file modification time only. -The -.Ar m -specifies the comparison of file modification time (the time when -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). -When -.Ar c -and -.Ar m -are both specified, then the modification and inode change times are -both compared. -The inode change time comparison is useful in selecting files whose -attributes were recently changed or selecting files which were recently -created and had their modification time reset to an older time (as what -happens when a file is extracted from an archive and the modification time -is preserved). -Time comparisons using both file times is useful when -.Nm -is used to create a time based incremental archive (only files that were -changed during a specified time range will be archived). -.Pp -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] -Where -.Cm yy -is the last two digits of the year, -the first -.Cm mm -is the month (from 01 to 12), -.Cm dd -is the day of the month (from 01 to 31), -.Cm hh -is the hour of the day (from 00 to 23), -the second -.Cm mm -is the minute (from 00 to 59), -and -.Cm ss -is the seconds (from 00 to 59). -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 . -The -.Cm ss -field may be added independently of the other fields. -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 -of 12:34 PM today or later. -Multiple -.Fl T -time range can be supplied and checking stops with the first match. -.It Fl U Ar user -Select a file based on its -.Ar user -name, or when starting with a -.Cm # , -a numeric uid. -A '\\' can be used to escape the -.Cm # . -Multiple -.Fl U -options may be supplied and checking stops with the first match. -.It Fl X -When traversing the file hierarchy specified by a pathname, -do not descend into directories that have a different device ID. -See the -.Li st_dev -field as described in -.Xr stat 2 -for more information about device ID's. +file pathname length, file size, link pathname length, and the type of the +file. +.\" ========== .It Fl Y This option is the same as the .Fl D option, except that the inode change time is checked using the pathname created after all the file name modifications have completed. +.\" ========== .It Fl Z 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 z +Use +.Xr gzip 1 +to compress (decompress) the archive while writing (reading). +Incompatible with +.Fl a . .El .Pp The options that operate on the names of files or archive members -.Fl ( c , +.Po Fl c , .Fl i , .Fl n , .Fl s , @@ -977,7 +1090,8 @@ The options that operate on the names of files or archive members .Fl U , .Fl Y , and -.Fl Z ) +.Fl Z +.Pc interact as follows. .Pp When extracting files during a @@ -1003,7 +1117,7 @@ Then the and .Fl Z options will be applied based on the final pathname. -Finally the +Finally, the .Fl v option will write the names resulting from these modifications. .Pp @@ -1036,7 +1150,7 @@ operation the and the .Fl Z options will be applied based on the final pathname. -Finally the +Finally, the .Fl v option will write the names resulting from these modifications. .Pp @@ -1048,102 +1162,65 @@ options are specified along with the .Fl n option, a file is not considered selected unless it is newer than the file to which it is compared. +.Sh ENVIRONMENT +.Bl -tag -width Fl +.It Ev TMPDIR +Path in which to store temporary files. +.El .Sh EXAMPLES -The command: -.Dl "pax -w -f /dev/sa0 ." -copies the contents of the current directory to the device -.Pa /dev/sa0 . +.Li $ pax -w -f /dev/rst0 \&. .Pp -The command: -.Dl pax -v -f filename -gives the verbose table of contents for an archive stored in +Copies the contents of the current directory to the device +.Pa /dev/rst0 . +.Pp +.Li $ pax -v -f filename +.Pp +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 +.Li $ mkdir newdir ; +.Li cd olddir ; +.Li pax -rw \&. newdir +.Pp +This sequence of commands will copy the entire +.Pa olddir directory hierarchy to -.Pa /tmp/to . +.Pa newdir . +.Pp +.Li $ pax -r -s ',^//*usr//*,,' -f a.pax .Pp -The command: -.Dl pax -r -s ',^//*usr//*,,' -f a.pax -reads the archive +Reads the archive .Pa a.pax , -with all files rooted in ``/usr'' into the archive extracted relative to the -current directory. +with all files rooted in +.Pa /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 +.Li $ pax -rw -i \&. dest_dir +.Pp +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 +.Li "$ pax -r -pe -U root -G bin -f a.pax" +.Pp +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. +and preserve all file permissions. +.Pp +.Li "$ pax -r -w -v -Y -Z home /backup" .Pp -The command: -.Dl pax -r -w -v -Y -Z home /backup -will update (and list) only those files in the destination directory +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 STANDARDS -The -.Nm -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 P , -.Fl T , -.Fl U , -.Fl Y , -.Fl Z , -the archive formats -.Ar bcpio , -.Ar sv4cpio , -.Ar sv4crc , -.Ar tar , -and the flawed archive handling during -.Ar list -and -.Ar read -operations are extensions to the -.Tn POSIX -standard. -.Sh SEE ALSO -.Xr cpio 1 , -.Xr tar 1 -.Sh HISTORY -The -.Nm -utility appeared in -.Bx 4.4 . -.Sh AUTHORS -.An Keith Muller -at the University of California, San Diego .Sh DIAGNOSTICS -The -.Nm -utility will exit with one of the following values: +.Nm pax +will exit with one of the following values: .Bl -tag -width 2n .It 0 All files were processed successfully. @@ -1152,41 +1229,79 @@ An error occurred. .El .Pp Whenever -.Nm +.Nm pax cannot create a file or a link when reading an archive or cannot find a file when writing an archive, or cannot preserve the user ID, group ID, or file mode when the .Fl p -option is specified, a diagnostic message is written to -.Dv standard error +option is specified, a diagnostic message is written to standard error and a non-zero exit status will be returned, but processing will continue. -In the case where pax cannot create a link to a file, -.Nm +In the case where +.Nm pax +cannot create a link to a file, +.Nm pax will not create a second copy of the file. .Pp If the extraction of a file from an archive is prematurely terminated by a signal or error, -.Nm +.Nm pax may have only partially extracted a file the user wanted. Additionally, the file modes of extracted files and directories may have incorrect file bits, and the modification and access times may be wrong. .Pp If the creation of an archive is prematurely terminated by a signal or error, -.Nm -may have only partially created the archive which may violate the specific +.Nm pax +may have only partially created the archive, which may violate the specific archive format specification. .Pp -If while doing a +If, while doing a .Em copy , -.Nm +.Nm pax detects a file is about to overwrite itself, the file is not copied, -a diagnostic message is written to -.Dv standard error +a diagnostic message is written to standard error and when -.Nm +.Nm pax completes it will exit with a non-zero exit status. -.Sh BUGS +.Sh SEE ALSO +.Xr cpio 1 , +.Xr tar 1 +.Pp +"Archiving with Pax", Dru Lavigne, ONLamp.com BSD DevCenter, +http://www.onlamp.com/pub/a/bsd/2002/08/22/FreeBSD_Basics.html +.Pp +pax(1) manual page, +http://heirloom.sourceforge.net/man/pax.1.html +.Sh STANDARDS The -.Nm -utility does not recognize multibyte characters. +.Nm pax +utility is a superset of the +.St -p1003.2 +standard. +The options +.Fl B , +.Fl D , +.Fl E , +.Fl G , +.Fl H , +.Fl L , +.Fl O , +.Fl P , +.Fl T , +.Fl U , +.Fl Y , +.Fl Z , +the archive formats +.Ar bcpio , +.Ar sv4cpio , +.Ar sv4crc , +.Ar tar , +and the flawed archive handling during +.Ar list +and +.Ar read +operations are extensions to the +.Tn POSIX +standard. +.Sh AUTHORS +Keith Muller at the University of California, San Diego. diff --git a/pax/pax.c b/pax/pax.c index 574ed5b..e312833 100644 --- a/pax/pax.c +++ b/pax/pax.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pax.c,v 1.11 1997/09/01 18:29:58 deraadt Exp $ */ +/* $OpenBSD: pax.c,v 1.27 2004/04/16 22:50:23 deraadt Exp $ */ /* $NetBSD: pax.c,v 1.5 1996/03/26 23:54:20 mrg Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -39,16 +35,16 @@ */ #ifndef lint -static char copyright[] __attribute__((__unused__)) = +static const char copyright[] __attribute__((__unused__)) = "@(#) Copyright (c) 1992, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 -static char sccsid[] = "@(#)pax.c 8.2 (Berkeley) 4/18/94"; +static const char sccsid[] = "@(#)pax.c 8.2 (Berkeley) 4/18/94"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: pax.c,v 1.11 1997/09/01 18:29:58 deraadt Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: pax.c,v 1.27 2004/04/16 22:50:23 deraadt Exp $"; #endif #endif /* not lint */ @@ -61,11 +57,14 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: pax.c,v 1.11 1997/0 #include #include #include +#include #include +#include #include +#include #include "pax.h" #include "extern.h" -static int gen_init __P((void)); +static int gen_init(void); /* * PAX main routines, general globals and some simple start up routines @@ -86,13 +85,13 @@ 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 zflag; /* use gzip */ int Dflag; /* same as uflag except inode change time */ int Hflag; /* follow command line symlinks (write only) */ int Lflag; /* follow symlinks when writing */ 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 */ +int Yflag; /* same as Dflag except after name mode */ +int Zflag; /* same as uflag except after name mode */ +int zeroflag; /* use \0 as pathname terminator */ int vfpart; /* is partial verbose output in progress */ int patime = 1; /* preserve file access time */ int pmtime = 1; /* preserve file modification times */ @@ -106,11 +105,14 @@ char *dirptr; /* destination dir in a copy */ char *ltmfrmt; /* -v locale time format (if any) */ 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) */ /* * 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): * @@ -126,7 +128,7 @@ sigset_t s_mask; /* signal mask for cleanup critical sect */ * * 1 READ ENHANCEMENTS * 1.1 Operations which read archives will continue to operate even when - * processing archives which may be damaged, truncated, or fail to meet + * processing archives which may be damaged, truncated, or fail to meet * format specs in several different ways. Damaged sections of archives * are detected and avoided if possible. Attempts will be made to resync * archive read operations even with badly damaged media. @@ -141,7 +143,7 @@ sigset_t s_mask; /* signal mask for cleanup critical sect */ * 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 - * archive devices + * archive devices * 1.7 Rigidly restores all file attributes exactly as they are stored on the * archive. * 1.8 Modification change time ranges can be specified via multiple -T @@ -151,14 +153,14 @@ sigset_t s_mask; /* signal mask for cleanup critical sect */ * -U options. * 1.10 Files can be selected based on group (group name or gid) via one o * more -G options. - * 1.11 File modification time can be checked against exisiting file after + * 1.11 File modification time can be checked against existing file after * name modification (-Z) * * 2 WRITE ENHANCEMENTS * 2.1 Write operation will stop instead of allowing a user to create a flawed * flawed archive (due to any problem). - * 2.2 Archives writtens by pax are forced to strictly conform to both the - * archive and pax the spceific format specifications. + * 2.2 Archives written by pax are forced to strictly conform to both the + * archive and pax the specific format specifications. * 2.3 Blocking size and format is rigidly enforced on writes. * 2.4 Formats which may exhibit header overflow problems (they have fields * too small for large file systems, such as inode number storage), use @@ -167,11 +169,11 @@ sigset_t s_mask; /* signal mask for cleanup critical sect */ * these fields. This removes any restrictions on using these archive * formats on large file systems. * 2.5 Multiple archive volumes can be written and may span over different - * archive devices + * archive devices * 2.6 A archive volume record limit allows the user to specify the number * of bytes stored on an archive volume. When reached the user is * prompted for the next archive volume. This is specified with the - * non-standard -B flag. THe limit is rounded up to the next blocksize. + * non-standard -B flag. The limit is rounded up to the next blocksize. * 2.7 All archive padding during write use zero filled sections. This makes * it much easier to pull data out of flawed archive during read * operations. @@ -206,15 +208,15 @@ sigset_t s_mask; /* signal mask for cleanup critical sect */ * 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 exisiting 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 exisiting 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 exisiting file after + * 3.11 File modification time can be checked against existing file after * name modification (-Z) * * 4 GENERAL ENHANCEMENTS - * 4.1 Internal structure is designed to isolate format dependent and + * 4.1 Internal structure is designed to isolate format dependent and * independent functions. Formats are selected via a format driver table. * This encourages the addition of new archive formats by only having to * write those routines which id, read and write the archive header. @@ -227,16 +229,16 @@ sigset_t s_mask; /* signal mask for cleanup critical sect */ * Return: 0 if ok, 1 otherwise */ -#ifdef __STDC__ +extern void pax_usage(); + int main(int argc, char **argv) -#else -int -main(argc, argv) - int argc; - char **argv; -#endif { + char *tmpdir; + size_t tdlen; + + if (argc < 1) + pax_usage(); /* * Keep a reference to cwd, so we can always come back home. */ @@ -247,6 +249,24 @@ main(argc, argv) } /* + * Where should we put temporary files? + */ + if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') + tmpdir = _PATH_TMP; + tdlen = strlen(tmpdir); + while (tdlen > 0 && tmpdir[tdlen - 1] == '/') + tdlen--; + tempfile = malloc(tdlen + 1 + sizeof(_TFILE_BASE)); + if (tempfile == NULL) { + paxwarn(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); @@ -254,9 +274,9 @@ main(argc, argv) return(exit_val); /* - * select a primary operation mode + * select a primary operation mode */ - switch(act) { + switch (act) { case EXTRACT: extract(); break; @@ -264,6 +284,8 @@ main(argc, argv) archive(); break; case APPND: + if (gzip_program != NULL) + errx(1, "can not gzip while appending"); append(); break; case COPY: @@ -286,15 +308,11 @@ main(argc, argv) * never.... */ -#ifdef __STDC__ void sig_cleanup(int which_sig) -#else -void -sig_cleanup(which_sig) - int which_sig; -#endif { + /* XXX signal races */ + /* * restore modes and times for any dirs we may have created * or any dirs we may have read. Set vflag and vfpart so the user @@ -319,13 +337,8 @@ sig_cleanup(which_sig) * when dealing with a medium to large sized archives. */ -#ifdef __STDC__ static int gen_init(void) -#else -static int -gen_init() -#endif { struct rlimit reslimit; struct sigaction n_hand; @@ -368,14 +381,14 @@ gen_init() /* * Handle posix locale * - * set user defines time printing format for -v option + * 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) || @@ -385,6 +398,7 @@ gen_init() paxwarn(1, "Unable to set up signal mask"); return(-1); } + memset(&n_hand, 0, sizeof n_hand); n_hand.sa_mask = s_mask; n_hand.sa_flags = 0; n_hand.sa_handler = sig_cleanup; diff --git a/pax/pax.h b/pax/pax.h index bdf00a4..b951b55 100644 --- a/pax/pax.h +++ b/pax/pax.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pax.h,v 1.9 1997/07/23 19:15:58 kstailey Exp $ */ +/* $OpenBSD: pax.h,v 1.16 2003/10/20 06:22:27 jmc Exp $ */ /* $NetBSD: pax.h,v 1.3 1995/03/21 09:07:41 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -52,7 +48,7 @@ /* 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 /* maximium path length for pax. MUST be */ +#define PAXPATHLEN 3072 /* maximum path length for pax. MUST be */ /* longer than the system MAXPATHLEN */ /* @@ -66,7 +62,7 @@ #define DEFOP LIST /* if no flags default is to LIST */ /* - * Device type of the current archive volume + * Device type of the current archive volume */ #define ISREG 0 /* regular file */ #define ISCHR 1 /* character device */ @@ -75,12 +71,69 @@ #define ISPIPE 4 /* pipe/socket */ /* + * 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 */ + 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 */ + 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 * * The format specific routine table allows new archive formats to be quickly * added. Overall pax operation is independent of the actual format used to - * form the archive. Only those routines which deal directly with the archive - * are tailored to the oddities of the specifc format. All other routines are + * form the archive. Only those routines which deal directly with the archive + * are tailored to the oddities of the specific format. All other routines are * independent of the archive format. Data flow in and out of the format * dependent routines pass pointers to ARCHD structure (described below). */ @@ -106,17 +159,17 @@ typedef struct { int hlk; /* does archive store hard links info? if */ /* not, we do not bother to look for them */ /* during archive write operations */ - int blkalgn; /* writes must be aligned to blkalgn boundry */ + int blkalgn; /* writes must be aligned to blkalgn boundary */ int inhead; /* is the trailer encoded in a valid header? */ /* if not, trailers are assumed to be found */ /* in invalid headers (i.e like tar) */ - int (*id)(); /* checks if a buffer is a valid header */ - /* returns 1 if it is, o.w. returns a 0 */ - int (*st_rd)(); /* initialize routine for read. so format */ + int (*id)(char *, /* checks if a buffer is a valid header */ + int); /* returns 1 if it is, o.w. returns a 0 */ + int (*st_rd)(void); /* initialize routine for read. so format */ /* can set up tables etc before it starts */ /* reading an archive */ - int (*rd)(); /* read header routine. passed a pointer to */ - /* ARCHD. It must extract the info from the */ + int (*rd)(ARCHD *, /* read header routine. passed a pointer to */ + 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) */ @@ -127,12 +180,12 @@ typedef struct { /* padding and the number of bytes of data */ /* which follow the header. This info is */ /* used skip to the next file header */ - off_t (*end_rd)(); /* read cleanup. Allows format to clean up */ + 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 */ /* to move back to rewrite the trailer) */ - int (*st_wr)(); /* initialize routine for write operations */ - int (*wr)(); /* write archive header. Passed an ARCHD */ + int (*st_wr)(void); /* initialize routine for write operations */ + int (*wr)(ARCHD *); /* write archive header. Passed an ARCHD */ /* filled with the specs on the next file to */ /* archived. Returns a 1 if no file data is */ /* is to be stored; 0 if file data is to be */ @@ -142,79 +195,26 @@ typedef struct { /* the proper padding can be added after */ /* file data. This routine must NEVER write */ /* a flawed archive header. */ - int (*end_wr)(); /* end write. write the trailer and do any */ + int (*end_wr)(void); /* end write. write the trailer and do any */ /* other format specific functions needed */ - /* at the ecnd of a archive write */ - int (*trail)(); /* returns 0 if a valid trailer, -1 if not */ - /* For formats which encode the trailer */ - /* outside of a valid header, a return value */ + /* at the end of an archive write */ + int (*trail)(ARCHD *, /* returns 0 if a valid trailer, -1 if not */ + char *, int, /* For formats which encode the trailer */ + int *); /* 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) */ /* CAUTION: parameters to this function are */ /* different for trailers inside or outside */ /* of headers. See get_head() for details */ - int (*rd_data)(); /* read/process file data from the archive */ - int (*wr_data)(); /* write/process file data to the archive */ - int (*options)(); /* process format specific options (-o) */ + int (*rd_data)(ARCHD *, /* read/process file data from the archive */ + int, off_t *); + int (*wr_data)(ARCHD *, /* write/process file data to the archive */ + int, off_t *); + int (*options)(void); /* process format specific options (-o) */ } FSUB; /* - * 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 */ - 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 */ - 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 */ -} ARCHD; - -/* * Format Specific Options List * * Used to pass format options to the format options handler @@ -223,13 +223,18 @@ typedef struct oplist { char *name; /* option variable name e.g. name= */ char *value; /* value for option variable */ struct oplist *fow; /* next option */ + int separator; /* 2 means := separator; 1 means = separator + 0 means no separator */ } OPLIST; +#define SEP_COLONEQ 2 +#define SEP_EQ 1 +#define SEP_NONE 0 /* * General Macros */ #ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MIN(a,b) (((a)<(b))?(a):(b)) #endif #define MAJOR(x) major(x) #define MINOR(x) minor(x) @@ -238,6 +243,7 @@ typedef struct oplist { /* * General Defines */ -#define HEX 16 -#define OCT 8 -#define _PAX_ 1 +#define HEX 16 +#define OCT 8 +#define _PAX_ 1 +#define _TFILE_BASE "paxXXXXXXXXXX" diff --git a/pax/pax_format.c b/pax/pax_format.c new file mode 100644 index 0000000..e98d8a7 --- /dev/null +++ b/pax/pax_format.c @@ -0,0 +1,2024 @@ +/* $OpenBSD: tar.c,v 1.34 2004/10/23 19:34:14 otto Exp $ */ +/* $NetBSD: tar.c,v 1.5 1995/03/21 09:07:49 cgd Exp $ */ + +/*- + * Copyright (c) 1992 Keith Muller. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static const char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94"; +#else +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tar.c,v 1.34 2004/10/23 19:34:14 otto Exp $"; +#endif +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pax.h" +#include "extern.h" +#include "tar.h" +#include +#include +#include "pat_rep.h" +#include + +/* + * This file implements the -x pax format support; it is incomplete. + * Known missing features include: + * many -o options for "copy" mode are not implemented (only path=) + * many format specifiers for -o listopt are not implemented + * -o listopt option should work for all archive formats, not just -x pax + * This file was originally derived from the file tar.c. You should + * 'diff' it to that file to see how much of the -x pax format has been implemented. + */ + +char pax_eh_datablk[4*1024]; +int pax_read_or_list_mode = 0; +int want_a_m_time_headers = 0; +int want_linkdata = 0; + +int pax_invalid_action = 0; +char * pax_invalid_action_write_path = NULL; +char * pax_invalid_action_write_cwd = NULL; + +char + *path_g, *path_x, *path_g_current, *path_x_current, + *uname_g, *uname_x, *uname_g_current, *uname_x_current, + *gname_g, *gname_x, *gname_g_current, *gname_x_current, + *comment_g, *comment_x, *comment_g_current, *comment_x_current, + *charset_g, *charset_x, *charset_g_current, *charset_x_current, + *atime_g, *atime_x, *atime_g_current, *atime_x_current, + *gid_g, *gid_x, *gid_g_current, *gid_x_current, + *linkpath_g, *linkpath_x, *linkpath_g_current, *linkpath_x_current, + *mtime_g, *mtime_x, *mtime_g_current, *mtime_x_current, + *size_g, *size_x, *size_g_current, *size_x_current, + *uid_g, *uid_x, *uid_g_current, *uid_x_current; + +char *header_name_g_requested = NULL, + *header_name_x_requested = NULL; + +char *header_name_g = "/tmp/GlobalHead.%p.%n", + *header_name_x = "%d/PaxHeaders.%p/%f"; + +int nglobal_headers = 0; +char *pax_list_opt_format; + +#define O_OPTION_ACTION_NOTIMPL 0 +#define O_OPTION_ACTION_INVALID 1 +#define O_OPTION_ACTION_DELETE 2 +#define O_OPTION_ACTION_STORE_HEADER 3 +#define O_OPTION_ACTION_TIMES 4 +#define O_OPTION_ACTION_HEADER_NAME 5 +#define O_OPTION_ACTION_LISTOPT 6 +#define O_OPTION_ACTION_LINKDATA 7 + +#define O_OPTION_ACTION_IGNORE 8 +#define O_OPTION_ACTION_ERROR 9 +#define O_OPTION_ACTION_STORE_HEADER2 10 + +#define ATTRSRC_FROM_NOWHERE 0 +#define ATTRSRC_FROM_X_O_OPTION 1 +#define ATTRSRC_FROM_G_O_OPTION 2 +#define ATTRSRC_FROM_X_HEADER 3 +#define ATTRSRC_FROM_G_HEADER 4 + +#define KW_PATH_CASE 0 +#define KW_SKIP_CASE -1 + +typedef struct { + char * name; + int len; + int active; /* 1 means active, 0 means deleted via -o delete= */ + int cmdline_action; + int header_action; + /* next 2 entries only used by store_header actions */ + char ** g_value; /* -o keyword= value */ + char ** x_value; /* -o keyword:= value */ + char ** g_value_current; /* keyword= value found in Global extended header */ + char ** x_value_current; /* keyword= value found in extended header */ + int header_inx; /* starting index of header field this keyword represents */ + int header_len; /* length of header field this keyword represents */ + /* If negative, special cases line path= */ +} O_OPTION_TYPE; + +O_OPTION_TYPE o_option_table[] = { + { "atime", 5, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER, + &atime_g, &atime_x, &atime_g_current, &atime_x_current, 0, KW_SKIP_CASE }, + { "charset", 7, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_IGNORE, + &charset_g, &charset_x, &charset_g_current, &charset_x_current, 0, KW_SKIP_CASE }, + { "comment", 7, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_IGNORE, + &comment_g, &comment_x, &comment_g_current, &comment_x_current, 0, KW_SKIP_CASE }, + { "gid", 3, 1, O_OPTION_ACTION_STORE_HEADER2, O_OPTION_ACTION_STORE_HEADER2, + &gid_g, &gid_x, &gid_g_current, &gid_x_current , 116, 8 }, + { "gname", 5, 1, O_OPTION_ACTION_STORE_HEADER2, O_OPTION_ACTION_STORE_HEADER2, + &gname_g, &gname_x, &gname_g_current, &gname_x_current, 297, 32 }, + { "linkpath", 8, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER, + &linkpath_g, &linkpath_x, &linkpath_g_current, &linkpath_x_current, 0, KW_SKIP_CASE }, + { "mtime", 5, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER, + &mtime_g, &mtime_x, &mtime_g_current, &mtime_x_current, 136, KW_SKIP_CASE }, + { "path", 4, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER, + &path_g, &path_x, &path_g_current, &path_x_current, 0, KW_PATH_CASE }, + { "size", 4, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER, + &size_g, &size_x, &size_g_current, &size_x_current, 124, KW_SKIP_CASE }, + { "uid", 3, 1, O_OPTION_ACTION_STORE_HEADER2, O_OPTION_ACTION_STORE_HEADER2, + &uid_g, &uid_x, &uid_g_current, &uid_x_current, 108, 8 }, + { "uname", 5, 1, O_OPTION_ACTION_STORE_HEADER2, O_OPTION_ACTION_STORE_HEADER2, + &uname_g, &uname_x, &uname_g_current, &uname_x_current, 265, 32 }, + + { "exthdr.name", 11, 1, O_OPTION_ACTION_HEADER_NAME, O_OPTION_ACTION_ERROR, + &header_name_x, &header_name_x_requested, NULL, NULL, 0, KW_SKIP_CASE }, + { "globexthdr.name", 15, 1, O_OPTION_ACTION_HEADER_NAME, O_OPTION_ACTION_ERROR, + &header_name_g, &header_name_g_requested, NULL, NULL, 0, KW_SKIP_CASE }, + + { "delete", 6, 1, O_OPTION_ACTION_DELETE, O_OPTION_ACTION_ERROR, + NULL, NULL, NULL, NULL, 0, KW_SKIP_CASE }, + { "invalid", 7, 1, O_OPTION_ACTION_INVALID, O_OPTION_ACTION_ERROR, + NULL, NULL, NULL, NULL, 0, KW_SKIP_CASE }, + { "linkdata", 8, 1, O_OPTION_ACTION_LINKDATA, O_OPTION_ACTION_ERROR, + NULL, NULL, NULL, NULL, 0, KW_SKIP_CASE }, /* Test 241 */ + { "listopt", 7, 1, O_OPTION_ACTION_LISTOPT, O_OPTION_ACTION_ERROR, + &pax_list_opt_format, NULL, NULL, NULL, 0, KW_SKIP_CASE }, /* Test 242 */ + /* Note: listopt is supposed to apply for all formats, not just -x pax only */ + { "times", 5, 1, O_OPTION_ACTION_TIMES, O_OPTION_ACTION_ERROR, + NULL, NULL, NULL, NULL, 0, KW_SKIP_CASE }, +}; + +int ext_header_inx, + global_ext_header_inx; + +/* Make these tables big enough to handle lots of -o options, not just one per table entry */ +int ext_header_entry [4*sizeof(o_option_table)/sizeof(O_OPTION_TYPE)], + global_ext_header_entry[4*sizeof(o_option_table)/sizeof(O_OPTION_TYPE)]; + +/* + * Routines for reading, writing and header identify of various versions of pax + */ + +static size_t expandname(char *, size_t, char **, const char *, size_t); +static u_long pax_chksm(char *, int); +char *name_split(char *, int); +static int ul_oct(u_long, char *, int, int); +#ifndef LONG_OFF_T +static int uqd_oct(u_quad_t, char *, int, int); +#endif + +static uid_t uid_nobody; +static uid_t uid_warn; +static gid_t gid_nobody; +static gid_t gid_warn; + +/* + * Routines common to all versions of pax + */ + +#if 0 +static int tar_nodir; /* do not write dirs under old tar */ +char *gnu_name_string; /* GNU ././@LongLink hackery name */ +char *gnu_link_string; /* GNU ././@LongLink hackery link */ + +/* + * tar_endwr() + * add the tar trailer of two null blocks + * Return: + * 0 if ok, -1 otherwise (what wr_skip returns) + */ + +int +tar_endwr(void) +{ + return(wr_skip((off_t)(NULLCNT*BLKMULT))); +} + +/* + * tar_endrd() + * no cleanup needed here, just return size of trailer (for append) + * Return: + * size of trailer (2 * BLKMULT) + */ + +off_t +tar_endrd(void) +{ + return((off_t)(NULLCNT*BLKMULT)); +} + +/* + * tar_trail() + * 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) which is + * used to count the number of empty blocks we have seen so far. + * Return: + * 0 if a valid trailer, -1 if not a valid trailer, or 1 if the block + * could never contain a header. + */ + +int +tar_trail(ARCHD *ignore, char *buf, int in_resync, int *cnt) +{ + int i; + + /* + * look for all zero, trailer is two consecutive blocks of zero + */ + for (i = 0; i < BLKMULT; ++i) { + if (buf[i] != '\0') + break; + } + + /* + * if not all zero it is not a trailer, but MIGHT be a header. + */ + if (i != BLKMULT) + return(-1); + + /* + * When given a zero block, we must be careful! + * If we are not in resync mode, check for the trailer. Have to watch + * out that we do not mis-identify file data as the trailer, so we do + * NOT try to id a trailer during resync mode. During resync mode we + * might as well throw this block out since a valid header can NEVER be + * a block of all 0 (we must have a valid file name). + */ + if (!in_resync && (++*cnt >= NULLCNT)) + return(0); + return(1); +} +#endif + +/* + * ul_oct() + * convert an unsigned long to an octal string. many oddball field + * termination characters are used by the various versions of tar in the + * different fields. term selects which kind to use. str is '0' padded + * at the front to len. we are unable to use only one format as many old + * tar readers are very cranky about this. + * Return: + * 0 if the number fit into the string, -1 otherwise + */ + +static int +ul_oct(u_long val, char *str, int len, int term) +{ + char *pt; + + /* + * term selects the appropriate character(s) for the end of the string + */ + pt = str + len - 1; + switch (term) { + case 3: + *pt-- = '\0'; + break; + case 2: + *pt-- = ' '; + *pt-- = '\0'; + break; + case 1: + *pt-- = ' '; + break; + case 0: + default: + *pt-- = '\0'; + *pt-- = ' '; + break; + } + + /* + * convert and blank pad if there is space + */ + while (pt >= str) { + *pt-- = '0' + (char)(val & 0x7); + if ((val = val >> 3) == (u_long)0) + break; + } + + while (pt >= str) + *pt-- = '0'; + if (val != (u_long)0) + return(-1); + return(0); +} + +#ifndef LONG_OFF_T +/* + * uqd_oct() + * convert an u_quad_t to an octal string. one of many oddball field + * termination characters are used by the various versions of tar in the + * different fields. term selects which kind to use. str is '0' padded + * at the front to len. we are unable to use only one format as many old + * tar readers are very cranky about this. + * Return: + * 0 if the number fit into the string, -1 otherwise + */ + +static int +uqd_oct(u_quad_t val, char *str, int len, int term) +{ + char *pt; + + /* + * term selects the appropriate character(s) for the end of the string + */ + pt = str + len - 1; + switch (term) { + case 3: + *pt-- = '\0'; + break; + case 2: + *pt-- = ' '; + *pt-- = '\0'; + break; + case 1: + *pt-- = ' '; + break; + case 0: + default: + *pt-- = '\0'; + *pt-- = ' '; + break; + } + + /* + * convert and blank pad if there is space + */ + while (pt >= str) { + *pt-- = '0' + (char)(val & 0x7); + if ((val = val >> 3) == 0) + break; + } + + while (pt >= str) + *pt-- = '0'; + if (val != (u_quad_t)0) + return(-1); + return(0); +} +#endif + +/* + * pax_chksm() + * calculate the checksum for a pax block counting the checksum field as + * all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks). + * NOTE: we use len to short circuit summing 0's on write since we ALWAYS + * pad headers with 0. + * Return: + * unsigned long checksum + */ + +static u_long +pax_chksm(char *blk, int len) +{ + char *stop; + char *pt; + u_long chksm = BLNKSUM; /* initial value is checksum field sum */ + + /* + * add the part of the block before the checksum field + */ + pt = blk; + stop = blk + CHK_OFFSET; + while (pt < stop) + chksm += (u_long)(*pt++ & 0xff); + /* + * move past the checksum field and keep going, spec counts the + * checksum field as the sum of 8 blanks (which is pre-computed as + * BLNKSUM). + * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding + * starts, no point in summing zero's) + */ + pt += CHK_LEN; + stop = blk + len; + while (pt < stop) + chksm += (u_long)(*pt++ & 0xff); + return(chksm); +} + +#if 0 +/* + * Routines for old BSD style tar (also made portable to sysV tar) + */ + +/* pax_id must be derived from ustar, NOT tar */ +/* + * tar_id() + * determine if a block given to us is a valid tar header (and not a USTAR + * header). We have to be on the lookout for those pesky blocks of all + * zero's. + * Return: + * 0 if a tar header, -1 otherwise + */ + +int +tar_id(char *blk, int size) +{ + HD_TAR *hd; + HD_USTAR *uhd; + + if (size < BLKMULT) + return(-1); + hd = (HD_TAR *)blk; + uhd = (HD_USTAR *)blk; + + /* + * check for block of zero's first, a simple and fast test, then make + * sure this is not a ustar header by looking for the ustar magic + * cookie. We should use TMAGLEN, but some USTAR archive programs are + * wrong and create archives missing the \0. Last we check the + * checksum. If this is ok we have to assume it is a valid header. + */ + if (hd->name[0] == '\0') + return(-1); + if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0) + return(-1); + if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) + return(-1); + force_one_volume = 1; + return(0); +} +#endif + +void +pax_format_list_output(ARCHD *arcn, time_t now, FILE *fp, int term) +{ + /* parse specified listopt format */ + char *nextpercent, *nextchar; + char buf[4*1024]; + int pos, cpylen; + char *fname; + + nextpercent = strchr(pax_list_opt_format,'%'); + if (nextpercent==NULL) { + /* Strange case: no specifiers? */ + safe_print(pax_list_opt_format, fp); + (void)putc(term, fp); + (void)fflush(fp); + return; + } + pos = nextpercent-pax_list_opt_format; + memcpy(buf,pax_list_opt_format, pos); + while (nextpercent++) { + switch (*nextpercent) { + case 'F': + fname = arcn->name; + cpylen = strlen(fname); + memcpy(&buf[pos],fname,cpylen); + pos+= cpylen; + break; + case 'D': + case 'T': + case 'M': + case 'L': + default: + paxwarn(1, "Unimplemented listopt format: %c",*nextpercent); + break; + } + nextpercent++; + if (*nextpercent=='\0') { + break; + } + nextchar = nextpercent; + nextpercent = strchr(nextpercent,'%'); + if (nextpercent==NULL) { + cpylen = strlen(nextchar); + } else { + cpylen = nextpercent - nextchar; + } + memcpy(&buf[pos],nextchar, cpylen); + pos += cpylen; + } + buf[pos]='\0'; + safe_print(&buf[0], fp); + (void)putc(term, fp); + (void)fflush(fp); + return; +} + +void +cleanup_pax_invalid_action() +{ + switch (pax_invalid_action) { + case PAX_INVALID_ACTION_BYPASS: + case PAX_INVALID_ACTION_RENAME: + break; + case PAX_INVALID_ACTION_WRITE: + pax_invalid_action_write_path = NULL; + if (pax_invalid_action_write_cwd) { + free(pax_invalid_action_write_cwd); + pax_invalid_action_write_cwd = NULL; + } + break; + case PAX_INVALID_ACTION_UTF8: + default: + paxwarn(1, "pax_invalid_action not implemented:%d", pax_invalid_action); + } +} + +void +record_pax_invalid_action_results(ARCHD * arcn, char * fixed_path) +{ + switch (pax_invalid_action) { + case PAX_INVALID_ACTION_BYPASS: + case PAX_INVALID_ACTION_RENAME: + break; + case PAX_INVALID_ACTION_WRITE: + pax_invalid_action_write_path = fixed_path; + pax_invalid_action_write_cwd = strdup(arcn->name); + pax_invalid_action_write_cwd[fixed_path-arcn->name-1] = '\0'; + break; + case PAX_INVALID_ACTION_UTF8: + default: + paxwarn(1, "pax_invalid_action not implemented:%d", pax_invalid_action); + } +} + +int +perform_pax_invalid_action(ARCHD * arcn, int err) +{ + int rc = 0; + switch (pax_invalid_action) { + case PAX_INVALID_ACTION_BYPASS: + rc = -1; + break; + case PAX_INVALID_ACTION_RENAME: + rc = tty_rename(arcn); + break; + case PAX_INVALID_ACTION_WRITE: + pax_invalid_action_write_path = NULL; + pax_invalid_action_write_cwd = NULL; + rc = 2; + break; + case PAX_INVALID_ACTION_UTF8: + default: + paxwarn(1, "pax_invalid_action not implemented:%d", pax_invalid_action); + rc = -1; /* do nothing? */ + } + return rc; +} + +void +delete_keywords(char * pattern) +{ + int i; + /* loop over all keywords, marking any matched as deleted */ + for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) { + if (fnmatch(pattern, o_option_table[i].name, 0) == 0) { + /* Found option: mark deleted */ + o_option_table[i].active = 0; + } + } +} + +/* + * pax_opt() + * handle pax format specific -o options + * Return: + * 0 if ok -1 otherwise + */ + +int +pax_opt(void) +{ + OPLIST *opt; + int got_option = 0; + + while ((opt = opt_next()) != NULL) { + int i; + got_option = -1; + pax_invalid_action = PAX_INVALID_ACTION_BYPASS; /* Default for pax format */ + /* look up opt->name */ + for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) { + if (strncasecmp(opt->name, o_option_table[i].name, o_option_table[i].len) == 0) { + /* Found option: see if already set */ + /* Save it away */ + got_option = 1; + switch (o_option_table[i].cmdline_action) { + case O_OPTION_ACTION_INVALID: + if (opt->separator != SEP_EQ) { + paxwarn(1,"-o %s= option requires '=' separator: option ignored", + opt->name); + break; + } + if (opt->value) { + if (strncasecmp(opt->value,"bypass",6) == 0) { + pax_invalid_action = PAX_INVALID_ACTION_BYPASS; + } else if (strncasecmp(opt->value,"rename",6) == 0) { + pax_invalid_action = PAX_INVALID_ACTION_RENAME; + } else if (strncasecmp(opt->value,"UTF-8",5) == 0) { + pax_invalid_action = PAX_INVALID_ACTION_UTF8; + } else if (strncasecmp(opt->value,"write",5) == 0) { + pax_invalid_action = PAX_INVALID_ACTION_WRITE; + } else { + paxwarn(1,"Invalid action %s not recognized: option ignored", + opt->value); + } + } else { + paxwarn(1,"Invalid action RHS not specified: option ignored"); + } + break; + case O_OPTION_ACTION_DELETE: + if (opt->separator != SEP_EQ) { + paxwarn(1,"-o %s= option requires '=' separator: option ignored", + opt->name); + break; + } + /* Mark all matches as deleted */ + /* can have multiple -o delete= patterns */ + delete_keywords(opt->value); + break; + case O_OPTION_ACTION_STORE_HEADER2: + if(pax_read_or_list_mode) pids = 1; /* Force -p o for these options */ + case O_OPTION_ACTION_STORE_HEADER: + if (o_option_table[i].g_value == NULL || + o_option_table[i].x_value == NULL ) { + paxwarn(1,"-o option not implemented: %s=%s", + opt->name, opt->value); + } else { + if (opt->separator == SEP_EQ) { + *(o_option_table[i].g_value) = opt->value; + global_ext_header_entry[global_ext_header_inx++] = i; + } else if (opt->separator == SEP_COLONEQ ) { + *(o_option_table[i].x_value) = opt->value; + ext_header_entry [ext_header_inx++] = i; + } else { /* SEP_NONE */ + paxwarn(1,"-o %s option is missing value", opt->name); + } + } + break; + case O_OPTION_ACTION_TIMES: + if (opt->separator != SEP_NONE) { + paxwarn(1,"-o %s option takes no value: option ignored", opt->name); + break; + } + want_a_m_time_headers = 1; + break; + case O_OPTION_ACTION_LINKDATA: + if (opt->separator != SEP_NONE) { + paxwarn(1,"-o %s option takes no value: option ignored", opt->name); + break; + } + want_linkdata = 1; + break; + case O_OPTION_ACTION_HEADER_NAME: + if (opt->separator != SEP_EQ) { + paxwarn(1,"-o %s= option requires '=' separator: option ignored", + opt->name); + break; + } + *(o_option_table[i].g_value) = opt->value; + *(o_option_table[i].x_value) = "YES"; + break; + case O_OPTION_ACTION_LISTOPT: + if (opt->separator != SEP_EQ) { + paxwarn(1,"-o %s= option requires '=' separator: option ignored", + opt->name); + break; + } + *(o_option_table[i].g_value) = opt->value; + break; + case O_OPTION_ACTION_NOTIMPL: + default: + paxwarn(1,"pax format -o option not yet implemented: %s=%s", + opt->name, opt->value); + break; + } + break; + } + } + if (got_option == -1) { + paxwarn(1,"pax format -o option not recognized: %s=%s", + opt->name, opt->value); + } + } + return(0); +} + + +#if 0 +/* pax_rd is derived from ustar_rd NOT tar_rd */ +/* + * tar_rd() + * extract the values out of block already determined to be a tar header. + * store the values in the ARCHD parameter. + * Return: + * 0 + */ + +int +tar_rd(ARCHD *arcn, char *buf) +{ + HD_TAR *hd; + char *pt; + + /* + * we only get proper sized buffers passed to us + */ + if (tar_id(buf, BLKMULT) < 0) + return(-1); + memset(arcn, 0, sizeof(*arcn)); + arcn->org_name = arcn->name; + arcn->sb.st_nlink = 1; + + /* + * copy out the name and values in the stat buffer + */ + hd = (HD_TAR *)buf; + if (hd->linkflag != LONGLINKTYPE && hd->linkflag != LONGNAMETYPE) { + arcn->nlen = expandname(arcn->name, sizeof(arcn->name), + &gnu_name_string, hd->name, sizeof(hd->name)); + arcn->ln_nlen = expandname(arcn->ln_name, sizeof(arcn->ln_name), + &gnu_link_string, hd->linkname, sizeof(hd->linkname)); + } + arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) & + 0xfff); + arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); + arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); +#ifdef LONG_OFF_T + arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); +#else + arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); +#endif + arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); + arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; + + /* + * have to look at the last character, it may be a '/' and that is used + * to encode this as a directory + */ + pt = &(arcn->name[arcn->nlen - 1]); + arcn->pad = 0; + arcn->skip = 0; + switch (hd->linkflag) { + case SYMTYPE: + /* + * symbolic link, need to get the link name and set the type in + * the st_mode so -v printing will look correct. + */ + arcn->type = PAX_SLK; + arcn->sb.st_mode |= S_IFLNK; + break; + case LNKTYPE: + /* + * hard link, need to get the link name, set the type in the + * st_mode and st_nlink so -v printing will look better. + */ + arcn->type = PAX_HLK; + arcn->sb.st_nlink = 2; + + /* + * no idea of what type this thing really points at, but + * we set something for printing only. + */ + arcn->sb.st_mode |= S_IFREG; + break; + case LONGLINKTYPE: + case LONGNAMETYPE: + /* + * GNU long link/file; we tag these here and let the + * pax internals deal with it -- too ugly otherwise. + */ + arcn->type = + hd->linkflag == LONGLINKTYPE ? PAX_GLL : PAX_GLF; + arcn->pad = TAR_PAD(arcn->sb.st_size); + arcn->skip = arcn->sb.st_size; + break; + case DIRTYPE: + /* + * It is a directory, set the mode for -v printing + */ + arcn->type = PAX_DIR; + arcn->sb.st_mode |= S_IFDIR; + arcn->sb.st_nlink = 2; + break; + case AREGTYPE: + case REGTYPE: + default: + /* + * If we have a trailing / this is a directory and NOT a file. + */ + arcn->ln_name[0] = '\0'; + arcn->ln_nlen = 0; + if (*pt == '/') { + /* + * it is a directory, set the mode for -v printing + */ + arcn->type = PAX_DIR; + arcn->sb.st_mode |= S_IFDIR; + arcn->sb.st_nlink = 2; + } else { + /* + * have a file that will be followed by data. Set the + * skip value to the size field and calculate the size + * of the padding. + */ + arcn->type = PAX_REG; + arcn->sb.st_mode |= S_IFREG; + arcn->pad = TAR_PAD(arcn->sb.st_size); + arcn->skip = arcn->sb.st_size; + } + break; + } + + /* + * strip off any trailing slash. + */ + if (*pt == '/') { + *pt = '\0'; + --arcn->nlen; + } + return(0); +} + +/* pax_wr is derived from ustar_wr NOT tar_wr */ +/* + * tar_wr() + * write a tar header for the file specified in the ARCHD to the archive. + * Have to check for file types that cannot be stored and file names that + * are too long. Be careful of the term (last arg) to ul_oct, each field + * of tar has it own spec for the termination character(s). + * ASSUMED: space after header in header block is zero filled + * Return: + * 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 + */ + +int +tar_wr(ARCHD *arcn) +{ + HD_TAR *hd; + int len; + char hdblk[sizeof(HD_TAR)]; + + /* + * check for those file system types which tar cannot store + */ + switch (arcn->type) { + case PAX_DIR: + /* + * user asked that dirs not be written to the archive + */ + if (tar_nodir) + return(1); + break; + case PAX_CHR: + paxwarn(1, "Tar cannot archive a character device %s", + arcn->org_name); + return(1); + case PAX_BLK: + paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name); + return(1); + case PAX_SCK: + paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name); + return(1); + case PAX_FIF: + paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name); + return(1); + case PAX_SLK: + case PAX_HLK: + case PAX_HRG: + if (arcn->ln_nlen > sizeof(hd->linkname)) { + paxwarn(1,"Link name too long for tar %s", arcn->ln_name); + return(1); + } + break; + case PAX_REG: + case PAX_CTG: + default: + break; + } + + /* + * check file name len, remember extra char for dirs (the / at the end) + */ + len = arcn->nlen; + if (arcn->type == PAX_DIR) + ++len; + if (len >= sizeof(hd->name)) { + paxwarn(1, "File name too long for tar %s", arcn->name); + return(1); + } + + /* + * Copy the data out of the ARCHD into the tar header based on the type + * of the file. Remember, many tar readers want all fields to be + * padded with zero so we zero the header first. We then set the + * linkflag field (type), the linkname, the size, and set the padding + * (if any) to be added after the file data (0 for all other types, + * as they only have a header). + */ + memset(hdblk, 0, sizeof(hdblk)); + hd = (HD_TAR *)hdblk; + strlcpy(hd->name, arcn->name, sizeof(hd->name)); + arcn->pad = 0; + + if (arcn->type == PAX_DIR) { + /* + * directories are the same as files, except have a filename + * that ends with a /, we add the slash here. No data follows + * dirs, so no pad. + */ + hd->linkflag = AREGTYPE; + hd->name[len-1] = '/'; + if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) + goto out; + } else if (arcn->type == PAX_SLK) { + /* + * no data follows this file, so no pad + */ + hd->linkflag = SYMTYPE; + strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname)); + if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) + goto out; + } else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) { + /* + * no data follows this file, so no pad + */ + hd->linkflag = LNKTYPE; + strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname)); + if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) + goto out; + } else { + /* + * data follows this file, so set the pad + */ + hd->linkflag = AREGTYPE; +# ifdef LONG_OFF_T + if (ul_oct((u_long)arcn->sb.st_size, hd->size, + sizeof(hd->size), 1)) { +# else + if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, + sizeof(hd->size), 1)) { +# endif + paxwarn(1,"File is too large for tar %s", arcn->org_name); + return(1); + } + arcn->pad = TAR_PAD(arcn->sb.st_size); + } + + /* + * copy those fields that are independent of the type + */ + if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) || + ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) || + ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) || + ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1)) + goto out; + + /* + * calculate and add the checksum, then write the header. A return of + * 0 tells the caller to now write the file data, 1 says no data needs + * to be written + */ + if (ul_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum, + sizeof(hd->chksum), 3)) + goto out; + if (wr_rdbuf(hdblk, sizeof(HD_TAR)) < 0) + return(-1); + if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0) + return(-1); + if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) + return(0); + return(1); + + out: + /* + * header field is out of range + */ + paxwarn(1, "Tar header field is too small for %s", arcn->org_name); + return(1); +} +#endif + +#if 0 +/* + * Routines for POSIX ustar + */ + +/* + * ustar_strd() + * initialization for ustar read + * Return: + * 0 if ok, -1 otherwise + */ + +int +ustar_strd(void) +{ + if ((usrtb_start() < 0) || (grptb_start() < 0)) + return(-1); + return(0); +} + +/* + * ustar_stwr() + * initialization for ustar write + * Return: + * 0 if ok, -1 otherwise + */ + +int +ustar_stwr(void) +{ + if ((uidtb_start() < 0) || (gidtb_start() < 0)) + return(-1); + return(0); +} +#endif + +int +expand_extended_headers(ARCHD *arcn, HD_USTAR *hd) +{ + char mybuf[BLKMULT]; + HD_USTAR *myhd; + char * current_value; + int path_replaced = 0; + int i, len; + + myhd = hd; + while (myhd->typeflag == PAXGTYPE || myhd->typeflag == PAXXTYPE) { + char *name, *str; + int size, nbytes, inx; + size = asc_ul(myhd->size, sizeof(myhd->size), OCT); + if (size > sizeof(mybuf)) + paxwarn(1,"extended header buffer overflow"); + nbytes = rd_wrbuf(mybuf, size); + if (nbytes != size) { + paxwarn(1,"extended header data read failure: nbytes=%d, size=%d\n", + nbytes, size); + } + /* + printf("Read 1 extended header: type=%c, size=%d\n", + myhd->typeflag, size); + */ + inx=0; + /* loop over buffer collecting attributes */ + while (nbytes > 0) { + int got_option = -1; + int nentries = sscanf(&mybuf[inx],"%d ", &len); + if (nentries != 1) { + paxwarn(1,"Extended header failure: length"); + } + if (mybuf[inx+len-1] != '\n') + paxwarn(1,"Extended header failure: missed newline"); + else mybuf[inx+len-1] = '\0'; + name = strchr(&mybuf[inx],' '); + if (name) name++; + else + paxwarn(1,"Extended header failure: missing space"); + str = strchr(name,'='); + if (str) { + *str++='\0'; /* end of name */ + } else + paxwarn(1,"Extended header failure: missing RHS string"); + for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) { + if (strncasecmp(name, o_option_table[i].name, o_option_table[i].len) == 0) { + /* Found option: see if already set TBD */ + /* Save it away */ + got_option = i; + break; + } + } + if (got_option == -1) { + paxwarn(1,"Unrecognized header keyword: %s",name); + } else { + /* Determine precedence of -o and header attributes */ + int found_value = ATTRSRC_FROM_NOWHERE; + current_value = NULL; + if (myhd->typeflag == PAXXTYPE) { + if (*o_option_table[got_option].x_value) { + current_value = *o_option_table[got_option].x_value; + found_value = ATTRSRC_FROM_X_O_OPTION; + } else { + current_value = str; + found_value = ATTRSRC_FROM_X_HEADER; + } + } else if (myhd->typeflag == PAXGTYPE) { + if (*o_option_table[got_option].g_value) { + current_value = *o_option_table[got_option].g_value; + found_value = ATTRSRC_FROM_G_O_OPTION; + } else { + current_value = str; + found_value = ATTRSRC_FROM_G_HEADER; + } + } else { + paxwarn(1,"Unsupported header type:%c",myhd->typeflag); + } + if (current_value) { + /* Save this attribute value for use later */ + switch (o_option_table[got_option].header_action) { + case O_OPTION_ACTION_IGNORE: + paxwarn(1,"ignoring header keyword: %s",name); + break; + case O_OPTION_ACTION_STORE_HEADER2: + case O_OPTION_ACTION_STORE_HEADER: + switch (found_value) { + case ATTRSRC_FROM_NOWHERE: /* shouldn't happen */ + paxwarn(1, "internal error: value from nowhere"); + break; + case ATTRSRC_FROM_X_O_OPTION: + case ATTRSRC_FROM_G_O_OPTION: + break; + case ATTRSRC_FROM_X_HEADER: + current_value = strdup(current_value); + if(*o_option_table[got_option].x_value_current) + free(*o_option_table[got_option].x_value_current); + *o_option_table[got_option].x_value_current = current_value; + break; + case ATTRSRC_FROM_G_HEADER: + current_value = strdup(current_value); + if(*o_option_table[got_option].g_value_current) + free(*o_option_table[got_option].g_value_current); + *o_option_table[got_option].g_value_current = current_value; + break; + } + break; + case O_OPTION_ACTION_ERROR: + default: + paxwarn(1,"Unsupported extended header attribute: %s=%s", + name, str); + } + } + } + inx+=len; + nbytes -= len; + } + + /* position file at next header */ + (void)rd_skip(TAR_PAD(size)); + + /* read next header */ + nbytes = rd_wrbuf(mybuf, frmt->hsz); + if (nbytes != frmt->hsz) { + paxwarn(1,"extended header read failure: nbytes=%d, size=%d\n", + nbytes, frmt->hsz); + } + myhd = ((HD_USTAR *)mybuf); + /* repeat until no more extended headers */ + } + + /* The header about to be returned must now be updated using all the extended + header values collected and any command line options */ + /* Acceleration: check during command option processing. If there are no -o + options, and no changes from any header, do not need to run through this loop. */ + + current_value = NULL; + for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) { + int header_len, free_it; + if (!o_option_table[i].active) continue; /* deleted keywords */ + header_len = o_option_table[i].header_len; + free_it = 0; + if (header_len >= 0) { /* Normal keywords */ + current_value = *o_option_table[i].x_value; + if (!current_value) { /* No -o := */ + current_value = *o_option_table[i].x_value_current; + if (current_value) { + /* Must remove it: x header values not valid beyond this header */ + *o_option_table[i].x_value_current = NULL; + free_it = 1; + } else { /* No x values, try globals */ + current_value = *o_option_table[i].g_value; + if (!current_value) + current_value = *o_option_table[i].g_value_current; + } + } + if (current_value) { + /* Update current header with this value */ + /* + printf ("Found current_value:%s for %s, pids=%d\n", + current_value, o_option_table[i].name, pids); + */ + len = strlen(current_value); + if (header_len == KW_PATH_CASE) { /* Special case for path keyword */ + path_replaced = 1; + arcn->nlen = len; + strlcpy(arcn->name,current_value,sizeof(arcn->name)); + } else { + if (len > header_len) { + paxwarn(1," length of string from extended header bigger than header field:" + " THAT won't work!\n"); + } else { + char * p = (char *) myhd; + memcpy(&p[o_option_table[i].header_inx], + current_value, len); + if (len != header_len) { + /* pad with ? */ + p[o_option_table[i].header_inx+len+1] = '\0'; + } + } + } + } + if (free_it) free(current_value); + } + } + + if (myhd==hd) return(path_replaced); + + /* must put new header into memory of original */ + memcpy(hd, myhd, sizeof(HD_USTAR)); + + return(path_replaced); +} + +/* + * pax_id() + * determine if a block given to us is a valid pax header. We have to + * be on the lookout for those pesky blocks of all zero's + * Return: + * 0 if a ustar header, -1 otherwise + */ + +int +pax_id(char *blk, int size) +{ + HD_USTAR *hd; + + if (size < BLKMULT) + return(-1); + hd = (HD_USTAR *)blk; + + /* + * check for block of zero's first, a simple and fast test then check + * ustar magic cookie. We should use TMAGLEN, but some USTAR archive + * programs are fouled up and create archives missing the \0. Last we + * check the checksum. If ok we have to assume it is a valid header. + */ + if (hd->name[0] == '\0') + return(-1); + if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0) + return(-1); + if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != pax_chksm(blk,BLKMULT)) + return(-1); + if ((hd->typeflag != PAXXTYPE) && (hd->typeflag != PAXGTYPE)) { + /* Not explicitly pax format, but at least ustar */ + if (act==LIST || act==EXTRACT) { + /* Although insufficient evidence, call it pax format */ + return(0); + } + return(-1); + } + pax_invalid_action = PAX_INVALID_ACTION_BYPASS; /* Default for pax format */ + return(0); +} + +/* + * pax_rd() + * extract the values out of block already determined to be a pax header. + * store the values in the ARCHD parameter. + * Return: + * 0 + */ + +int +pax_rd(ARCHD *arcn, char *buf) +{ + HD_USTAR *hd; + int cnt = 0; + int check_path; + dev_t devmajor; + dev_t devminor; + + /* + * we only get proper sized buffers + */ + if (pax_id(buf, BLKMULT) < 0) + return(-1); + + memset(arcn, 0, sizeof(*arcn)); + arcn->org_name = arcn->name; + arcn->sb.st_nlink = 1; + hd = (HD_USTAR *)buf; + + check_path = expand_extended_headers(arcn, hd); + + if (check_path) { + /* + * pathname derived from extended head or -o option; + * full name is in one string, but length may exceed + * max path so be careful. + */ + if (arcn->nlen > sizeof(arcn->name)) { + paxwarn(1,"pathname from extended header info doesn't fit! (len=%d)\n", + arcn->nlen); + } + } else { + /* + * see if the filename is split into two parts. if so, join the parts. + * we copy the prefix first and add a / between the prefix and name. + */ + char *dest = arcn->name; + if (*(hd->prefix) != '\0') { + cnt = strlcpy(dest, hd->prefix, sizeof(arcn->name) - 1); + dest += cnt; + *dest++ = '/'; + cnt++; + } else { + cnt = 0; + } + + if (hd->typeflag != LONGLINKTYPE && hd->typeflag != LONGNAMETYPE) { + arcn->nlen = expandname(dest, sizeof(arcn->name) - cnt, + &gnu_name_string, hd->name, sizeof(hd->name)); + arcn->ln_nlen = expandname(arcn->ln_name, sizeof(arcn->ln_name), + &gnu_link_string, hd->linkname, sizeof(hd->linkname)); + } + } + + /* + * follow the spec to the letter. we should only have mode bits, strip + * off all other crud we may be passed. + */ + arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) & + 0xfff); +#ifdef LONG_OFF_T + arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); +#else + arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); +#endif + arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); + arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; + + /* + * If we can find the ascii names for gname and uname in the password + * and group files we will use the uid's and gid they bind. Otherwise + * we use the uid and gid values stored in the header. (This is what + * the posix spec wants). + */ + hd->gname[sizeof(hd->gname) - 1] = '\0'; + if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0) + arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); + hd->uname[sizeof(hd->uname) - 1] = '\0'; + if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0) + arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); + + /* + * set the defaults, these may be changed depending on the file type + */ + arcn->pad = 0; + arcn->skip = 0; + arcn->sb.st_rdev = (dev_t)0; + + /* + * set the mode and PAX type according to the typeflag in the header + */ + switch (hd->typeflag) { + case FIFOTYPE: + arcn->type = PAX_FIF; + arcn->sb.st_mode |= S_IFIFO; + break; + case DIRTYPE: + arcn->type = PAX_DIR; + arcn->sb.st_mode |= S_IFDIR; + arcn->sb.st_nlink = 2; + + /* + * Some programs that create pax archives append a '/' + * to the pathname for directories. This clearly violates + * pax specs, but we will silently strip it off anyway. + */ + if (arcn->name[arcn->nlen - 1] == '/') + arcn->name[--arcn->nlen] = '\0'; + break; + case BLKTYPE: + case CHRTYPE: + /* + * this type requires the rdev field to be set. + */ + if (hd->typeflag == BLKTYPE) { + arcn->type = PAX_BLK; + arcn->sb.st_mode |= S_IFBLK; + } else { + arcn->type = PAX_CHR; + arcn->sb.st_mode |= S_IFCHR; + } + devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT); + devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT); + arcn->sb.st_rdev = TODEV(devmajor, devminor); + break; + case SYMTYPE: + case LNKTYPE: + if (hd->typeflag == SYMTYPE) { + arcn->type = PAX_SLK; + arcn->sb.st_mode |= S_IFLNK; + } else { + arcn->type = PAX_HLK; + /* + * so printing looks better + */ + arcn->sb.st_mode |= S_IFREG; + arcn->sb.st_nlink = 2; + } + break; + case LONGLINKTYPE: + case LONGNAMETYPE: + /* + * GNU long link/file; we tag these here and let the + * pax internals deal with it -- too ugly otherwise. + */ + arcn->type = + hd->typeflag == LONGLINKTYPE ? PAX_GLL : PAX_GLF; + arcn->pad = TAR_PAD(arcn->sb.st_size); + arcn->skip = arcn->sb.st_size; + break; + case CONTTYPE: + case AREGTYPE: + case REGTYPE: + default: + /* + * these types have file data that follows. Set the skip and + * pad fields. + */ + arcn->type = PAX_REG; + arcn->pad = TAR_PAD(arcn->sb.st_size); + arcn->skip = arcn->sb.st_size; + arcn->sb.st_mode |= S_IFREG; + break; + } + return(0); +} + +void +adjust_copy_for_pax_options(ARCHD * arcn) +{ + /* Because ext_header options take precedence over global_header options, apply + global options first, then override with any extended header options */ + int i; + if (global_ext_header_inx) { + for (i=0; i < global_ext_header_inx; i++) { + if (!o_option_table[global_ext_header_entry[i]].active) continue; /* deleted keywords */ + if (strcmp(o_option_table[global_ext_header_entry[i]].name, "path")==0) { + strlcpy(arcn->name,*(o_option_table[global_ext_header_entry[i]].g_value), + sizeof(arcn->name)); + arcn->nlen = strlen(*(o_option_table[global_ext_header_entry[i]].g_value)); + } else { /* only handle path for now: others TBD */ + paxwarn(1, "adjust arcn for global extended header options not implemented:%d", i); + } + } + } + if (ext_header_inx) { + for (i=0; i < ext_header_inx; i++) { + if (!o_option_table[ext_header_entry[i]].active) continue; /* deleted keywords */ + if (strcmp(o_option_table[ext_header_entry[i]].name, "path")==0) { + strlcpy(arcn->name,*(o_option_table[ext_header_entry[i]].x_value), + sizeof(arcn->name)); + arcn->nlen = strlen(*(o_option_table[ext_header_entry[i]].x_value)); + } else { /* only handle path for now: others TBD */ + paxwarn(1, "adjust arcn for extended header options not implemented:%d", i); + } + } + } + if (want_a_m_time_headers) { + /* TBD */ + } +} + +static int +emit_extended_header_record(int len, int total_len, int head_type, + char * name, char * value) +{ + if (total_len + len > sizeof(pax_eh_datablk)) { + paxwarn(1,"extended header buffer overflow for header type '%c': %d", + head_type, total_len+len); + } else { + sprintf(&pax_eh_datablk[total_len],"%d %s=%s\n", len, name, value); + total_len += len; + } + return (total_len); +} + +static char * +substitute_percent(char * header, char * filename) +{ + char *nextpercent, *nextchar; + char buf[4*1024]; + int pos, cpylen; + char *dname, *fname; + + nextpercent = strchr(header,'%'); + if (nextpercent==NULL) return header; + pos = nextpercent-header; + memcpy(buf,header, pos); + while (nextpercent++) { + switch (*nextpercent) { + case '%': + buf[pos++]='%'; /* just skip it */ + break; + case 'd': + dname = strrchr(filename,'/'); + if (dname==NULL) { + cpylen = 1; + dname = "."; + } else { + cpylen = dname-filename; + dname = filename; + } + memcpy(&buf[pos],dname,cpylen); + pos+= cpylen; + break; + case 'f': + fname = strrchr(filename,'/'); + if (fname==NULL) { + fname = filename; + } else { + fname++; + } + cpylen = strlen(fname); + memcpy(&buf[pos],fname,cpylen); + pos+= cpylen; + break; + case 'n': + pos += sprintf (&buf[pos],"%d",nglobal_headers); + break; + case 'p': + pos += sprintf (&buf[pos],"%d",getpid()); + break; + default: + paxwarn(1,"header format substitution failed: '%c'", *nextpercent); + return (header); + } + nextpercent++; + if (*nextpercent=='\0') { + break; + } + nextchar = nextpercent; + nextpercent = strchr(nextpercent,'%'); + if (nextpercent==NULL) { + cpylen = strlen(nextchar); + } else { + cpylen = nextpercent - nextchar; + } + memcpy(&buf[pos],nextchar, cpylen); + pos += cpylen; + } + buf[pos]='\0'; + return (strdup(&buf[0])); +} + +int +generate_pax_ext_header_and_data(ARCHD *arcn, int nfields, int *table, + char header_type, char * header_name, char * header_name_requested) +{ + HD_USTAR *hd; + char hdblk[sizeof(HD_USTAR)]; + u_long records_size; + int term_char, i, len, total_len; + char * str, *name; + + if (nfields == 0 && (header_name_requested == NULL)) { + if (header_type==PAXXTYPE) { + if (!want_a_m_time_headers) return (0); + } else + return (0); + } + + /* There might be no fields but a header with a specific name or + times might be wanted */ + + term_char = 1; + records_size = 0; + memset(hdblk, 0, sizeof(hdblk)); + hd = (HD_USTAR *)hdblk; + memset(pax_eh_datablk, 0, sizeof(pax_eh_datablk)); + + /* generate header */ + hd->typeflag = header_type; + + /* These fields appear to be necessary to be able to treat extended headers + like files in older versions of pax */ + ul_oct((u_long)0444, hd->mode, sizeof(hd->mode), term_char); + strncpy(hd->magic, TMAGIC, TMAGLEN); + strncpy(hd->version, TVERSION, TVERSLEN); + ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),term_char); + + /* compute size of data */ + total_len = 0; + for (i=0; i < nfields; i++) { + if (!o_option_table[table[i]].active) continue; /* deleted keywords */ + name = o_option_table[table[i]].name; + if (header_type == PAXXTYPE) { + str = *(o_option_table[table[i]].x_value); + } else { + str = *(o_option_table[table[i]].g_value); + } + if (str==NULL) { + paxwarn(1,"Missing option value for %s", name); + continue; + } + len = strlen(str) + o_option_table[table[i]].len + 3; + if (len < 9) len++; + else if (len < 98) len = len + 2; + else if (len < 997) len = len + 3; + else if (len < 9996) len = len + 4; + else { + paxwarn(1,"extended header data too long for header type '%c': %d", + header_type, len); + } + total_len = emit_extended_header_record(len, total_len, + header_type, name, str); + } + + if ((header_type == PAXXTYPE) && want_a_m_time_headers) { + char time_buffer[12]; + memset(time_buffer,0,sizeof(time_buffer)); + sprintf(&time_buffer[0],"%d",(int)arcn->sb.st_atime); + /* 3 chars + strlen("atime") + time + # chars in len */ + len = 3 + 5 + strlen(&time_buffer[0]) + 2; + total_len = emit_extended_header_record(len, total_len, + header_type, "atime", &time_buffer[0]); + memset(time_buffer,0,sizeof(time_buffer)); + sprintf(&time_buffer[0],"%d",(int)arcn->sb.st_mtime); + /* 3 chars + strlen("mtime") + time + # chars in len */ + len = 3 + 5 + strlen(&time_buffer[0]) + 2; + total_len = emit_extended_header_record(len, total_len, + header_type, "mtime", &time_buffer[0]); + } + + /* Check if all fields were deleted: might not need to generate anything */ + if ((total_len==0) && (header_name_requested == NULL)) return (0); + + if (header_type == PAXGTYPE) nglobal_headers++; + /* substitution of fields in header_name */ + header_name = substitute_percent(header_name, arcn->name); + if (strlen(header_name) == sizeof(hd->name)) { /* must account for name just fits in buffer */ + strncpy(hd->name, header_name, sizeof(hd->name)); + } else { + strlcpy(hd->name, header_name, sizeof(hd->name)); + } + + records_size = (u_long)total_len; + if (ul_oct(records_size, hd->size, sizeof(hd->size), term_char)) { + paxwarn(1,"extended header data too long for header type '%c'", header_type); + return(1); + } + + if (ul_oct(pax_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum, sizeof(hd->chksum), term_char)) { + paxwarn(1,"extended header data checksum failed: header type '%c'", header_type); + return(1); + } + + /* write out header */ + if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0) + return(-1); + if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0) + return(-1); + /* write out header data */ + if (total_len > 0) { + if (wr_rdbuf(pax_eh_datablk, total_len) < 0) + return(-1); + if (wr_skip((off_t)(BLKMULT - total_len)) < 0) + return(-1); + /* + printf("data written:\n%s",&pax_eh_datablk[0]); + */ + } + + /* + paxwarn(0,"extended header and data written: header type '%c', #items: %d, %d characters", + header_type, nfields, records_size); + */ + return (0); +} + +/* + * pax_wr() + * write a pax header for the file specified in the ARCHD to the archive + * Have to check for file types that cannot be stored and file names that + * are too long. Be careful of the term (last arg) to ul_oct, we only use + * '\0' for the termination character (this is different than picky tar) + * ASSUMED: space after header in header block is zero filled + * Return: + * 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 + */ + +int +pax_wr(ARCHD *arcn) +{ + HD_USTAR *hd; + char *pt; + char hdblk[sizeof(HD_USTAR)]; + mode_t mode12only; + int term_char=3; /* orignal setting */ + term_char=1; /* To pass conformance tests 274, 301 */ + + /* + * check for those file system types pax cannot store + */ + if (arcn->type == PAX_SCK) { + paxwarn(1, "Pax cannot archive a socket %s", arcn->org_name); + return(1); + } + + /* + * check the length of the linkname + */ + if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || + (arcn->type == PAX_HRG)) && (arcn->ln_nlen > sizeof(hd->linkname))){ + paxwarn(1, "Link name too long for pax %s", arcn->ln_name); + /* + * Conformance: test pax:285 wants error code to be non-zero, and + * test tar:12 wants error code from pax to be 0 + */ + return(1); + } + + /* + * split the path name into prefix and name fields (if needed). if + * pt != arcn->name, the name has to be split + */ + if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) { + paxwarn(1, "File name too long for pax %s", arcn->name); + return(1); + } + + generate_pax_ext_header_and_data(arcn, global_ext_header_inx, &global_ext_header_entry[0], + PAXGTYPE, header_name_g, header_name_g_requested); + generate_pax_ext_header_and_data(arcn, ext_header_inx, &ext_header_entry[0], + PAXXTYPE, header_name_x, header_name_x_requested); + + /* + * zero out the header so we don't have to worry about zero fill below + */ + memset(hdblk, 0, sizeof(hdblk)); + hd = (HD_USTAR *)hdblk; + arcn->pad = 0L; + /* To pass conformance tests 274/301, always set these fields to "zero" */ + ul_oct(0, hd->devmajor, sizeof(hd->devmajor), term_char); + ul_oct(0, hd->devminor, sizeof(hd->devminor), term_char); + + /* + * split the name, or zero out the prefix + */ + if (pt != arcn->name) { + /* + * name was split, pt points at the / where the split is to + * occur, we remove the / and copy the first part to the prefix + */ + *pt = '\0'; + strlcpy(hd->prefix, arcn->name, sizeof(hd->prefix)); + *pt++ = '/'; + } + + /* + * copy the name part. this may be the whole path or the part after + * the prefix + */ + if (strlen(pt) == sizeof(hd->name)) { /* must account for name just fits in buffer */ + strncpy(hd->name, pt, sizeof(hd->name)); + } else { + strlcpy(hd->name, pt, sizeof(hd->name)); + } + + /* + * set the fields in the header that are type dependent + */ + switch (arcn->type) { + case PAX_DIR: + hd->typeflag = DIRTYPE; + if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char)) + goto out; + break; + case PAX_CHR: + case PAX_BLK: + if (arcn->type == PAX_CHR) + hd->typeflag = CHRTYPE; + else + hd->typeflag = BLKTYPE; + if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor, + sizeof(hd->devmajor), term_char) || + ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor, + sizeof(hd->devminor), term_char) || + ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char)) + goto out; + break; + case PAX_FIF: + hd->typeflag = FIFOTYPE; + if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char)) + goto out; + break; + case PAX_SLK: + case PAX_HLK: + case PAX_HRG: + if (arcn->type == PAX_SLK) + hd->typeflag = SYMTYPE; + else + hd->typeflag = LNKTYPE; + if (strlen(arcn->ln_name) == sizeof(hd->linkname)) { /* must account for name just fits in buffer */ + strncpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname)); + } else { + strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname)); + } + if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char)) + goto out; + break; + case PAX_REG: + case PAX_CTG: + default: + /* + * file data with this type, set the padding + */ + if (arcn->type == PAX_CTG) + hd->typeflag = CONTTYPE; + else + hd->typeflag = REGTYPE; + arcn->pad = TAR_PAD(arcn->sb.st_size); +# ifdef LONG_OFF_T + if (ul_oct((u_long)arcn->sb.st_size, hd->size, + sizeof(hd->size), term_char)) { +# else + if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, + sizeof(hd->size), term_char)) { +# endif + paxwarn(1,"File is too long for pax %s",arcn->org_name); + return(1); + } + break; + } + + strncpy(hd->magic, TMAGIC, TMAGLEN); + strncpy(hd->version, TVERSION, TVERSLEN); + + /* + * set the remaining fields. Some versions want all 16 bits of mode + * we better humor them (they really do not meet spec though).... + */ + if (ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), term_char)) { + if (uid_nobody == 0) { + if (uid_name("nobody", &uid_nobody) == -1) + goto out; + } + if (uid_warn != arcn->sb.st_uid) { + uid_warn = arcn->sb.st_uid; + paxwarn(1, + "Pax header field is too small for uid %lu, " + "using nobody", (u_long)arcn->sb.st_uid); + } + if (ul_oct((u_long)uid_nobody, hd->uid, sizeof(hd->uid), term_char)) + goto out; + } + if (ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), term_char)) { + if (gid_nobody == 0) { + if (gid_name("nobody", &gid_nobody) == -1) + goto out; + } + if (gid_warn != arcn->sb.st_gid) { + gid_warn = arcn->sb.st_gid; + paxwarn(1, + "Pax header field is too small for gid %lu, " + "using nobody", (u_long)arcn->sb.st_gid); + } + if (ul_oct((u_long)gid_nobody, hd->gid, sizeof(hd->gid), term_char)) + goto out; + } + /* However, Unix conformance tests do not like MORE than 12 mode bits: + remove all beyond (see definition of stat.st_mode structure) */ + mode12only = ((u_long)arcn->sb.st_mode) & 0x00000fff; + if (ul_oct((u_long)mode12only, hd->mode, sizeof(hd->mode), term_char) || + ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),term_char)) + goto out; + strncpy(hd->uname, name_uid(arcn->sb.st_uid, 0), sizeof(hd->uname)); + strncpy(hd->gname, name_gid(arcn->sb.st_gid, 0), sizeof(hd->gname)); + + /* + * calculate and store the checksum write the header to the archive + * return 0 tells the caller to now write the file data, 1 says no data + * needs to be written + */ + if (ul_oct(pax_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum, + sizeof(hd->chksum), term_char)) + goto out; + if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0) + return(-1); + if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0) + return(-1); + if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG)) + return(0); + return(1); + + out: + /* + * header field is out of range + */ + paxwarn(1, "Pax header field is too small for %s", arcn->org_name); + return(1); +} + +#if 0 +/* + * name_split() + * see if the name has to be split for storage in a ustar header. We try + * to fit the entire name in the name field without splitting if we can. + * The split point is always at a / + * Return + * character pointer to split point (always the / that is to be removed + * if the split is not needed, the points is set to the start of the file + * name (it would violate the spec to split there). A NULL is returned if + * the file name is too long + */ + +static char * +name_split(char *name, int len) +{ + char *start; + + /* + * check to see if the file name is small enough to fit in the name + * field. if so just return a pointer to the name. + */ + if (len <= TNMSZ) + return(name); + if (len > (TPFSZ + TNMSZ)) + return(NULL); + + /* + * we start looking at the biggest sized piece that fits in the name + * field. We walk forward looking for a slash to split at. The idea is + * to find the biggest piece to fit in the name field (or the smallest + * prefix we can find) + */ + start = name + len - TNMSZ -1; + while ((*start != '\0') && (*start != '/')) + ++start; + + /* + * if we hit the end of the string, this name cannot be split, so we + * cannot store this file. + */ + if (*start == '\0') + return(NULL); + len = start - name; + + /* + * NOTE: /str where the length of str == TNMSZ can not be stored under + * the p1003.1-1990 spec for ustar. We could force a prefix of / and + * the file would then expand on extract to //str. The len == 0 below + * makes this special case follow the spec to the letter. + */ + if ((len >= TPFSZ) || (len == 0)) + return(NULL); + + /* + * ok have a split point, return it to the caller + */ + return(start); +} +#endif /* if 0 */ + +static size_t +expandname(char *buf, size_t len, char **gnu_name, const char *name, size_t name_len) +{ + size_t nlen; + + if (*gnu_name) { + if ((nlen = strlcpy(buf, *gnu_name, len)) >= len) + nlen = len - 1; + free(*gnu_name); + *gnu_name = NULL; + } else { + if (name_len < len) { + /* name may not be null terminated: it might be as big as the + field, so copy is limited to the max size of the header field */ + if ((nlen = strlcpy(buf, name, name_len+1)) >= name_len+1) + nlen = name_len; + } else { + if ((nlen = strlcpy(buf, name, len)) >= len) + nlen = len - 1; + } + } + return(nlen); +} diff --git a/pax/sel_subs.c b/pax/sel_subs.c index a4e1c22..86ba9ed 100644 --- a/pax/sel_subs.c +++ b/pax/sel_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sel_subs.c,v 1.7 1997/08/17 23:05:09 millert Exp $ */ +/* $OpenBSD: sel_subs.c,v 1.18 2004/04/16 22:50:23 deraadt Exp $ */ /* $NetBSD: sel_subs.c,v 1.5 1995/03/21 09:07:42 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)sel_subs.c 8.1 (Berkeley) 5/31/93"; +static const char sccsid[] = "@(#)sel_subs.c 8.1 (Berkeley) 5/31/93"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: sel_subs.c,v 1.7 1997/08/17 23:05:09 millert Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: sel_subs.c,v 1.18 2004/04/16 22:50:23 deraadt Exp $"; #endif #endif /* not lint */ @@ -50,20 +46,22 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: sel_subs.c,v 1.7 19 #include #include #include -#include +#include #include +#include #include +#include #include +#include #include -#include #include "pax.h" #include "sel_subs.h" #include "extern.h" -static int str_sec __P((register char *, time_t *)); -static int usr_match __P((register ARCHD *)); -static int grp_match __P((register ARCHD *)); -static int trng_match __P((register ARCHD *)); +static int str_sec(const char *, time_t *); +static int usr_match(ARCHD *); +static int grp_match(ARCHD *); +static int trng_match(ARCHD *); static TIME_RNG *trhead = NULL; /* time range list head */ static TIME_RNG *trtail = NULL; /* time range list tail */ @@ -76,19 +74,13 @@ static GRPT **grptb = NULL; /* group selection table */ /* * sel_chk() - * check if this file matches a specfied uid, gid or time range + * check if this file matches a specified uid, gid or time range * Return: * 0 if this archive member should be processed, 1 if it should be skipped */ -#ifdef __STDC__ int -sel_chk(register ARCHD *arcn) -#else -int -sel_chk(arcn) - register ARCHD *arcn; -#endif +sel_chk(ARCHD *arcn) { if (((usrtb != NULL) && usr_match(arcn)) || ((grptb != NULL) && grp_match(arcn)) || @@ -101,8 +93,8 @@ sel_chk(arcn) * 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 - * a # on the command line. A \# will eascape the #. + * add an entry, the user supplies either the name or the uid/gid starting with + * a # on the command line. A \# will escape the #. */ /* @@ -112,19 +104,13 @@ sel_chk(arcn) * 0 if added ok, -1 otherwise; */ -#ifdef __STDC__ int -usr_add(register char *str) -#else -int -usr_add(str) - register char *str; -#endif +usr_add(char *str) { - register u_int indx; - register USRT *pt; - register struct passwd *pw; - register uid_t uid; + u_int indx; + USRT *pt; + struct passwd *pw; + uid_t uid; /* * create the table if it doesn't exist @@ -152,11 +138,7 @@ usr_add(str) } 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(); /* @@ -191,16 +173,10 @@ usr_add(str) * 0 if this archive member should be processed, 1 if it should be skipped */ -#ifdef __STDC__ static int -usr_match(register ARCHD *arcn) -#else -static int -usr_match(arcn) - register ARCHD *arcn; -#endif +usr_match(ARCHD *arcn) { - register USRT *pt; + USRT *pt; /* * hash and look for it in the table @@ -225,19 +201,13 @@ usr_match(arcn) * 0 if added ok, -1 otherwise; */ -#ifdef __STDC__ int -grp_add(register char *str) -#else -int -grp_add(str) - register char *str; -#endif +grp_add(char *str) { - register u_int indx; - register GRPT *pt; - register struct group *gr; - register gid_t gid; + u_int indx; + GRPT *pt; + struct group *gr; + gid_t gid; /* * create the table if it doesn't exist @@ -265,11 +235,7 @@ grp_add(str) } 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(); /* @@ -304,16 +270,10 @@ grp_add(str) * 0 if this archive member should be processed, 1 if it should be skipped */ -#ifdef __STDC__ -static int -grp_match(register ARCHD *arcn) -#else static int -grp_match(arcn) - register ARCHD *arcn; -#endif +grp_match(ARCHD *arcn) { - register GRPT *pt; + GRPT *pt; /* * hash and look for it in the table @@ -353,27 +313,21 @@ grp_match(arcn) * trng_add() * add a time range match to the time range list. * This is a non-standard pax option. Lower and upper ranges are in the - * format: [yy[mm[dd[hh]]]]mm[.ss] and are comma separated. + * format: [[[[[cc]yy]mm]dd]HH]MM[.SS] and are comma separated. * Time ranges are based on current time, so 1234 would specify a time of * 12:34 today. * Return: * 0 if the time range was added to the list, -1 otherwise */ -#ifdef __STDC__ -int -trng_add(register char *str) -#else int -trng_add(str) - register char *str; -#endif +trng_add(char *str) { - register TIME_RNG *pt; - register char *up_pt = NULL; - register char *stpt; - register char *flgpt; - register int dot = 0; + TIME_RNG *pt; + char *up_pt = NULL; + char *stpt; + char *flgpt; + int dot = 0; /* * throw out the badly formed time ranges @@ -419,7 +373,7 @@ trng_add(str) } /* - * 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')) @@ -427,7 +381,7 @@ trng_add(str) else { pt->flgs = 0; while (*flgpt != '\0') { - switch(*flgpt) { + switch (*flgpt) { case 'M': case 'm': pt->flgs |= CMPMTME; @@ -495,7 +449,7 @@ trng_add(str) return(0); out: - paxwarn(1, "Time range format is: [yy[mm[dd[hh]]]]mm[.ss][/[c][m]]"); + paxwarn(1, "Time range format is: [[[[[cc]yy]mm]dd]HH]MM[.SS][/[c][m]]"); return(-1); } @@ -506,16 +460,10 @@ trng_add(str) * 0 if this archive member should be processed, 1 if it should be skipped */ -#ifdef __STDC__ -static int -trng_match(register ARCHD *arcn) -#else static int -trng_match(arcn) - register ARCHD *arcn; -#endif +trng_match(ARCHD *arcn) { - register TIME_RNG *pt; + TIME_RNG *pt; /* * have to search down the list one at a time looking for a match. @@ -523,7 +471,7 @@ trng_match(arcn) */ pt = trhead; while (pt != NULL) { - switch(pt->flgs & CMPBOTH) { + switch (pt->flgs & CMPBOTH) { case CMPBOTH: /* * user wants both mtime and ctime checked for this @@ -575,87 +523,89 @@ trng_match(arcn) /* * str_sec() - * Convert a time string in the format of [yy[mm[dd[hh]]]]mm[.ss] to gmt - * seconds. Tval already has current time loaded into it at entry. + * Convert a time string in the format of [[[[[cc]yy]mm]dd]HH]MM[.SS] to + * seconds UTC. Tval already has current time loaded into it at entry. * Return: * 0 if converted ok, -1 otherwise */ -#ifdef __STDC__ -static int -str_sec(register char *str, time_t *tval) -#else static int -str_sec(str, tval) - register char *str; - time_t *tval; -#endif +str_sec(const char *p, time_t *tval) { - register struct tm *lt; - register char *dot = NULL; + struct tm *lt; + const char *dot, *t; + size_t len; + int bigyear; + int yearset; + + yearset = 0; + len = strlen(p); + + for (t = p, dot = NULL; *t; ++t) { + if (isdigit(*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) + + if (dot != NULL) { /* .SS */ + if (strlen(++dot) != 2) return(-1); - if ((lt->tm_sec = ATOI2(dot)) > 61) + lt->tm_sec = ATOI2(dot); + if (lt->tm_sec > 61) return(-1); + len -= 3; } else lt->tm_sec = 0; - switch (strlen(str)) { - case 10: - /* - * year (yy) - * watch out for year 2000 - */ - if ((lt->tm_year = ATOI2(str)) < 69) - lt->tm_year += 100; - str += 2; + switch (len) { + case 12: /* cc */ + bigyear = ATOI2(p); + lt->tm_year = (bigyear * 100) - TM_YEAR_BASE; + yearset = 1; /* FALLTHROUGH */ - case 8: - /* - * month (mm) - * watch out months are from 0 - 11 internally - */ - if ((lt->tm_mon = ATOI2(str)) > 12) + case 10: /* yy */ + if (yearset) { + lt->tm_year += ATOI2(p); + } else { + lt->tm_year = ATOI2(p); + if (lt->tm_year < 69) /* hack for 2000 ;-} */ + lt->tm_year += (2000 - TM_YEAR_BASE); + else + lt->tm_year += (1900 - TM_YEAR_BASE); + } + /* FALLTHROUGH */ + case 8: /* mm */ + lt->tm_mon = ATOI2(p); + if ((lt->tm_mon > 12) || !lt->tm_mon) return(-1); - --lt->tm_mon; - str += 2; + --lt->tm_mon; /* time struct is 0 - 11 */ /* FALLTHROUGH */ - case 6: - /* - * day (dd) - */ - if ((lt->tm_mday = ATOI2(str)) > 31) + case 6: /* dd */ + lt->tm_mday = ATOI2(p); + if ((lt->tm_mday > 31) || !lt->tm_mday) return(-1); - str += 2; /* FALLTHROUGH */ - case 4: - /* - * hour (hh) - */ - if ((lt->tm_hour = ATOI2(str)) > 23) + case 4: /* HH */ + lt->tm_hour = ATOI2(p); + if (lt->tm_hour > 23) return(-1); - str += 2; /* FALLTHROUGH */ - case 2: - /* - * minute (mm) - */ - if ((lt->tm_min = ATOI2(str)) > 59) + case 2: /* MM */ + lt->tm_min = ATOI2(p); + if (lt->tm_min > 59) return(-1); break; default: return(-1); } - /* - * convert broken-down time to GMT clock time seconds - */ + + /* convert broken-down time to UTC clock time seconds */ if ((*tval = mktime(lt)) == -1) return(-1); return(0); diff --git a/pax/sel_subs.h b/pax/sel_subs.h index fc86e9d..b699ee8 100644 --- a/pax/sel_subs.h +++ b/pax/sel_subs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sel_subs.h,v 1.2 1996/06/23 14:20:41 deraadt Exp $ */ +/* $OpenBSD: sel_subs.h,v 1.4 2003/06/02 23:32:09 millert Exp $ */ /* $NetBSD: sel_subs.h,v 1.3 1995/03/21 09:07:44 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -61,7 +57,7 @@ typedef struct grpt { * data structure for storing user supplied time ranges (-T option) */ -#define ATOI2(s) ((((s)[0] - '0') * 10) + ((s)[1] - '0')) +#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; typedef struct time_rng { time_t low_time; /* lower inclusive time limit */ diff --git a/pax/tables.c b/pax/tables.c index a0a964e..6b067e8 100644 --- a/pax/tables.c +++ b/pax/tables.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tables.c,v 1.9 1997/09/01 18:30:00 deraadt Exp $ */ +/* $OpenBSD: tables.c,v 1.22 2004/11/29 16:23:22 otto Exp $ */ /* $NetBSD: tables.c,v 1.4 1995/03/21 09:07:45 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 5/31/93"; +static const char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 5/31/93"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tables.c,v 1.9 1997/09/01 18:30:00 deraadt Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tables.c,v 1.22 2004/11/29 16:23:22 otto Exp $"; #endif #endif /* not lint */ @@ -71,7 +67,7 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tables.c,v 1.9 1997 * 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. */ @@ -80,11 +76,12 @@ 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 */ -static int dirfd = -1; /* storage for setting created dir time/mode */ -static u_long dircnt; /* entries in dir time/mode storage */ +static DIRDATA *dirp = NULL; /* storage for setting created dir time/mode */ +static size_t dirsize; /* size of dirp table */ +static long dircnt = 0; /* entries in dir time/mode storage */ static int ffd = -1; /* tmp file for file time table name storage */ -static DEVT *chk_dev __P((dev_t, int)); +static DEVT *chk_dev(dev_t, int); /* * hard link table routines @@ -109,13 +106,8 @@ static DEVT *chk_dev __P((dev_t, int)); * 0 if created, -1 if failure */ -#ifdef __STDC__ int lnk_start(void) -#else -int -lnk_start() -#endif { if (ltab != NULL) return(0); @@ -138,18 +130,12 @@ lnk_start() * if found returns 1; if not found returns 0; -1 on error */ -#ifdef __STDC__ int -chk_lnk(register ARCHD *arcn) -#else -int -chk_lnk(arcn) - register ARCHD *arcn; -#endif +chk_lnk(ARCHD *arcn) { - register HRDLNK *pt; - register HRDLNK **ppt; - register u_int indx; + HRDLNK *pt; + HRDLNK **ppt; + u_int indx; if (ltab == NULL) return(-1); @@ -160,6 +146,12 @@ chk_lnk(arcn) return(0); /* + * Conformance tests: ignore symlink because cannot create hard link to it + */ + if ((arcn->type == PAX_SLK)) + return(0); + + /* * hash inode number and look for this file */ indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ; @@ -183,9 +175,8 @@ chk_lnk(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 @@ -231,18 +222,12 @@ chk_lnk(arcn) * we do not want to accidently point another file at it later on. */ -#ifdef __STDC__ -void -purg_lnk(register ARCHD *arcn) -#else void -purg_lnk(arcn) - register ARCHD *arcn; -#endif +purg_lnk(ARCHD *arcn) { - register HRDLNK *pt; - register HRDLNK **ppt; - register u_int indx; + HRDLNK *pt; + HRDLNK **ppt; + u_int indx; if (ltab == NULL) return; @@ -291,17 +276,12 @@ purg_lnk(arcn) * write phase */ -#ifdef __STDC__ void lnk_end(void) -#else -void -lnk_end() -#endif { - register int i; - register HRDLNK *pt; - register HRDLNK *ppt; + int i; + HRDLNK *pt; + HRDLNK *ppt; if (ltab == NULL) return; @@ -336,14 +316,14 @@ lnk_end() * 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 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 + * 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 scratch file space available to store the * path names. */ @@ -356,15 +336,9 @@ lnk_end() * 0 if the table and file was created ok, -1 otherwise */ -#ifdef __STDC__ int ftime_start(void) -#else -int -ftime_start() -#endif { - char *pt; if (ftab != NULL) return(0); @@ -377,14 +351,13 @@ ftime_start() * get random name and create temporary scratch file, unlink name * so it will get removed on exit */ - pt = strdup("/tmp/paxXXXXXX"); - if ((ffd = mkstemp(pt)) < 0) { - syswarn(1, errno, "Unable to create temporary file: %s", pt); - free(pt); + memcpy(tempbase, _TFILE_BASE, sizeof(_TFILE_BASE)); + if ((ffd = mkstemp(tempfile)) < 0) { + syswarn(1, errno, "Unable to create temporary file: %s", + tempfile); return(-1); } - (void)unlink(pt); - free(pt); + (void)unlink(tempfile); return(0); } @@ -401,18 +374,12 @@ ftime_start() * -1 on error */ -#ifdef __STDC__ -int -chk_ftime(register ARCHD *arcn) -#else int -chk_ftime(arcn) - register ARCHD *arcn; -#endif +chk_ftime(ARCHD *arcn) { - register FTM *pt; - register int namelen; - register u_int indx; + FTM *pt; + int namelen; + u_int indx; char ckname[PAXPATHLEN+1]; /* @@ -511,7 +478,7 @@ chk_ftime(arcn) * Interactive rename table routines * * The interactive rename table keeps track of the new names that the user - * assignes to files from tty input. Since this map is unique for each file + * assigns to files from tty input. Since this map is unique for each file * we must store it in case there is a reference to the file later in archive * (a link). Otherwise we will be unable to find the file we know was * extracted. The remapping of these files is stored in a memory based hash @@ -526,13 +493,8 @@ chk_ftime(arcn) * 0 if successful, -1 otherwise */ -#ifdef __STDC__ int name_start(void) -#else -int -name_start() -#endif { if (ntab != NULL) return(0); @@ -552,25 +514,17 @@ name_start() * 0 if added, -1 otherwise */ -#ifdef __STDC__ -int -add_name(register char *oname, int onamelen, char *nname) -#else int -add_name(oname, onamelen, nname) - register char *oname; - int onamelen; - char *nname; -#endif +add_name(char *oname, int onamelen, char *nname) { - register NAMT *pt; - register u_int indx; + NAMT *pt; + u_int indx; if (ntab == NULL) { /* * should never happen */ - paxwarn(0, "No interactive rename table, links may fail\n"); + paxwarn(0, "No interactive rename table, links may fail"); return(0); } @@ -628,19 +582,11 @@ add_name(oname, onamelen, nname) * new name (oname is the link to name) */ -#ifdef __STDC__ -void -sub_name(register char *oname, int *onamelen, size_t onamesize) -#else void -sub_name(oname, onamelen, onamesize) - register char *oname; - int *onamelen; - size_t onamesize; -#endif +sub_name(char *oname, int *onamelen, size_t onamesize) { - register NAMT *pt; - register u_int indx; + NAMT *pt; + u_int indx; if (ntab == NULL) return; @@ -660,8 +606,7 @@ sub_name(oname, onamelen, 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; @@ -720,13 +665,8 @@ sub_name(oname, onamelen, onamesize) * 0 if successful, -1 otherwise */ -#ifdef __STDC__ int dev_start(void) -#else -int -dev_start() -#endif { if (dtab != NULL) return(0); @@ -747,14 +687,8 @@ dev_start() * 0 if added ok, -1 otherwise */ -#ifdef __STDC__ -int -add_dev(register ARCHD *arcn) -#else int -add_dev(arcn) - register ARCHD *arcn; -#endif +add_dev(ARCHD *arcn) { if (chk_dev(arcn->sb.st_dev, 1) == NULL) return(-1); @@ -766,7 +700,7 @@ add_dev(arcn) * check for a device value in the device table. If not found and the add * flag is set, it is added. This does NOT assign any mapping values, just * adds the device number as one that need to be remapped. If this device - * is alread mapped, just return with a pointer to that entry. + * is already mapped, just return with a pointer to that entry. * Return: * pointer to the entry for this device in the device map table. Null * if the add flag is not set and the device is not in the table (it is @@ -774,18 +708,11 @@ add_dev(arcn) * is returned (indicates an error). */ -#ifdef __STDC__ static DEVT * chk_dev(dev_t dev, int add) -#else -static DEVT * -chk_dev(dev, add) - dev_t dev; - int add; -#endif { - register DEVT *pt; - register u_int indx; + DEVT *pt; + u_int indx; if (dtab == NULL) return(NULL); @@ -839,19 +766,11 @@ chk_dev(dev, add) * 0 if all ok, -1 otherwise. */ -#ifdef __STDC__ -int -map_dev(register ARCHD *arcn, u_long dev_mask, u_long ino_mask) -#else int -map_dev(arcn, dev_mask, ino_mask) - register ARCHD *arcn; - u_long dev_mask; - u_long ino_mask; -#endif +map_dev(ARCHD *arcn, u_long dev_mask, u_long ino_mask) { - register DEVT *pt; - register DLIST *dpt; + DEVT *pt; + DLIST *dpt; static dev_t lastdev = 0; /* next device number to try */ int trc_ino = 0; int trc_dev = 0; @@ -968,14 +887,14 @@ map_dev(arcn, dev_mask, ino_mask) /* * 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 + * The pax -t flag requires that access times of archive files be the same * 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 * all the descendants in their subtree are visited by fts. Directory access * and modification times are stored during the fts pre-order visit (done - * before any descendants in the subtree is visited) and restored after the + * before any descendants in the subtree are visited) and restored after the * fts post-order visit (after all the descendants have been visited). In the * case of premature exit from a subtree (like from the effects of -n), any * directory entries left in this database are reset during final cleanup @@ -989,13 +908,8 @@ map_dev(arcn, dev_mask, ino_mask) * 0 is created ok, -1 otherwise. */ -#ifdef __STDC__ int atdir_start(void) -#else -int -atdir_start() -#endif { if (atab != NULL) return(0); @@ -1014,16 +928,11 @@ atdir_start() * entries are for directories READ by pax */ -#ifdef __STDC__ void atdir_end(void) -#else -void -atdir_end() -#endif { - register ATDIR *pt; - register int i; + ATDIR *pt; + int i; if (atab == NULL) return; @@ -1050,21 +959,11 @@ atdir_end() * and chained by inode number. This is for directories READ by pax */ -#ifdef __STDC__ void add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime) -#else -void -add_atdir(fname, dev, ino, mtime, atime) - char *fname; - dev_t dev; - ino_t ino; - time_t mtime; - time_t atime; -#endif { - register ATDIR *pt; - register u_int indx; + ATDIR *pt; + u_int indx; if (atab == NULL) return; @@ -1074,7 +973,7 @@ add_atdir(fname, dev, ino, mtime, 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) { @@ -1122,21 +1021,12 @@ add_atdir(fname, dev, ino, mtime, atime) * 0 if found, -1 if not found. */ -#ifdef __STDC__ int get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) -#else -int -get_atdir(dev, ino, mtime, atime) - dev_t dev; - ino_t ino; - time_t *mtime; - time_t *atime; -#endif { - register ATDIR *pt; - register ATDIR **ppt; - register u_int indx; + ATDIR *pt; + ATDIR **ppt; + u_int indx; if (atab == NULL) return(-1); @@ -1206,31 +1096,18 @@ get_atdir(dev, ino, mtime, atime) * 0 if ok, -1 otherwise */ -#ifdef __STDC__ int dir_start(void) -#else -int -dir_start() -#endif { - char *pt; - - if (dirfd != -1) + if (dirp != NULL) return(0); - /* - * unlink the file so it goes away at termination by itself - */ - pt = strdup("/tmp/paxXXXXXX"); - if ((dirfd = mkstemp(pt)) >= 0) { - (void)unlink(pt); - free(pt); - return(0); + dirsize = DIRP_SIZE; + if ((dirp = malloc(dirsize * sizeof(DIRDATA))) == NULL) { + paxwarn(1, "Unable to allocate memory for directory times"); + return(-1); } - paxwarn(1, "Unable to create temporary file for directory times: %s", pt); - free(pt); - return(-1); + return(0); } /* @@ -1246,48 +1123,35 @@ dir_start() * pax spec) */ -#ifdef __STDC__ -void -add_dir(char *name, int nlen, struct stat *psb, int frc_mode) -#else void -add_dir(name, nlen, psb, frc_mode) - char *name; - int nlen; - struct stat *psb; - int frc_mode; -#endif +add_dir(char *name, struct stat *psb, int frc_mode) { - DIRDATA dblk; + DIRDATA *dblk; - if (dirfd < 0) + if (dirp == NULL) return; - /* - * get current position (where file name will start) so we can store it - * in the trailer - */ - if ((dblk.npos = lseek(dirfd, 0L, SEEK_CUR)) < 0) { - paxwarn(1,"Unable to store mode and times for directory: %s",name); - return; + if (dircnt == dirsize) { + dblk = realloc(dirp, 2 * dirsize * sizeof(DIRDATA)); + if (dblk == NULL) { + paxwarn(1, "Unable to store mode and times for created" + " directory: %s", name); + return; + } + dirp = dblk; + dirsize *= 2; } - - /* - * write the file name followed by the trailer - */ - dblk.nlen = nlen + 1; - dblk.mode = psb->st_mode & 0xffff; - dblk.mtime = psb->st_mtime; - dblk.atime = psb->st_atime; - dblk.frc_mode = frc_mode; - if ((write(dirfd, name, dblk.nlen) == dblk.nlen) && - (write(dirfd, (char *)&dblk, sizeof(dblk)) == sizeof(dblk))) { - ++dircnt; + dblk = &dirp[dircnt]; + if ((dblk->name = strdup(name)) == NULL) { + paxwarn(1, "Unable to store mode and times for created" + " directory: %s", name); return; } - - paxwarn(1,"Unable to store mode and times for created directory: %s",name); - return; + dblk->mode = psb->st_mode & 0xffff; + dblk->mtime = psb->st_mtime; + dblk->atime = psb->st_atime; + dblk->frc_mode = frc_mode; + ++dircnt; } /* @@ -1296,54 +1160,34 @@ add_dir(name, nlen, psb, frc_mode) * by pax */ -#ifdef __STDC__ void proc_dir(void) -#else -void -proc_dir() -#endif { - char name[PAXPATHLEN+1]; - DIRDATA dblk; - u_long cnt; + DIRDATA *dblk; + long cnt; - if (dirfd < 0) + if (dirp == NULL) return; /* * read backwards through the file and process each directory */ - for (cnt = 0; cnt < dircnt; ++cnt) { - /* - * read the trailer, then the file name, if this fails - * just give up. - */ - if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0) - break; - if (read(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) - break; - if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) - break; - + cnt = dircnt; + while (--cnt >= 0) { /* * 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(name, dblk.mode); + dblk = &dirp[cnt]; + if (pmode || dblk->frc_mode) + set_pmode(dblk->name, dblk->mode); if (patime || pmtime) - set_ftime(name, dblk.mtime, dblk.atime, 0); + set_ftime(dblk->name, dblk->mtime, dblk->atime, 0); + free(dblk->name); } - (void)close(dirfd); - dirfd = -1; - if (cnt != dircnt) - paxwarn(1,"Unable to set mode and times for created directories"); - return; + free(dirp); + dirp = NULL; + dircnt = 0; } /* @@ -1364,24 +1208,16 @@ proc_dir() * the hash value of the string MOD (%) the table size. */ -#ifdef __STDC__ u_int st_hash(char *name, int len, int tabsz) -#else -u_int -st_hash(name, len, tabsz) - char *name; - int len; - int tabsz; -#endif { - register char *pt; - register char *dest; - register char *end; - register int i; - register u_int key = 0; - register int steps; - register int res; + char *pt; + char *dest; + char *end; + int i; + u_int key = 0; + int steps; + int res; u_int val; /* diff --git a/pax/tables.h b/pax/tables.h index 1d9c813..e065387 100644 --- a/pax/tables.h +++ b/pax/tables.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tables.h,v 1.2 1996/06/23 14:20:43 deraadt Exp $ */ +/* $OpenBSD: tables.h,v 1.7 2004/11/29 16:23:22 otto Exp $ */ /* $NetBSD: tables.h,v 1.3 1995/03/21 09:07:47 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -47,7 +43,7 @@ /* * Hash Table Sizes MUST BE PRIME, if set too small performance suffers. * Probably safe to expect 500000 inodes per tape. Assuming good key - * distribution (inodes) chains of under 50 long (worse case) is ok. + * distribution (inodes) chains of under 50 long (worst case) is ok. */ #define L_TAB_SZ 2503 /* hard link hash table size */ #define F_TAB_SZ 50503 /* file time hash table size */ @@ -55,6 +51,7 @@ #define D_TAB_SZ 317 /* unique device mapping table */ #define A_TAB_SZ 317 /* ftree dir access time reset table */ #define MAXKEYLEN 64 /* max number of chars for hash */ +#define DIRP_SIZE 64 /* initial size of created dir table */ /* * file hard link structure (hashed by dev/ino and chained) used to find the @@ -82,7 +79,7 @@ typedef struct hrdlnk { typedef struct ftm { int namelen; /* file name length */ time_t mtime; /* files last modification time */ - off_t seek; /* loacation in scratch file */ + off_t seek; /* location in scratch file */ struct ftm *fow; } FTM; @@ -108,7 +105,7 @@ typedef struct namt { * this table. (When the inode field in the archive header are too small, we * remap the dev on writes to remove accidental collisions). * - * The list is hashed by device number using chain collision resolution. Off of + * The list is hashed by device number using chain collision resolution. Off of * each DEVT are linked the various remaps for this device based on those bits * in the inode which were truncated. For example if we are just remapping to * avoid a device number during an update append, off the DEVT we would have @@ -161,15 +158,13 @@ typedef struct atdir { * times and/or modes). We must reset time in the reverse order of creation, * because entries are added from the top of the file tree to the bottom. * We MUST reset times from leaf to root (it will not work the other - * direction). Entries are recorded into a spool file to make reverse - * reading faster. + * direction). */ typedef struct dirdata { - int nlen; /* length of the directory name (includes \0) */ - off_t npos; /* position in file where this dir name starts */ - mode_t mode; /* file mode to restore */ + char *name; /* file name */ time_t mtime; /* mtime to set */ time_t atime; /* atime to set */ - int frc_mode; /* do we force mode settings? */ + u_int16_t mode; /* file mode to restore */ + u_int16_t frc_mode; /* do we force mode settings? */ } DIRDATA; diff --git a/pax/tar.c b/pax/tar.c index 11ec097..b8f9b42 100644 --- a/pax/tar.c +++ b/pax/tar.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tar.c,v 1.12 1997/09/01 18:30:03 deraadt Exp $ */ +/* $OpenBSD: tar.c,v 1.34 2004/10/23 19:34:14 otto Exp $ */ /* $NetBSD: tar.c,v 1.5 1995/03/21 09:07:49 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94"; +static const char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tar.c,v 1.12 1997/09/01 18:30:03 deraadt Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tar.c,v 1.34 2004/10/23 19:34:14 otto Exp $"; #endif #endif /* not lint */ @@ -62,18 +58,26 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tar.c,v 1.12 1997/0 * Routines for reading, writing and header identify of various versions of tar */ -static u_long tar_chksm __P((register char *, register int)); -static char *name_split __P((register char *, register int)); -static int ul_oct __P((u_long, register char *, register int, int)); -#ifndef NET2_STAT -static int uqd_oct __P((u_quad_t, register char *, register int, int)); +static size_t expandname(char *, size_t, char **, const char *, size_t); +static u_long tar_chksm(char *, int); +char *name_split(char *, int); +static int ul_oct(u_long, char *, int, int); +#ifndef LONG_OFF_T +static int uqd_oct(u_quad_t, char *, int, int); #endif +static uid_t uid_nobody; +static uid_t uid_warn; +static gid_t gid_nobody; +static gid_t gid_warn; + /* * Routines common to all versions of tar */ static int tar_nodir; /* do not write dirs under old tar */ +char *gnu_name_string; /* GNU ././@LongLink hackery name */ +char *gnu_link_string; /* GNU ././@LongLink hackery link */ /* * tar_endwr() @@ -82,13 +86,8 @@ static int tar_nodir; /* do not write dirs under old tar */ * 0 if ok, -1 otherwise (what wr_skip returns) */ -#ifdef __STDC__ int tar_endwr(void) -#else -int -tar_endwr() -#endif { return(wr_skip((off_t)(NULLCNT*BLKMULT))); } @@ -100,13 +99,8 @@ tar_endwr() * size of trailer (2 * BLKMULT) */ -#ifdef __STDC__ off_t tar_endrd(void) -#else -off_t -tar_endrd() -#endif { return((off_t)(NULLCNT*BLKMULT)); } @@ -122,18 +116,10 @@ tar_endrd() * could never contain a header. */ -#ifdef __STDC__ int -tar_trail(register char *buf, register int in_resync, register int *cnt) -#else -int -tar_trail(buf, in_resync, cnt) - register char *buf; - register int in_resync; - register int *cnt; -#endif +tar_trail(ARCHD *ignore, char *buf, int in_resync, int *cnt) { - register int i; + int i; /* * look for all zero, trailer is two consecutive blocks of zero @@ -173,25 +159,16 @@ tar_trail(buf, in_resync, cnt) * 0 if the number fit into the string, -1 otherwise */ -#ifdef __STDC__ static int -ul_oct(u_long val, register char *str, register int len, int term) -#else -static int -ul_oct(val, str, len, term) - u_long val; - register char *str; - register int len; - int term; -#endif +ul_oct(u_long val, char *str, int len, int term) { - register char *pt; + char *pt; /* * term selects the appropriate character(s) for the end of the string */ pt = str + len - 1; - switch(term) { + switch (term) { case 3: *pt-- = '\0'; break; @@ -225,7 +202,7 @@ ul_oct(val, str, len, term) return(0); } -#ifndef NET2_STAT +#ifndef LONG_OFF_T /* * uqd_oct() * convert an u_quad_t to an octal string. one of many oddball field @@ -237,25 +214,16 @@ ul_oct(val, str, len, term) * 0 if the number fit into the string, -1 otherwise */ -#ifdef __STDC__ static int -uqd_oct(u_quad_t val, register char *str, register int len, int term) -#else -static int -uqd_oct(val, str, len, term) - u_quad_t val; - register char *str; - register int len; - int term; -#endif +uqd_oct(u_quad_t val, char *str, int len, int term) { - register char *pt; + char *pt; /* * term selects the appropriate character(s) for the end of the string */ pt = str + len - 1; - switch(term) { + switch (term) { case 3: *pt-- = '\0'; break; @@ -293,26 +261,19 @@ uqd_oct(val, str, len, term) /* * tar_chksm() * calculate the checksum for a tar block counting the checksum field as - * all blanks (BLNKSUM is that value pre-calculated, the sume of 8 blanks). + * all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks). * NOTE: we use len to short circuit summing 0's on write since we ALWAYS * pad headers with 0. * Return: * unsigned long checksum */ -#ifdef __STDC__ static u_long -tar_chksm(register char *blk, register int len) -#else -static u_long -tar_chksm(blk, len) - register char *blk; - register int len; -#endif +tar_chksm(char *blk, int len) { - register char *stop; - register char *pt; - u_long chksm = BLNKSUM; /* inital value is checksum field sum */ + char *stop; + char *pt; + u_long chksm = BLNKSUM; /* initial value is checksum field sum */ /* * add the part of the block before the checksum field @@ -348,18 +309,11 @@ tar_chksm(blk, len) * 0 if a tar header, -1 otherwise */ -#ifdef __STDC__ int -tar_id(register char *blk, int size) -#else -int -tar_id(blk, size) - register char *blk; - int size; -#endif +tar_id(char *blk, int size) { - register HD_TAR *hd; - register HD_USTAR *uhd; + HD_TAR *hd; + HD_USTAR *uhd; if (size < BLKMULT) return(-1); @@ -379,6 +333,7 @@ tar_id(blk, size) return(-1); if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT)) return(-1); + force_one_volume = 1; return(0); } @@ -389,13 +344,8 @@ tar_id(blk, size) * 0 if ok -1 otherwise */ -#ifdef __STDC__ int tar_opt(void) -#else -int -tar_opt() -#endif { OPLIST *opt; @@ -431,39 +381,40 @@ tar_opt() * 0 */ -#ifdef __STDC__ int -tar_rd(register ARCHD *arcn, register char *buf) -#else -int -tar_rd(arcn, buf) - register ARCHD *arcn; - register char *buf; -#endif +tar_rd(ARCHD *arcn, char *buf) { - register HD_TAR *hd; - register char *pt; + HD_TAR *hd; + char *pt; /* * we only get proper sized buffers passed to us */ if (tar_id(buf, BLKMULT) < 0) return(-1); + memset(arcn, 0, sizeof(*arcn)); arcn->org_name = arcn->name; arcn->sb.st_nlink = 1; - arcn->pat = NULL; /* * copy out the name and values in the stat buffer */ hd = (HD_TAR *)buf; - arcn->nlen = l_strncpy(arcn->name, hd->name, sizeof(arcn->name) - 1); - arcn->name[arcn->nlen] = '\0'; + if (hd->linkflag != LONGLINKTYPE && hd->linkflag != LONGNAMETYPE) { + arcn->nlen = expandname(arcn->name, sizeof(arcn->name), + &gnu_name_string, hd->name, sizeof(hd->name)); + arcn->ln_nlen = expandname(arcn->ln_name, sizeof(arcn->ln_name), + &gnu_link_string, hd->linkname, sizeof(hd->linkname)); + } arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) & 0xfff); arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT); arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT); - arcn->sb.st_size = (size_t)asc_ul(hd->size, sizeof(hd->size), OCT); +#ifdef LONG_OFF_T + arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); +#else + arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); +#endif arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; @@ -474,16 +425,13 @@ tar_rd(arcn, buf) pt = &(arcn->name[arcn->nlen - 1]); arcn->pad = 0; arcn->skip = 0; - switch(hd->linkflag) { + switch (hd->linkflag) { case SYMTYPE: /* * symbolic link, need to get the link name and set the type in * the st_mode so -v printing will look correct. */ arcn->type = PAX_SLK; - arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, - sizeof(arcn->ln_name) - 1); - arcn->ln_name[arcn->ln_nlen] = '\0'; arcn->sb.st_mode |= S_IFLNK; break; case LNKTYPE: @@ -493,9 +441,6 @@ tar_rd(arcn, buf) */ arcn->type = PAX_HLK; arcn->sb.st_nlink = 2; - arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, - sizeof(arcn->ln_name) - 1); - arcn->ln_name[arcn->ln_nlen] = '\0'; /* * no idea of what type this thing really points at, but @@ -503,6 +448,17 @@ tar_rd(arcn, buf) */ arcn->sb.st_mode |= S_IFREG; break; + case LONGLINKTYPE: + case LONGNAMETYPE: + /* + * GNU long link/file; we tag these here and let the + * pax internals deal with it -- too ugly otherwise. + */ + arcn->type = + hd->linkflag == LONGLINKTYPE ? PAX_GLL : PAX_GLF; + arcn->pad = TAR_PAD(arcn->sb.st_size); + arcn->skip = arcn->sb.st_size; + break; case DIRTYPE: /* * It is a directory, set the mode for -v printing @@ -510,8 +466,6 @@ tar_rd(arcn, buf) arcn->type = PAX_DIR; arcn->sb.st_mode |= S_IFDIR; arcn->sb.st_nlink = 2; - arcn->ln_name[0] = '\0'; - arcn->ln_nlen = 0; break; case AREGTYPE: case REGTYPE: @@ -531,7 +485,7 @@ tar_rd(arcn, buf) } else { /* * have a file that will be followed by data. Set the - * skip value to the size field and caluculate the size + * skip value to the size field and calculate the size * of the padding. */ arcn->type = PAX_REG; @@ -546,7 +500,7 @@ tar_rd(arcn, buf) * strip off any trailing slash. */ if (*pt == '/') { - *pt = '\0'; + *pt = '\0'; --arcn->nlen; } return(0); @@ -564,23 +518,17 @@ tar_rd(arcn, buf) * data to write after the header, -1 if archive write failed */ -#ifdef __STDC__ -int -tar_wr(register ARCHD *arcn) -#else int -tar_wr(arcn) - register ARCHD *arcn; -#endif +tar_wr(ARCHD *arcn) { - register HD_TAR *hd; + HD_TAR *hd; int len; char hdblk[sizeof(HD_TAR)]; /* * check for those file system types which tar cannot store */ - switch(arcn->type) { + switch (arcn->type) { case PAX_DIR: /* * user asked that dirs not be written to the archive @@ -627,26 +575,25 @@ tar_wr(arcn) } /* - * copy the data out of the ARCHD into the tar header based on the type - * of the file. Remember many tar readers want the unused fields to be - * padded with zero. We set the linkflag field (type), the linkname - * (or zero if not used),the size, and set the padding (if any) to be - * added after the file data (0 for all other types, as they only have - * a header) + * Copy the data out of the ARCHD into the tar header based on the type + * of the file. Remember, many tar readers want all fields to be + * padded with zero so we zero the header first. We then set the + * linkflag field (type), the linkname, the size, and set the padding + * (if any) to be added after the file data (0 for all other types, + * as they only have a header). */ + memset(hdblk, 0, sizeof(hdblk)); hd = (HD_TAR *)hdblk; - l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1); - hd->name[sizeof(hd->name) - 1] = '\0'; + strlcpy(hd->name, arcn->name, sizeof(hd->name)); arcn->pad = 0; if (arcn->type == PAX_DIR) { /* * directories are the same as files, except have a filename - * that ends with a /, we add the slash here. No data follows, + * that ends with a /, we add the slash here. No data follows * dirs, so no pad. */ hd->linkflag = AREGTYPE; - memset(hd->linkname, 0, sizeof(hd->linkname)); hd->name[len-1] = '/'; if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) goto out; @@ -655,8 +602,7 @@ tar_wr(arcn) * no data follows this file, so no pad */ hd->linkflag = SYMTYPE; - l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); - hd->linkname[sizeof(hd->linkname) - 1] = '\0'; + strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname)); if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) goto out; } else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) { @@ -664,8 +610,7 @@ tar_wr(arcn) * no data follows this file, so no pad */ hd->linkflag = LNKTYPE; - l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); - hd->linkname[sizeof(hd->linkname) - 1] = '\0'; + strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname)); if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1)) goto out; } else { @@ -673,8 +618,7 @@ tar_wr(arcn) * data follows this file, so set the pad */ hd->linkflag = AREGTYPE; - memset(hd->linkname, 0, sizeof(hd->linkname)); -# ifdef NET2_STAT +# ifdef LONG_OFF_T if (ul_oct((u_long)arcn->sb.st_size, hd->size, sizeof(hd->size), 1)) { # else @@ -731,13 +675,8 @@ tar_wr(arcn) * 0 if ok, -1 otherwise */ -#ifdef __STDC__ int ustar_strd(void) -#else -int -ustar_strd() -#endif { if ((usrtb_start() < 0) || (grptb_start() < 0)) return(-1); @@ -751,13 +690,8 @@ ustar_strd() * 0 if ok, -1 otherwise */ -#ifdef __STDC__ int ustar_stwr(void) -#else -int -ustar_stwr() -#endif { if ((uidtb_start() < 0) || (gidtb_start() < 0)) return(-1); @@ -772,17 +706,10 @@ ustar_stwr() * 0 if a ustar header, -1 otherwise */ -#ifdef __STDC__ int ustar_id(char *blk, int size) -#else -int -ustar_id(blk, size) - char *blk; - int size; -#endif { - register HD_USTAR *hd; + HD_USTAR *hd; if (size < BLKMULT) return(-1); @@ -811,19 +738,12 @@ ustar_id(blk, size) * 0 */ -#ifdef __STDC__ -int -ustar_rd(register ARCHD *arcn, register char *buf) -#else int -ustar_rd(arcn, buf) - register ARCHD *arcn; - register char *buf; -#endif +ustar_rd(ARCHD *arcn, char *buf) { - register HD_USTAR *hd; - register char *dest; - register int cnt = 0; + HD_USTAR *hd; + char *dest; + int cnt = 0; dev_t devmajor; dev_t devminor; @@ -832,10 +752,9 @@ ustar_rd(arcn, buf) */ if (ustar_id(buf, BLKMULT) < 0) return(-1); + memset(arcn, 0, sizeof(*arcn)); arcn->org_name = arcn->name; arcn->sb.st_nlink = 1; - arcn->pat = NULL; - arcn->nlen = 0; hd = (HD_USTAR *)buf; /* @@ -844,13 +763,20 @@ ustar_rd(arcn, buf) */ dest = arcn->name; if (*(hd->prefix) != '\0') { - cnt = l_strncpy(dest, hd->prefix, sizeof(arcn->name) - 2); + cnt = strlcpy(dest, hd->prefix, sizeof(arcn->name) - 1); dest += cnt; *dest++ = '/'; cnt++; + } else { + cnt = 0; + } + + if (hd->typeflag != LONGLINKTYPE && hd->typeflag != LONGNAMETYPE) { + arcn->nlen = expandname(dest, sizeof(arcn->name) - cnt, + &gnu_name_string, hd->name, sizeof(hd->name)); + arcn->ln_nlen = expandname(arcn->ln_name, sizeof(arcn->ln_name), + &gnu_link_string, hd->linkname, sizeof(hd->linkname)); } - arcn->nlen = cnt + l_strncpy(dest, hd->name, sizeof(arcn->name) - cnt); - arcn->name[arcn->nlen] = '\0'; /* * follow the spec to the letter. we should only have mode bits, strip @@ -858,7 +784,11 @@ ustar_rd(arcn, buf) */ arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) & 0xfff); - arcn->sb.st_size = (size_t)asc_ul(hd->size, sizeof(hd->size), OCT); +#ifdef LONG_OFF_T + arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT); +#else + arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT); +#endif arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT); arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime; @@ -878,8 +808,6 @@ ustar_rd(arcn, buf) /* * set the defaults, these may be changed depending on the file type */ - arcn->ln_name[0] = '\0'; - arcn->ln_nlen = 0; arcn->pad = 0; arcn->skip = 0; arcn->sb.st_rdev = (dev_t)0; @@ -887,7 +815,7 @@ ustar_rd(arcn, buf) /* * set the mode and PAX type according to the typeflag in the header */ - switch(hd->typeflag) { + switch (hd->typeflag) { case FIFOTYPE: arcn->type = PAX_FIF; arcn->sb.st_mode |= S_IFIFO; @@ -934,12 +862,17 @@ ustar_rd(arcn, buf) arcn->sb.st_mode |= S_IFREG; arcn->sb.st_nlink = 2; } + break; + case LONGLINKTYPE: + case LONGNAMETYPE: /* - * copy the link name + * GNU long link/file; we tag these here and let the + * pax internals deal with it -- too ugly otherwise. */ - arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname, - sizeof(arcn->ln_name) - 1); - arcn->ln_name[arcn->ln_nlen] = '\0'; + arcn->type = + hd->typeflag == LONGLINKTYPE ? PAX_GLL : PAX_GLF; + arcn->pad = TAR_PAD(arcn->sb.st_size); + arcn->skip = arcn->sb.st_size; break; case CONTTYPE: case AREGTYPE: @@ -970,18 +903,15 @@ ustar_rd(arcn, buf) * data to write after the header, -1 if archive write failed */ -#ifdef __STDC__ -int -ustar_wr(register ARCHD *arcn) -#else int -ustar_wr(arcn) - register ARCHD *arcn; -#endif +ustar_wr(ARCHD *arcn) { - register HD_USTAR *hd; - register char *pt; + HD_USTAR *hd; + char *pt; char hdblk[sizeof(HD_USTAR)]; + mode_t mode12only; + int term_char=3; /* orignal setting */ + term_char=1; /* To pass conformance tests 274, 301 */ /* * check for those file system types ustar cannot store @@ -995,8 +925,12 @@ ustar_wr(arcn) * check the length of the linkname */ if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) || - (arcn->type == PAX_HRG)) && (arcn->ln_nlen >= sizeof(hd->linkname))){ + (arcn->type == PAX_HRG)) && (arcn->ln_nlen > sizeof(hd->linkname))){ paxwarn(1, "Link name too long for ustar %s", arcn->ln_name); + /* + * Conformance: test pax:285 wants error code to be non-zero, and + * test tar:12 wants error code from pax to be 0 + */ return(1); } @@ -1008,8 +942,16 @@ ustar_wr(arcn) paxwarn(1, "File name too long for ustar %s", arcn->name); return(1); } + + /* + * zero out the header so we don't have to worry about zero fill below + */ + memset(hdblk, 0, sizeof(hdblk)); hd = (HD_USTAR *)hdblk; arcn->pad = 0L; + /* To pass conformance tests 274/301, always set these fields to "zero" */ + ul_oct(0, hd->devmajor, sizeof(hd->devmajor), term_char); + ul_oct(0, hd->devminor, sizeof(hd->devminor), term_char); /* * split the name, or zero out the prefix @@ -1020,26 +962,27 @@ ustar_wr(arcn) * occur, we remove the / and copy the first part to the prefix */ *pt = '\0'; - l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix) - 1); + strlcpy(hd->prefix, arcn->name, sizeof(hd->prefix)); *pt++ = '/'; - } else - memset(hd->prefix, 0, sizeof(hd->prefix)); + } /* * copy the name part. this may be the whole path or the part after * the prefix */ - l_strncpy(hd->name, pt, sizeof(hd->name) - 1); - hd->name[sizeof(hd->name) - 1] = '\0'; + if (strlen(pt) == sizeof(hd->name)) { /* must account for name just fits in buffer */ + strncpy(hd->name, pt, sizeof(hd->name)); + } else { + strlcpy(hd->name, pt, sizeof(hd->name)); + } /* * set the fields in the header that are type dependent */ - switch(arcn->type) { + switch (arcn->type) { case PAX_DIR: hd->typeflag = DIRTYPE; - memset(hd->linkname, 0, sizeof(hd->linkname)); - if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) + if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char)) goto out; break; case PAX_CHR: @@ -1048,15 +991,16 @@ ustar_wr(arcn) hd->typeflag = CHRTYPE; else hd->typeflag = BLKTYPE; - memset(hd->linkname, 0, sizeof(hd->linkname)); - if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) + if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor, + sizeof(hd->devmajor), term_char) || + ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor, + sizeof(hd->devminor), term_char) || + ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char)) goto out; - break; case PAX_FIF: hd->typeflag = FIFOTYPE; - memset(hd->linkname, 0, sizeof(hd->linkname)); - if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) + if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char)) goto out; break; case PAX_SLK: @@ -1066,9 +1010,12 @@ ustar_wr(arcn) hd->typeflag = SYMTYPE; else hd->typeflag = LNKTYPE; - l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1); - hd->linkname[sizeof(hd->linkname) - 1] = '\0'; - if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3)) + if (strlen(arcn->ln_name) == sizeof(hd->linkname)) { /* must account for name just fits in buffer */ + strncpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname)); + } else { + strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname)); + } + if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char)) goto out; break; case PAX_REG: @@ -1081,14 +1028,13 @@ ustar_wr(arcn) hd->typeflag = CONTTYPE; else hd->typeflag = REGTYPE; - memset(hd->linkname, 0, sizeof(hd->linkname)); arcn->pad = TAR_PAD(arcn->sb.st_size); -# ifdef NET2_STAT +# ifdef LONG_OFF_T if (ul_oct((u_long)arcn->sb.st_size, hd->size, - sizeof(hd->size), 3)) { + sizeof(hd->size), term_char)) { # else if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size, - sizeof(hd->size), 3)) { + sizeof(hd->size), term_char)) { # endif paxwarn(1,"File is too long for ustar %s",arcn->org_name); return(1); @@ -1096,27 +1042,49 @@ ustar_wr(arcn) break; } - /* set devmajor and devminor for all types as per spec */ - if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor, - sizeof(hd->devmajor), 3) || - ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor, - sizeof(hd->devminor), 3)) - goto out; - - l_strncpy(hd->magic, TMAGIC, TMAGLEN); - l_strncpy(hd->version, TVERSION, TVERSLEN); + strncpy(hd->magic, TMAGIC, TMAGLEN); + strncpy(hd->version, TVERSION, TVERSLEN); /* * set the remaining fields. Some versions want all 16 bits of mode * we better humor them (they really do not meet spec though).... */ - if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) || - ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3) || - ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) || - ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3)) + if (ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), term_char)) { + if (uid_nobody == 0) { + if (uid_name("nobody", &uid_nobody) == -1) + goto out; + } + if (uid_warn != arcn->sb.st_uid) { + uid_warn = arcn->sb.st_uid; + paxwarn(1, + "Ustar header field is too small for uid %lu, " + "using nobody", (u_long)arcn->sb.st_uid); + } + if (ul_oct((u_long)uid_nobody, hd->uid, sizeof(hd->uid), term_char)) + goto out; + } + if (ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), term_char)) { + if (gid_nobody == 0) { + if (gid_name("nobody", &gid_nobody) == -1) + goto out; + } + if (gid_warn != arcn->sb.st_gid) { + gid_warn = arcn->sb.st_gid; + paxwarn(1, + "Ustar header field is too small for gid %lu, " + "using nobody", (u_long)arcn->sb.st_gid); + } + if (ul_oct((u_long)gid_nobody, hd->gid, sizeof(hd->gid), term_char)) + goto out; + } + /* However, Unix conformance tests do not like MORE than 12 mode bits: + remove all beyond (see definition of stat.st_mode structure) */ + mode12only = ((u_long)arcn->sb.st_mode) & 0x00000fff; + if (ul_oct((u_long)mode12only, hd->mode, sizeof(hd->mode), term_char) || + ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),term_char)) goto out; - l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname)); - l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname)); + strncpy(hd->uname, name_uid(arcn->sb.st_uid, 0), sizeof(hd->uname)); + strncpy(hd->gname, name_gid(arcn->sb.st_gid, 0), sizeof(hd->gname)); /* * calculate and store the checksum write the header to the archive @@ -1124,7 +1092,7 @@ ustar_wr(arcn) * needs to be written */ if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum, - sizeof(hd->chksum), 3)) + sizeof(hd->chksum), term_char)) goto out; if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0) return(-1); @@ -1135,7 +1103,7 @@ ustar_wr(arcn) return(1); out: - /* + /* * header field is out of range */ paxwarn(1, "Ustar header field is too small for %s", arcn->org_name); @@ -1154,34 +1122,29 @@ ustar_wr(arcn) * the file name is too long */ -#ifdef __STDC__ -static char * -name_split(register char *name, register int len) -#else -static char * -name_split(name, len) - register char *name; - register int len; -#endif +char * +name_split(char *name, int len) { - register char *start; + char *start; /* * check to see if the file name is small enough to fit in the name * field. if so just return a pointer to the name. */ - if (len < TNMSZ) + if (len <= TNMSZ) return(name); if (len > (TPFSZ + TNMSZ)) return(NULL); /* * we start looking at the biggest sized piece that fits in the name - * field. We walk foward looking for a slash to split at. The idea is + * field. We walk forward looking for a slash to split at. The idea is * to find the biggest piece to fit in the name field (or the smallest * prefix we can find) */ - start = name + len - TNMSZ; + start = name + len - TNMSZ -1; + if ((*start == '/') && (start == name)) + ++start; /* 101 byte paths with leading '/' are dinged otherwise */ while ((*start != '\0') && (*start != '/')) ++start; @@ -1207,3 +1170,27 @@ name_split(name, len) */ return(start); } + +static size_t +expandname(char *buf, size_t len, char **gnu_name, const char *name, size_t name_len) +{ + size_t nlen; + + if (*gnu_name) { + if ((nlen = strlcpy(buf, *gnu_name, len)) >= len) + nlen = len - 1; + free(*gnu_name); + *gnu_name = NULL; + } else { + if (name_len < len) { + /* name may not be null terminated: it might be as big as the + field, so copy is limited to the max size of the header field */ + if ((nlen = strlcpy(buf, name, name_len+1)) >= name_len+1) + nlen = name_len; + } else { + if ((nlen = strlcpy(buf, name, len)) >= len) + nlen = len - 1; + } + } + return(nlen); +} diff --git a/pax/tar.h b/pax/tar.h index 79a8ce4..61bc6e1 100644 --- a/pax/tar.h +++ b/pax/tar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tar.h,v 1.5 1997/04/16 03:50:25 millert Exp $ */ +/* $OpenBSD: tar.h,v 1.7 2003/06/02 23:32:09 millert Exp $ */ /* $NetBSD: tar.h,v 1.3 1995/03/21 09:07:51 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -65,6 +61,15 @@ #define FIFOTYPE '6' /* FIFO */ #define CONTTYPE '7' /* high perf file */ +#define PAXXTYPE 'x' /* pax format extended header */ +#define PAXGTYPE 'g' /* pax format global extended header */ + +/* + * GNU tar compatibility; + */ +#define LONGLINKTYPE 'K' /* Long Symlink */ +#define LONGNAMETYPE 'L' /* Long File */ + /* * Mode field encoding of the different file types - values in octal */ diff --git a/pax/tty_subs.c b/pax/tty_subs.c index 61f4e78..c72ec8e 100644 --- a/pax/tty_subs.c +++ b/pax/tty_subs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty_subs.c,v 1.5 1997/07/25 18:58:39 mickey Exp $ */ +/* $OpenBSD: tty_subs.c,v 1.12 2003/06/02 23:32:09 millert Exp $ */ /* $NetBSD: tty_subs.c,v 1.5 1995/03/21 09:07:52 cgd Exp $ */ /*- @@ -17,11 +17,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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. * @@ -40,9 +36,9 @@ #ifndef lint #if 0 -static char sccsid[] = "@(#)tty_subs.c 8.2 (Berkeley) 4/18/94"; +static const char sccsid[] = "@(#)tty_subs.c 8.2 (Berkeley) 4/18/94"; #else -static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tty_subs.c,v 1.5 1997/07/25 18:58:39 mickey Exp $"; +static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tty_subs.c,v 1.12 2003/06/02 23:32:09 millert Exp $"; #endif #endif /* not lint */ @@ -58,11 +54,7 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tty_subs.c,v 1.5 1 #include #include "pax.h" #include "extern.h" -#ifdef __STDC__ #include -#else -#include -#endif /* * routines that deal with I/O to and from the user @@ -74,17 +66,12 @@ static FILE *ttyinf = NULL; /* input pointing at control tty */ /* * tty_init() - * try to open the controlling termina (if any) for this process. if the + * 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 */ -#ifdef __STDC__ int tty_init(void) -#else -int -tty_init() -#endif { int ttyfd; @@ -110,24 +97,16 @@ tty_init() * if there is no controlling terminal, just return. */ -#ifdef __STDC__ void -tty_prnt(char *fmt, ...) -#else -void -tty_prnt(fmt, va_alist) - char *fmt; - va_dcl -#endif +tty_prnt(const char *fmt, ...) { va_list ap; -# ifdef __STDC__ + va_start(ap, fmt); -# else - va_start(ap); -# endif - if (ttyoutf == NULL) + if (ttyoutf == NULL) { + va_end(ap); return; + } (void)vfprintf(ttyoutf, fmt, ap); va_end(ap); (void)fflush(ttyoutf); @@ -141,17 +120,10 @@ tty_prnt(fmt, va_alist) * 0 if data was read, -1 otherwise. */ -#ifdef __STDC__ int tty_read(char *str, int len) -#else -int -tty_read(str, len) - char *str; - int len; -#endif { - register char *pt; + char *pt; if ((--len <= 0) || (ttyinf == NULL) || (fgets(str,len,ttyinf) == NULL)) return(-1); @@ -171,30 +143,20 @@ tty_read(str, len) * will be non-zero. */ -#ifdef __STDC__ -void -paxwarn(int set, char *fmt, ...) -#else void -paxwarn(set, fmt, va_alist) - int set; - char *fmt; - va_dcl -#endif +paxwarn(int set, const char *fmt, ...) { va_list ap; -# ifdef __STDC__ + va_start(ap, fmt); -# else - va_start(ap); -# endif - if (set) + if (set && (pax_invalid_action==0)) exit_val = 1; /* * 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); vfpart = 0; } @@ -210,24 +172,12 @@ paxwarn(set, fmt, va_alist) * will be non-zero. */ -#ifdef __STDC__ -void -syswarn(int set, int errnum, char *fmt, ...) -#else void -syswarn(set, errnum, fmt, va_alist) - int set; - int errnum; - char *fmt; - va_dcl -#endif +syswarn(int set, int errnum, const char *fmt, ...) { va_list ap; -# ifdef __STDC__ + va_start(ap, fmt); -# else - va_start(ap); -# endif if (set) exit_val = 1; /* @@ -235,6 +185,7 @@ syswarn(set, errnum, fmt, va_alist) * line by itself */ if (vflag && vfpart) { + (void)fflush(listf); (void)fputc('\n', stderr); vfpart = 0; } @@ -246,6 +197,6 @@ syswarn(set, errnum, fmt, va_alist) * format and print the errno */ if (errnum > 0) - (void)fprintf(stderr, " <%s>", strerror(errnum)); + (void)fprintf(stderr, ": %s", strerror(errnum)); (void)fputc('\n', stderr); } diff --git a/rm/rm.c b/rm/rm.c index c5c4da5..def4a2f 100644 --- a/rm/rm.c +++ b/rm/rm.c @@ -61,6 +61,8 @@ static const char rcsid[] = #include #ifdef __APPLE__ +#include +#include #include "get_compat.h" #else #define COMPAT_MODE(func, mode) 1 @@ -93,6 +95,9 @@ main(argc, argv) int ch, rflag; char *p; + if (argc < 1) + usage(); + /* * Test for the special case where the utility is called as * "unlink", for which the functionality provided is greatly @@ -310,6 +315,7 @@ err: } if (errno) err(1, "fts_read"); + fts_close(fts); } void diff --git a/shar/shar.1 b/shar/shar.1 index e6b0f15..3f9dac9 100644 --- a/shar/shar.1 +++ b/shar/shar.1 @@ -61,8 +61,8 @@ or .Sh SEE ALSO .Xr compress 1 , .Xr mail 1 , -.Xr uuencode 1 , -.Xr tar 1 +.Xr tar 1 , +.Xr uuencode 1 .Sh BUGS .Nm makes no provisions for special types of files or files containing diff --git a/stat/Makefile b/stat/Makefile index 550d148..5bad274 100644 --- a/stat/Makefile +++ b/stat/Makefile @@ -16,6 +16,7 @@ CFILES = stat.c OTHERSRCS = Makefile Makefile.preamble Makefile.postamble stat.1 +OTHER_CFLAGS = -D__FBSDID=__RCSID MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC diff --git a/stat/stat.1 b/stat/stat.1 index 4f4a784..79c774f 100644 --- a/stat/stat.1 +++ b/stat/stat.1 @@ -34,17 +34,17 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.\" $FreeBSD: src/usr.bin/stat/stat.1,v 1.6 2003/06/02 11:19:23 ru Exp $ +.\" $FreeBSD: src/usr.bin/stat/stat.1,v 1.8 2005/06/14 11:50:53 ru Exp $ .\" .Dd May 8, 2003 .Dt STAT 1 .Os .Sh NAME -.Nm stat , -.Nm readlink +.Nm readlink , +.Nm stat .Nd display file status .Sh SYNOPSIS -.Nm +.Nm stat .Op Fl FLnq .Op Fl f Ar format | Fl l | r | s | x .Op Fl t Ar timefmt @@ -54,14 +54,14 @@ .Op Ar .Sh DESCRIPTION The -.Nm +.Nm stat utility displays information about the file pointed to by .Ar file . Read, write or execute permissions of the named file are not required, but all directories listed in the path name leading to the file must be searchable. If no argument is given, -.Nm +.Nm stat displays information about the file descriptor for standard input. .Pp When invoked as @@ -77,6 +77,7 @@ with the given argument and evaluating the returned structure. .Pp The options are as follows: .Bl -tag -width indent +.\" ========== .It Fl F As in .Xr ls 1 , @@ -102,20 +103,34 @@ The use of .Fl F implies .Fl l . +.\" ========== +.It Fl f Ar format +Display information using the specified format. +See the +.Sx FORMATS +section for a description of valid formats. +.\" ========== .It Fl L Use .Xr stat 2 instead of .Xr lstat 2 . The information reported by -.Nm +.Nm stat will refer to the target of .Ar file , if file is a symbolic link, and not to .Ar file itself. +.\" ========== +.It Fl l +Display output in +.Nm ls Fl lT +format. +.\" ========== .It Fl n Do not force a newline to appear at the end of each piece of output. +.\" ========== .It Fl q Suppress failure messages if calls to .Xr stat 2 @@ -125,15 +140,7 @@ fail. When run as .Nm readlink , error messages are automatically suppressed. -.It Fl f Ar format -Display information using the specified format. -See the -.Sx FORMATS -section for a description of valid formats. -.It Fl l -Display output in -.Nm ls Fl lT -format. +.\" ========== .It Fl r Display raw information. That is, for all the fields in the @@ -141,19 +148,22 @@ That is, for all the fields in the structure, display the raw, numerical value (for example, times in seconds since the epoch, etc.). +.\" ========== .It Fl s Display information in .Dq "shell output" , suitable for initializing variables. -.It Fl x -Display information in a more verbose way as known from some -.Tn Linux -distributions. +.\" ========== .It Fl t Ar timefmt Display timestamps using the specified format. This format is passed directly to .Xr strftime 3 . +.\" ========== +.It Fl x +Display information in a more verbose way as known from some +.Tn Linux +distributions. .El .Ss Formats Format strings are similar to @@ -430,7 +440,7 @@ that points from to .Pa / , you would use -.Nm +.Nm stat as follows: .Bd -literal -offset indent \*[Gt] stat -F /tmp/foo @@ -507,13 +517,15 @@ Apr 24 16:47:35 2002 /tmp/foo .Xr strftime 3 .Sh HISTORY The -.Nm +.Nm stat utility appeared in -.Nx 1.6 . +.Nx 1.6 +and +.Fx 4.10 . .Sh AUTHORS .An -nosplit The -.Nm +.Nm stat utility was written by .An Andrew Brown .Aq atatat@NetBSD.org . diff --git a/stat/stat.c b/stat/stat.c index 78f8107..5603a05 100644 --- a/stat/stat.c +++ b/stat/stat.c @@ -41,16 +41,14 @@ __RCSID("$NetBSD: stat.c,v 1.13 2003/07/25 03:21:17 atatat Exp $"); #endif #endif -/* Commenting FBSDID, as it is not needed in OSX. __FBSDID("$FreeBSD: src/usr.bin/stat/stat.c,v 1.6 2003/10/06 01:55:17 dougb Exp $"); -*/ #if HAVE_CONFIG_H #include "config.h" #else /* HAVE_CONFIG_H */ #define HAVE_STRUCT_STAT_ST_FLAGS 1 #define HAVE_STRUCT_STAT_ST_GEN 1 -#define HAVE_STRUCT_STAT_ST_BIRTHTIME 0 /* was 1; not needed if ! __BSD_VISIBLE ? */ +#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 #define HAVE_STRUCT_STAT_ST_MTIMENSEC 1 #define HAVE_DEVNAME 1 #endif /* HAVE_CONFIG_H */ @@ -69,6 +67,12 @@ __FBSDID("$FreeBSD: src/usr.bin/stat/stat.c,v 1.6 2003/10/06 01:55:17 dougb Exp #include #include +#ifdef __APPLE__ +#define stat stat64 +#define fstat fstat64 +#define lstat lstat64 +#endif /* __APPLE__ */ + #if HAVE_STRUCT_STAT_ST_FLAGS #define DEF_F "%#Xf " #define RAW_F "%f " @@ -110,7 +114,7 @@ __FBSDID("$FreeBSD: src/usr.bin/stat/stat.c,v 1.6 2003/10/06 01:55:17 dougb Exp #define LINUX_FORMAT \ " File: \"%N\"%n" \ " Size: %-11z FileType: %HT%n" \ - " Mode: (%04OLp/%.10Sp) Uid: (%5u/%8Su) Gid: (%5g/%8Sg)%n" \ + " Mode: (%04OA/%.10Sp) Uid: (%5u/%8Su) Gid: (%5g/%8Sg)%n" \ "Device: %Hd,%Ld Inode: %i Links: %l%n" \ "Access: %Sa%n" \ "Modify: %Sm%n" \ @@ -162,6 +166,7 @@ __FBSDID("$FreeBSD: src/usr.bin/stat/stat.c,v 1.6 2003/10/06 01:55:17 dougb Exp #define SHOW_st_dev 'd' #define SHOW_st_ino 'i' #define SHOW_st_mode 'p' +#define SHOW_st_mode2 'A' #define SHOW_st_nlink 'l' #define SHOW_st_uid 'u' #define SHOW_st_gid 'g' @@ -487,6 +492,7 @@ output(const struct stat *st, const char *file, fmtcase(what, SHOW_st_dev); fmtcase(what, SHOW_st_ino); fmtcase(what, SHOW_st_mode); + fmtcase(what, SHOW_st_mode2); fmtcase(what, SHOW_st_nlink); fmtcase(what, SHOW_st_uid); fmtcase(what, SHOW_st_gid); @@ -601,6 +607,7 @@ format1(const struct stat *st, ofmt = FMTF_UNSIGNED; break; case SHOW_st_mode: + case SHOW_st_mode2: small = (sizeof(st->st_mode) == 4); data = st->st_mode; strmode(st->st_mode, smode); @@ -608,6 +615,8 @@ format1(const struct stat *st, l = strlen(sdata); if (sdata[l - 1] == ' ') sdata[--l] = '\0'; + if (what == SHOW_st_mode2) + data &= 07777; if (hilo == HIGH_PIECE) { data >>= 12; sdata += 1; diff --git a/tcopy/Makefile.postamble b/tcopy/Makefile.postamble deleted file mode 100644 index 013b558..0000000 --- a/tcopy/Makefile.postamble +++ /dev/null @@ -1 +0,0 @@ -include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common diff --git a/tcopy/tcopy.1 b/tcopy/tcopy.1 deleted file mode 100644 index 880d18b..0000000 --- a/tcopy/tcopy.1 +++ /dev/null @@ -1,115 +0,0 @@ -.\" Copyright (c) 1985, 1990, 1991, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 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. -.\" -.\" @(#)tcopy.1 8.2 (Berkeley) 4/17/94 -.\" $FreeBSD: src/usr.bin/tcopy/tcopy.1,v 1.15 2003/09/05 15:28:09 roam Exp $ -.\" -.Dd April 17, 1994 -.Dt TCOPY 1 -.Os -.Sh NAME -.Nm tcopy -.Nd copy and/or verify mag tapes -.Sh SYNOPSIS -.Nm -.Op Fl cvx -.Op Fl s Ar maxblk -.Oo Ar src Op Ar dest -.Oc -.Sh DESCRIPTION -The -.Nm -utility is designed to copy magnetic tapes. The only assumption made -about the tape is that there are two tape marks at the end. -The -.Nm -utility with only a source tape -.Pf ( Ar /dev/sa0 -by default) specified will print -information about the sizes of records and tape files. If a destination -is specified a copy will be made of the source tape. The blocking on the -destination tape will be identical to that used on the source tape. Copying -a tape will yield the same output as if just printing the sizes. -.Pp -Options: -.Bl -tag -width s_maxblk -.It Fl c -Copy -.Ar src -to -.Ar dest -and then verify that the two tapes are identical. -.It Fl s Ar maxblk -Specify a maximum block size, -.Ar maxblk . -.It Fl v -Given the two tapes, -.Ar src -and -.Ar dest -verify that they are identical. -.It Fl x -Output all informational messages to the standard error. -This option is useful when -.Ar dest -is -.Pa /dev/stdout . -.El -.Sh SEE ALSO -.Xr mtio 4 -.Sh HISTORY -The -.Nm -command appeared in -.Bx 4.3 . -.Sh BUGS -.Bl -item -.It -Writing an image of a tape to a file does not preserve much more than -the raw data. -Block size(s) and tape EOF marks are lost which would -otherwise be preserved in a tape-to-tape copy. -.It -EOD is determined by two sequential EOF marks with no data between. -There are old systems which typically wrote three EOF's between tape -files. -The -.Nm -utility will erroneously stop copying early in this case. -.It -When using the copy/verify option \-c -.Nm -does not rewind the tapes prior to start. -A rewind is performed -after writing prior to the verification stage. -If one doesn't start -at BOT then the comparison may not be of the intended data. -.El diff --git a/tcopy/tcopy.c b/tcopy/tcopy.c deleted file mode 100644 index 8f70cbe..0000000 --- a/tcopy/tcopy.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (c) 1985, 1987, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. - */ - -#include - -#ifndef lint -static const char copyright[] = -"@(#) Copyright (c) 1985, 1987, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif - -#ifndef lint -static const char sccsid[] = "@(#)tcopy.c 8.2 (Berkeley) 4/17/94"; -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAXREC (64 * 1024) -#define NOCOUNT (-2) - -int filen, guesslen, maxblk = MAXREC; -u_int64_t lastrec, record, size, tsize; -FILE *msg; - -void *getspace(int); -void intr(int); -static void usage(void); -void verify(int, int, char *); -void writeop(int, int); -void rewind_tape(int); - -int -main(argc, argv) - int argc; - char *argv[]; -{ - register int lastnread, nread, nw, inp, outp; - enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; - sig_t oldsig; - int ch, needeof; - char *buff; - const char *inf; - - msg = stdout; - guesslen = 1; - while ((ch = getopt(argc, argv, "cs:vx")) != -1) - switch((char)ch) { - case 'c': - op = COPYVERIFY; - break; - case 's': - maxblk = atoi(optarg); - if (maxblk <= 0) { - warnx("illegal block size"); - usage(); - } - guesslen = 0; - break; - case 'v': - op = VERIFY; - break; - case 'x': - msg = stderr; - break; - case '?': - default: - usage(); - } - argc -= optind; - argv += optind; - - switch(argc) { - case 0: - if (op != READ) - usage(); - inf = _PATH_DEFTAPE; - break; - case 1: - if (op != READ) - usage(); - inf = argv[0]; - break; - case 2: - if (op == READ) - op = COPY; - inf = argv[0]; - if ((outp = open(argv[1], op == VERIFY ? O_RDONLY : - op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) - err(3, "%s", argv[1]); - break; - default: - usage(); - } - - if ((inp = open(inf, O_RDONLY, 0)) < 0) - err(1, "%s", inf); - - buff = getspace(maxblk); - - if (op == VERIFY) { - verify(inp, outp, buff); - exit(0); - } - - if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) - (void) signal(SIGINT, intr); - - needeof = 0; - for (lastnread = NOCOUNT;;) { - if ((nread = read(inp, buff, maxblk)) == -1) { - while (errno == EINVAL && (maxblk -= 1024)) { - nread = read(inp, buff, maxblk); - if (nread >= 0) - goto r1; - } - err(1, "read error, file %d, record %qu", filen, record); - } else if (nread != lastnread) { - if (lastnread != 0 && lastnread != NOCOUNT) { - if (lastrec == 0 && nread == 0) - fprintf(msg, "%qu records\n", record); - else if (record - lastrec > 1) - fprintf(msg, "records %qu to %qu\n", - lastrec, record); - else - fprintf(msg, "record %qu\n", lastrec); - } - if (nread != 0) - fprintf(msg, "file %d: block size %d: ", - filen, nread); - (void) fflush(stdout); - lastrec = record; - } -r1: guesslen = 0; - if (nread > 0) { - if (op == COPY || op == COPYVERIFY) { - if (needeof) { - writeop(outp, MTWEOF); - needeof = 0; - } - nw = write(outp, buff, nread); - if (nw != nread) { - if (nw == -1) { - warn("write error, file %d, record %qu", filen, record); - } else { - warnx("write error, file %d, record %qu", filen, record); - warnx("write (%d) != read (%d)", nw, nread); - } - errx(5, "copy aborted"); - } - } - size += nread; - record++; - } else { - if (lastnread <= 0 && lastnread != NOCOUNT) { - fprintf(msg, "eot\n"); - break; - } - fprintf(msg, - "file %d: eof after %qu records: %qu bytes\n", - filen, record, size); - needeof = 1; - filen++; - tsize += size; - size = record = lastrec = 0; - lastnread = 0; - } - lastnread = nread; - } - fprintf(msg, "total length: %qu bytes\n", tsize); - (void)signal(SIGINT, oldsig); - if (op == COPY || op == COPYVERIFY) { - writeop(outp, MTWEOF); - writeop(outp, MTWEOF); - if (op == COPYVERIFY) { - rewind_tape(outp); - rewind_tape(inp); - verify(inp, outp, buff); - } - } - exit(0); -} - -void -verify(inp, outp, outb) - register int inp, outp; - register char *outb; -{ - register int eot, inmaxblk, inn, outmaxblk, outn; - register char *inb; - - inb = getspace(maxblk); - inmaxblk = outmaxblk = maxblk; - for (eot = 0;; guesslen = 0) { - if ((inn = read(inp, inb, inmaxblk)) == -1) { - if (guesslen) - while (errno == EINVAL && (inmaxblk -= 1024)) { - inn = read(inp, inb, inmaxblk); - if (inn >= 0) - goto r1; - } - warn("read error"); - break; - } -r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { - if (guesslen) - while (errno == EINVAL && (outmaxblk -= 1024)) { - outn = read(outp, outb, outmaxblk); - if (outn >= 0) - goto r2; - } - warn("read error"); - break; - } -r2: if (inn != outn) { - fprintf(msg, - "%s: tapes have different block sizes; %d != %d.\n", - "tcopy", inn, outn); - break; - } - if (!inn) { - if (eot++) { - fprintf(msg, "tcopy: tapes are identical.\n"); - return; - } - } else { - if (bcmp(inb, outb, inn)) { - fprintf(msg, - "tcopy: tapes have different data.\n"); - break; - } - eot = 0; - } - } - exit(1); -} - -void -intr(signo) - int signo __unused; -{ - if (record) { - if (record - lastrec > 1) - fprintf(msg, "records %qu to %qu\n", lastrec, record); - else - fprintf(msg, "record %qu\n", lastrec); - } - fprintf(msg, "interrupt at file %d: record %qu\n", filen, record); - fprintf(msg, "total length: %ju bytes\n", (uintmax_t)(tsize + size)); - exit(1); -} - -void * -getspace(blk) - int blk; -{ - void *bp; - - if ((bp = malloc((size_t)blk)) == NULL) - errx(11, "no memory"); - return (bp); -} - -void -writeop(fd, type) - int fd, type; -{ - struct mtop op; - - op.mt_op = type; - op.mt_count = (daddr_t)1; - if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) - err(6, "tape op"); -} - -static void -usage() -{ - fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] [src [dest]]\n"); - exit(1); -} - -void -rewind_tape(int fd) -{ - struct stat sp; - - if(fstat(fd, &sp)) - errx(12, "fstat in rewind"); - - /* - * don't want to do tape ioctl on regular files: - */ - if( S_ISREG(sp.st_mode) ) { - if( lseek(fd, 0, SEEK_SET) == -1 ) - errx(13, "lseek"); - } else - /* assume its a tape */ - writeop(fd, MTREW); -} diff --git a/touch/touch.c b/touch/touch.c index 77ca8e9..8909d79 100644 --- a/touch/touch.c +++ b/touch/touch.c @@ -189,11 +189,12 @@ main(int argc, char *argv[]) continue; /* Try reading/writing. */ - if (!S_ISLNK(sb.st_mode) && !S_ISDIR(sb.st_mode) && - rw(*argv, &sb, fflag)) - rval = 1; - else - warn("%s", *argv); + if (S_ISLNK(sb.st_mode) || S_ISDIR(sb.st_mode)) { + warn("%s", *argv); + rval = 1; + } else if (rw(*argv, &sb, fflag)) { + rval = 1; + } } exit(rval); } -- 2.7.4