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
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble chflags.1
+OTHER_CFLAGS = -D__FBSDID=__RCSID
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
+.\"-
.\" Copyright (c) 1989, 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
.\"
.\" 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.
.\" 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
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
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 ,
.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.
-/*
+/*-
* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* 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.
* 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 <sys/cdefs.h>
-__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 <sys/types.h>
#include <sys/stat.h>
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();
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) {
} 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;
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;
* 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);
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);
}
.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
.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
.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
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
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
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 ,
.Xr sticky 8
.Sh STANDARDS
The
-.Nm
+.Nm chmod
utility is expected to be
.St -p1003.2
compatible with the exception of the
which is not included in that standard.
.Sh HISTORY
A
-.Nm
+.Nm chmod
command appeared in
.At v1 .
#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':
case 'f':
fflag = 1;
break;
-#ifndef __APPLE__
case 'h':
/*
* In System V (and probably POSIX.2) the -h option
*/
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;
case 'V':
acloptflags |= ACL_FLAG | ACL_INVOKE_EDITOR;
ace_arg_not_required = 1;
+ errx(1, "-V not implemented");
goto done;
#endif /* __APPLE__ */
/*
} 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;
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;
{
#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");
* 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;
}
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'? */
} 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 */
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);
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");
}
}
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 */
}
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;
}
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))
}
}
if (0 == match_found) {
- errno = EINVAL;
- warn("Entry not found when attempting delete");
+ warnx("Entry not found when attempting delete");
retval = 1;
}
}
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
* "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;
}
#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)
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__*/
.Nm chgrp
.Nd change group
.Sh SYNOPSIS
-.Nm
+.Nm chgrp
.Op Fl fhv
.Oo
.Fl R
.Ar
.Sh DESCRIPTION
The
-.Nm
+.Nm chgrp
utility sets the group ID of the file named by each
.Ar file
operand to the
.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
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
.Xr chown 8
.Sh STANDARDS
The
-.Nm
+.Nm chgrp
utility is expected to be
.St -p1003.2
compatible.
.Nm chown
.Nd change file owner and group
.Sh SYNOPSIS
-.Nm
+.Nm chown
.Op Fl fhv
.Oo
.Fl R
.Oc
.Ar owner Ns Op : Ns Ar group
.Ar
-.Nm
+.Nm chown
.Op Fl fhv
.Oo
.Fl R
.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
.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
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
.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.
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 .
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sys/time.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
void a_gid(const char *);
void a_uid(const char *);
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);
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);
}
#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)
*/
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;
--- /dev/null
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = cksum
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+HFILES = extern.h
+
+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
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/bin
+LIBS =
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+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 = $(JDKBINDIR)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
--- /dev/null
+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
--- /dev/null
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
--- /dev/null
+{
+ DYNAMIC_CODE_GEN = YES;
+ FILESTABLE = {
+ FRAMEWORKS = ();
+ 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/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 = "$(JDKBINDIR)/javac";
+ PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
+ PROJECTNAME = cksum;
+ PROJECTTYPE = Tool;
+ PROJECTVERSION = 2.8;
+ WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
+ WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
+ WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
+}
--- /dev/null
+.\" 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 .
--- /dev/null
+/*-
+ * 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:
+ * 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.
+ */
+
+#ifndef lint
+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[] = "@(#)cksum.c 8.2 (Berkeley) 4/28/95";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cksum/cksum.c,v 1.17 2003/03/13 23:32:28 robert Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ 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;
+
+ 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, "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();
+ }
+ argc -= optind;
+ argv += optind;
+ }
+
+ 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;
+ }
+ }
+ if (cfncn(fd, &val, &len)) {
+ warn("%s", fn ? fn : "stdin");
+ rval = 1;
+ } else
+ pfncn(fn, val, len);
+ (void)close(fd);
+ } while (*argv);
+ exit(rval);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: cksum [-o 1 | 2 | 3] [file ...]\n");
+ (void)fprintf(stderr, " sum [file ...]\n");
+ exit(1);
+}
#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 <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cksum/crc.c,v 1.8 2003/03/13 23:32:28 robert Exp $");
#include <sys/types.h>
+
+#include <stdint.h>
#include <unistd.h>
-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,
* 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)
/* 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);
}
--- /dev/null
+/*
+ * 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 <srg@quick.com>
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cksum/crc32.c,v 1.9 2003/03/13 23:32:28 robert Exp $");
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#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 ;
+}
--- /dev/null
+/*-
+ * Copyright (c) 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.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/cksum/extern.h,v 1.6 2003/03/13 23:32:28 robert Exp $
+ */
+
+#include <sys/cdefs.h>
+
+__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
--- /dev/null
+/*-
+ * Copyright (c) 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)print.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cksum/print.c,v 1.7 2003/03/13 23:32:28 robert Exp $");
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdint.h>
+
+#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");
+}
+
+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");
+}
+
+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");
+}
--- /dev/null
+/*-
+ * Copyright (c) 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)sum1.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cksum/sum1.c,v 1.8 2003/03/13 23:32:28 robert Exp $");
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdint.h>
+
+#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];
+
+ /*
+ * 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);
+
+ *cval = lcrc;
+ *clen = total;
+ return (0);
+}
--- /dev/null
+/*-
+ * Copyright (c) 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.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)sum2.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cksum/sum2.c,v 1.8 2003/03/13 23:32:28 robert Exp $");
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdint.h>
+
+#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);
+
+ lcrc = (lcrc & 0xffff) + (lcrc >> 16);
+ lcrc = (lcrc & 0xffff) + (lcrc >> 16);
+
+ *cval = lcrc;
+ *clen = total;
+ return (0);
+}
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
int bits, ch;
char *p, newname[MAXPATHLEN];
+ if (argc < 1)
+ usage(1);
cat = 0;
if ((p = rindex(argv[0], '/')) == NULL)
p = argv[0];
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);
}
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble cp.1
+OTHER_CFLAGS = -D__FBSDID=__RCSID
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
+.\"-
.\" Copyright (c) 1989, 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
.\"
.\" 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.
.\" 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
.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
.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
(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
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.
.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.
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
.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 ,
.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 .
-/*
+/*-
* Copyright (c) 1988, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* 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.
* SUCH DAMAGE.
*/
+#if 0
#ifndef lint
static char const copyright[] =
"@(#) Copyright (c) 1988, 1993, 1994\n\
#endif /* not lint */
#ifndef lint
-#if 0
static char sccsid[] = "@(#)cp.c 8.2 (Berkeley) 4/1/94";
-#endif
#endif /* not lint */
+#endif
#include <sys/cdefs.h>
-__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.
* in "to") to form the final target path.
*/
-#include <sys/param.h>
+#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
#include <fts.h>
#include <limits.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __APPLE__
#include <copyfile.h>
-#endif
+#include <get_compat.h>
+#else /* !__APPLE__ */
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
-#include "get_compat.h"
#include "extern.h"
#define STRIP_TRAILING_SLASH(p) { \
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[])
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;
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;
fts_options &= ~FTS_PHYSICAL;
fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
}
+ (void)signal(SIGINFO, siginfo);
/* Save the target base in "to". */
target = argv[--argc];
exit (copy(argv, type, fts_options));
}
-int
+static int
copy(char *argv[], enum op type, int fts_options)
{
struct stat to_stat;
* 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)) ||
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;
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
*/
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:
}
if (errno)
err(1, "fts_read");
+ fts_close(ftsp);
return (rval);
}
* 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;
return (1);
return (0);
}
+
+static void
+siginfo(int sig __unused)
+{
+
+ info = 1;
+}
* 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.
* 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 {
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
* 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.
#endif
#endif /* not lint */
#include <sys/cdefs.h>
-__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 <sys/types.h>
+#include <sys/acl.h>
#include <sys/param.h>
-#include <sys/time.h>
#include <sys/stat.h>
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
#include <sys/mman.h>
#include <unistd.h>
#ifdef __APPLE__
+#include <sys/time.h>
#include <copyfile.h>
#include <string.h>
#include <sys/mount.h>
-#endif
+#include <get_compat.h>
+#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;
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);
}
}
- 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));
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__ */
/*
* 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;
}
} 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;
}
}
}
-#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,
* 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);
}
int
-copy_link(FTSENT *p, int exists)
+copy_link(const FTSENT *p, int exists)
{
int len;
char llink[PATH_MAX];
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
warn("mkfifo: %s", to.p_path);
return (1);
}
- return (pflag ? setfile(from_stat, 0) : 0);
+ return (pflag ? setfile(from_stat, -1) : 0);
}
int
warn("mknod: %s", to.p_path);
return (1);
}
- return (pflag ? setfile(from_stat, 0) : 0);
+ return (pflag ? setfile(from_stat, -1) : 0);
}
int
{
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;
* 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);
}
/* 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
CODE_GEN_STYLE = DYNAMIC
MAKEFILE = tool.make
NEXTSTEP_INSTALLDIR = /bin
-LIBS =
+LIBS = -lutil
DEBUG_LIBS = $(LIBS)
PROF_LIBS = $(LIBS)
-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
include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
-INSTALL_AS_GROUP = operator
-INSTALL_PERMISSIONS = 2555
.Nm df
.Nd display free disk space
.Sh SYNOPSIS
-.Nm
+.Nm df
.Oo
.Fl b | h | H | k |
.Fl m | P
.Op Fl T Ar type
.Op Ar file | filesystem ...
.Sh LEGACY SYNOPSIS
-.Nm
+.Nm df
.Oo
.Fl b | h | H | k |
.Fl m | P
.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
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
.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
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.
.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
.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
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 ,
.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 .
#ifdef __APPLE__
#define MNT_IGNORE 0
-#include <sys/types.h>
-typedef int32_t ufs_daddr_t;
#endif
#include <sys/cdefs.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/sysctl.h>
-#include <ufs/ufs/ufsmount.h>
-#include <ufs/ffs/fs.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
+#include <libutil.h>
#ifdef __APPLE__
#include "get_compat.h"
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)
{
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)
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':
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':
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;
/*
rv++;
continue;
}
+
if (argc == 1) {
- bzero(&maxwidths, sizeof(maxwidths));
+ bzero(&maxwidths, sizeof(maxwidths));
update_maxwidths(&maxwidths, &statfsbuf);
}
prtstat(&statfsbuf, &maxwidths);
}
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.
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"));
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"));
}
(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
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)));
}
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);
}
const char **
makevfslist(fslist)
- char *fslist;
+ const char *fslist;
{
const char **av;
int i;
+ const char *cnextcp;
char *nextcp;
if (fslist == NULL)
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) {
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble du.1
+OTHER_CFLAGS = -D__FBSDID=__RCSID
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
-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
.\" 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
.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
.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 .
#endif
#endif /* not lint */
#include <sys/cdefs.h>
-__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 <sys/mount.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <errno.h>
#include <fnmatch.h>
#include <fts.h>
+#include <locale.h>
#include <math.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
-#include <sys/param.h>
-#include <sys/mount.h>
#ifdef __APPLE__
-#include "get_compat.h"
+#include <get_compat.h>
#else
-#define COMPAT_MODE(func, mode) 1
+#define COMPAT_MODE(func, mode) (1)
#endif
#define KILO_SZ(n) (n)
SLIST_ENTRY(ignentry) next;
};
-int linkchk(FTSENT *);
+static int linkchk(FTSENT *);
static void usage(void);
void prthumanval(double);
unit_t unit_adjust(double *);
{
FTS *fts;
FTSENT *p;
+ off_t savednumber = 0;
long blocksize;
int ftsoptions;
int listall;
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':
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;
blocksize /= 512;
rval = 0;
-
+
if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
err(1, "fts_open");
} 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);
}
}
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) {
(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);
}
}
(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));
}
}
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);
}
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);
}
{
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);
return 1;
}
}
+#endif /* __APPLE__ */
SLIST_FOREACH(ign, &ignores, next)
if (fnmatch(ign->mask, ent->fts_name, 0) != FNM_NOMATCH)
return 1;
.Nm install
.Nd install binaries
.Sh SYNOPSIS
-.Nm
+.Nm install
.Op Fl bCcMpSsv
.Op Fl B Ar suffix
.Op Fl f Ar flags
.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
.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
.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
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
(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
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
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
.El
.Sh COMPATIBILITY
Historically
-.Nm
+.Nm install
moved files by default.
The default was changed to copy in
.Fx 4.4 .
.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
#ifdef __APPLE__
#include <copyfile.h>
-#endif
+#endif /* __APPLE__ */
#include "pathnames.h"
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.
*/
/*
* 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;
}
}
}
-
-#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)
.\" 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
.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
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
#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 <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
-#if 0
#include <sys/msg.h>
#include <sys/sem.h>
-#endif
#include <sys/shm.h>
#define IPC_TO_STR(x) (x == 'Q' ? "msq" : (x == 'M' ? "shm" : "sem"))
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);
}
key_t key;
int id;
{
-#if 0
union semun arg;
if (key) {
return -1;
}
return semctl(id, 0, IPC_RMID, arg);
-#endif
}
void not_configured()
{
int c, result, errflg, target_id;
key_t target_key;
+ char *en;
errflg = 0;
signal(SIGSYS, not_configured);
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')
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;
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));
}
exit(errflg);
}
-
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
-include Makefile.postamble
-include Makefile.dependencies
-
-ALL_CFLAGS += -I/System/Library/Frameworks/System.framework/PrivateHeaders
-
include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
+
+INSTALL_AS_USER = root
+INSTALL_PERMISSIONS = 4511
.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
.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
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
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
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
#include <err.h>
#include <fcntl.h>
#include <grp.h>
-#include <kvm.h>
#include <nlist.h>
#include <limits.h>
#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sysexits.h>
#include <sys/types.h>
#include <sys/ucred.h>
+#include <sys/time.h>
#include <sys/proc.h>
#include <sys/param.h>
-#include <sys/time.h>
#include <sys/sysctl.h>
-
-#define KERNEL
-
-#include <sys/ipc.h>
-#include <sys/sem_internal.h>
-#include <sys/shm_internal.h>
-#include <sys/msg.h>
-
+#include <errno.h>
#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;
#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) {
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;
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 <running system> as of %s\n", datestring);
if ((display & (MSGINFO | MSGTOTAL))) {
if (display & MSGTOTAL) {
struct IPCS_command ic;
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);
}
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");
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];
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));
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))) {
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");
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];
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));
shmptr->shm_nattch);
if (option & BIGGEST)
- printf(" %6d",
+ printf(" %6ld",
shmptr->shm_segsz);
if (option & PID)
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");
}
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))) {
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);
}
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");
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));
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);
}
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble ln.1\
symlink.7
+OTHER_CFLAGS = -D__FBSDID=__RCSID
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
+.\"-
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" 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.
.\" 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
.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
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.
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;
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.
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 ,
.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
.St -susv2 .
.Sh HISTORY
An
-.Nm
+.Nm ln
command appeared in
.At v1 .
-/*
+/*-
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* 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.
* SUCH DAMAGE.
*/
+#if 0
#ifndef lint
static char const copyright[] =
"@(#) Copyright (c) 1987, 1993, 1994\n\
#endif /* not lint */
#ifndef lint
-#if 0
static char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 3/31/94";
-#endif
#endif /* not lint */
+#endif
#include <sys/cdefs.h>
-__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 <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
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. */
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
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;
linkf = sflag ? symlink : link;
linkch = sflag ? '-' : '=';
+ if (sflag == 0)
+ Fflag = 0;
+ if (Fflag == 1 && iflag == 0)
+ fflag = 1;
switch(argc) {
case 0:
* 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);
}
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);
}
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);
}
+.\"-
.\" Copyright (c) 1992, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
.\"
.\" 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.
.\" 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
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
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
.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;
.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"
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
.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
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
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
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 *);
--- /dev/null
+/* $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 <sys/cdefs.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <fts.h>
+
+#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);
+}
.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.
.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
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 /
.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
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
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 . )
(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.
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
.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
.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
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
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,
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
.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
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.
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 ,
.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
#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 *);
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 */
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 */
char *bp = tcapbuf;
#endif
+ if (argc < 1)
+ usage();
(void)setlocale(LC_ALL, "");
/* Terminal defaults to -Cq, non-terminal defaults to -1. */
f_listdot = 1;
fts_options = FTS_PHYSICAL;
- while ((ch = getopt(argc, argv, "1ABCFGHLPRSTWabcdefghiklmnopqrstuvwx"))
+ while ((ch = getopt(argc, argv, "1@ABCFGHLOPRSTWabcdefghiklmnopqrstuvwx"))
!= -1) {
switch (ch) {
/*
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);
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;
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")) {
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;
case 'e':
f_acl = 1;
break;
+ case '@':
+ f_xattr = 1;
+ break;
+ case 'O':
+ f_flags = 1;
+ break;
default:
case '?':
usage();
* 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;
/*
{
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
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:
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");
}
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;
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;
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);
* 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;
* 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;
#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 */
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;
#include <sys/stat.h>
#ifdef __APPLE__
#include <sys/acl.h>
+#include <sys/xattr.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <signal.h>
#endif
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
#include "ls.h"
#include "extern.h"
#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 <sys/stat.h> */
typedef enum Colors {
{
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;
else if (f_nonprint)
return prn_printable(name);
else
- return printf("%s", name);
+ return prn_normal(name);
}
/*
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:
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, "<UNKNOWN>");
+ if (0 != mbr_uuid_to_string(*uu, name)) {
+ fprintf(stderr, "Unable to translate qualifier on ACL\n");
+ strcpy(name, "<UNKNOWN>");
+ }
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;
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;
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__ */
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__ */
}
}
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 ";
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);
}
-/*
+/*-
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* 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.
static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/2/94";
#endif /* not lint */
#endif
-#include <sys/types.h>
-__RCSID("$FreeBSD: src/bin/ls/util.c,v 1.30 2002/06/30 05:13:54 obrien Exp $");
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ls/util.c,v 1.38 2005/06/03 11:05:58 dd Exp $");
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <err.h>
#include <fts.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
#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);
}
/*
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
{
(void)fprintf(stderr,
#ifdef COLORLS
- "usage: ls [-ABCFGHLPRSTWZabcdefghiklmnopqrstuwx1]"
+ "usage: ls [-ABCFGHLPRSTWabcdefghiklmnopqrstuwx1]"
#else
- "usage: ls [-ABCFHLPRSTWZabcdefghiklmnopqrstuwx1]"
+ "usage: ls [-ABCFHLPRSTWabcdefghiklmnopqrstuwx1]"
#endif
" [file ...]\n");
exit(1);
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;
.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
.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 .
#include <sys/stat.h>
#include <unistd.h>
#include <err.h>
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
int main __P((int, char **));
static void usage __P((void));
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 */
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);
.Ar name
.Op Cm c | Cm b
.Ar number
+.Nm
+.Ar name
+.Ar w
.Sh DESCRIPTION
The
.Nm
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 .
argc -= optind;
argv += optind;
- if (argc < 3 || argc > 10)
+ if (argc < 2 || argc > 10)
usage();
name = *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);
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);
}
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)
* 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.
*
* 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobez Exp $");
#include <sys/param.h>
#include <sys/stat.h>
+#include <sys/time.h>
+
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
-#ifdef MD5
+#ifdef ENABLE_MD5
#include <md5.h>
#endif
-#ifdef SHA1
+#ifdef ENABLE_RMD160
+#include <ripemd.h>
+#endif
+#ifdef ENABLE_SHA1
#include <sha.h>
#endif
-#ifdef RMD160
-#include <ripemd.h>
+#ifdef ENABLE_SHA256
+#include <sha256.h>
#endif
+#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
+#include <vis.h>
+
#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++) { \
}
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;
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";
}
/*
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) {
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);
(void)printf("\n");
tab = "\t";
}
-#ifdef MD5
+#ifdef ENABLE_MD5
if (s->flags & F_MD5) {
char *new_digest, buf[33];
tab = "\t";
}
}
-#endif /* MD5 */
-#ifdef SHA1
+#endif /* ENABLE_MD5 */
+#ifdef ENABLE_SHA1
if (s->flags & F_SHA1) {
char *new_digest, buf[41];
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];
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:
/* NOTREACHED */
}
-static char *
-ftype(type)
- u_int type;
+const char *
+ftype(u_int type)
{
switch(type) {
case F_BLOCK:
}
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);
}
* 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.
*
* 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/create.c,v 1.37 2005/03/29 11:44:17 tobez Exp $");
#include <sys/param.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <fts.h>
#include <grp.h>
-#ifdef MD5
+#ifdef ENABLE_MD5
#include <md5.h>
#endif
-#ifdef SHA1
+#ifdef ENABLE_SHA1
#include <sha.h>
#endif
-#ifdef RMD160
+#ifdef ENABLE_RMD160
#include <ripemd.h>
#endif
+#ifdef ENABLE_SHA256
+#include <sha256.h>
+#endif
#include <pwd.h>
+#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#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;
}
(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;
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))
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);
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));
#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;
if ((p = fts_children(t, 0)) == NULL) {
if (errno)
- err(1, "line %d: %s", lineno, RP(parent));
+ err(1, "%s", RP(parent));
return (1);
}
*/
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;
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);
}
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))
return (strcmp((*a)->fts_name, (*b)->fts_name));
}
-#if __STDC__
#include <stdarg.h>
-#else
-#include <varargs.h>
-#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);
* 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
* 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/excludes.c,v 1.8 2003/10/21 08:27:05 phk Exp $");
#include <sys/types.h>
#include <sys/time.h> /* XXX for mtree.h */
#include <fnmatch.h>
#include <fts.h>
#include <stdio.h>
+#include <stdint.h>
#include <stdlib.h>
#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 {
#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;
}
* 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.
*
* 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
* 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.
*
* 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/misc.c,v 1.16 2005/03/29 11:44:17 tobez Exp $");
#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>
#include <fts.h>
+#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#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
{"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},
{"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),
}
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;
.\" 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.
.\" 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
.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
.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
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
.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.
.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
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.
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
* 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.
*
* SUCH DAMAGE.
*/
+#if 0
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1989, 1990, 1993\n\
#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 <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/mtree.c,v 1.29 2004/06/04 19:29:28 ru Exp $");
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <fts.h>
#include <stdio.h>
+#include <stdint.h>
#include <unistd.h>
#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;
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;
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;
case 'u':
uflag = 1;
break;
+ case 'w':
+ wflag = 1;
+ break;
case 'x':
ftsoptions |= FTS_XDEV;
break;
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);
}
* 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.
*
* 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 <string.h>
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 */
#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 */
* 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.
*
* 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/spec.c,v 1.22 2005/03/29 11:44:17 tobez Exp $");
#include <sys/types.h>
#include <sys/stat.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
+#include <stdint.h>
#include <unistd.h>
#include <vis.h>
#include "mtree.h"
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];
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')
#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) {
}
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;
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)
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);
}
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);
--- /dev/null
+/*-
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/specspec.c,v 1.6 2005/03/29 11:44:17 tobez Exp $");
+
+#include <sys/param.h>
+#include <err.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#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);
+}
* 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.
*
* 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/verify.c,v 1.24 2005/08/11 15:43:55 brian Exp $");
#include <sys/param.h>
#include <sys/stat.h>
#include <fts.h>
#include <fnmatch.h>
#include <stdio.h>
+#include <stdint.h>
#include <unistd.h>
#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);
}
(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))
/* 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
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)");
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",
.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
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
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
options.)
.It Fl v
Cause
-.Nm
+.Nm mv
to be verbose, showing files after they are moved.
.El
.Pp
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.
As the
.Xr rename 2
call does not work across file systems,
-.Nm
+.Nm mv
uses
.Xr cp 1
and
.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 ,
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 .
#include <sys/mount.h>
#endif
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
#include "pathnames.h"
int fflg, iflg, nflg, vflg;
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);
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) {
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);
*/
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;
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
-/* $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 $ */
/*-
* 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.
*
#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 */
#include <sys/ioctl.h>
#include <sys/mtio.h>
#include <sys/param.h>
+#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include <fcntl.h>
#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 "<STDOUT>" /* psuedo name for stdout */
-#define STDN "<STDIN>" /* psuedo name for stdin */
+#define STDO "<STDOUT>" /* pseudo name for stdout */
+#define STDN "<STDIN>" /* 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 */
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()
* -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;
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:
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
*/
/*
* 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
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;
break;
default:
/*
- * should never happen, worse case, slow...
+ * should never happen, worst case, slow...
*/
blksz = rdblksz = BLKMULT;
break;
* 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
*/
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);
}
/*
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;
* Print out a summary of I/O for this archive volume.
*/
if (vfpart) {
- (void)putc('\n', outf);
+ (void)putc('\n', listf);
vfpart = 0;
}
* 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;
}
* 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];
/*
* 0 if all ready to write, -1 otherwise
*/
-#ifdef __STDC__
int
ar_set_wr(void)
-#else
-int
-ar_set_wr()
-#endif
{
off_t cpos;
*/
wr_trail = 0;
- /*
+ /*
* Add any device dependent code as required here
*/
if (artyp != ISREG)
/*
* 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.");
* 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
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).
* 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;
/*
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
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;
/*
* 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).
* 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;
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
*/
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.
*/
/*
* 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:
* 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;
return(0);
/*
- * we cannot move foward at EOF or error
+ * we cannot move forward at EOF or error
*/
if (lstrval <= 0)
return(lstrval);
* Safer to read forward on devices where it is hard to find the end of
* the media without reading to it. With tapes we cannot be sure of the
* number of physical blocks to skip (we do not know physical block
- * size at this point), so we must only read foward on tapes!
+ * size at this point), so we must only read forward on tapes!
*/
if (artyp != ISREG)
return(0);
* 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;
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);
}
* 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
if (lstrval < 0)
return(lstrval);
- switch(artyp) {
+ switch (artyp) {
case ISPIPE:
if (sksz <= 0)
break;
/*
* 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.
*/
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);
/*
* 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...
* 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];
}
/*
- * 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)
* 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;
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);
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");
*/
if (ar_open(buf) >= 0) {
if (freeit) {
- (void)free(arcname);
+ (void)free((char *)arcname);
freeit = 0;
}
if ((arcname = strdup(buf)) == NULL) {
* 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 */
}
-/* $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 $ */
/*-
* 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.
*
#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 */
#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;
* (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;
* 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.
* 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;
* 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
/*
* 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
}
/*
- * 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))) {
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;
}
}
purg_lnk(arcn);
if (vflag && vfpart) {
- (void)putc('\n', stderr);
+ (void)putc('\n', listf);
vfpart = 0;
}
continue;
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)
#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
* 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__
*/
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
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;
#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);
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);
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;
}
}
}
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);
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)
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
* 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
* 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;
/*
* 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;
* 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;
}
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)
* 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
*/
* write a new archive
*/
-#ifdef __STDC__
void
archive(void)
-#else
-void
-archive()
-#endif
{
ARCHD archd;
* (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) {
/*
* 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;
while (next_file(arcn) == 0) {
fdsrc = -1;
+ /*
+ * Fill in arcn from any pax options
+ */
+ adjust_copy_for_pax_options(arcn);
+
/*
* check if this file meets user specified options
*/
/*
* 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
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)
}
/*
- * 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))) {
}
if (vflag) {
- (void)fputs(arcn->name, stderr);
+ (void)safe_print(arcn->name, listf);
vfpart = 1;
}
++flcnt;
res = chk_same(arcn);
if (res <= 0) {
if (vflag && vfpart) {
- (void)putc('\n', stderr);
+ (void)putc('\n', listf);
vfpart = 0;
}
continue;
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;
* 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
}
/*
* 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. */
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)
/*
* 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
*/
* 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
*/
* 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;
res = BLKMULT;
hdsz = 0;
hdend = hdbuf;
- for(;;) {
+ for (;;) {
for (;;) {
/*
* fill the buffer with at least the smallest header
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
-/* $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 $ */
/*-
* 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.
*
#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 */
* 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]);
/*
}
/*
- * 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))
* 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
}
if (wrblksz % BLKMULT) {
paxwarn(1, "Write block size %d is not a %d byte multiple",
- wrblksz, BLKMULT);
+ wrblksz, BLKMULT);
return(-1);
}
}
* 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;
* 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
* 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) {
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
* 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...
* 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);
/*
* 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.
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);
* 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
* -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
/*
* 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)
/*
* 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
* 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
* 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;
/*
* 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
/*
* 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))
* 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;
/*
* read the source file and copy to destination file until EOF
*/
- for(;;) {
+ for (;;) {
if ((cnt = read(fd1, buf, blksz)) <= 0)
break;
if (no_hole)
/*
* 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))
* 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.
* 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.
*/
-/* $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 $ */
/*-
* 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.
*
#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 */
/*
* 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;
/*
* 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;
/*
* 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;
/*
* 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;
* 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
++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 {
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);
}
* 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("");
/*
* 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
++gropn;
}
if (ptr == NULL)
- ptr = (GIDC *)malloc(sizeof(GIDC));
+ ptr = gidtb[gid % GID_SZ] = malloc(sizeof(GIDC));
if ((gr = getgrgid(gid)) == NULL) {
/*
return("");
ptr->gid = gid;
ptr->valid = INVALID;
-# ifdef NET2_STAT
- (void)snprintf(ptr->name, sizeof(ptr->name), "%u", gid);
-# else
(void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
(unsigned long)gid);
-# endif
- gidtb[hash] = ptr;
if (frc == 0)
return("");
} else {
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);
}
* 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
* 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);
}
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,
*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);
* 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
* 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);
++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,
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);
-/* $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 $ */
/*-
* 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.
*
* 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
+.\" $OpenBSD: cpio.1,v 1.20 2003/11/21 20:54:02 jmc Exp $
.\"
.\" Copyright (c) 1997 SigmaSoft, Th. Lockert
.\" All rights reserved.
.\" 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
.\" (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
.Nm cpio
.Nd copy file archives in and out
.Sh SYNOPSIS
-.Nm
+.Nm cpio
.Fl o
.Op Fl aABcLvzZ
.Op Fl C Ar bytes
.Op Fl O Ar archive
.Ar "< name-list"
.Op Ar "> archive"
-.Nm
+.Nm cpio
.Fl i
.Op Fl bBcdfmrsStuvzZ6
.Op Fl C Ar bytes
.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
.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.
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
.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
-/* $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 $ */
/*-
* 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.
*
#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 */
#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
* 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());
}
* 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
* 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;
* 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;
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));
}
* 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
* 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
* 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))
* 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
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
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));
* 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)));
}
* 0 if ok, -1 otherwise (what dev_start() returns)
*/
-#ifdef __STDC__
int
cpio_stwr(void)
-#else
-int
-cpio_stwr()
-#endif
{
return(dev_start());
}
* 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)];
/*
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
/*
* 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))
* 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))
* 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());
* 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
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
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);
* 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)))));
* 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());
* 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)];
*/
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:
* 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
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),
* 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);
* 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
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));
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);
* 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)))));
* 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;
arcn->sb.st_rdev = 0;
hd = (HD_BCPIO *)hdblk;
- switch(arcn->type) {
+ switch (arcn->type) {
case PAX_CTG:
case PAX_REG:
case PAX_HRG:
-/* $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 $ */
/*-
* 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.
*
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 */
#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
u_char h_namesize[2];
u_char h_filesize_1[2];
u_char h_filesize_2[2];
-} HD_BCPIO;
+} HD_BCPIO;
#ifdef _PAX_
/*
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 */
-/* $OpenBSD: extern.h,v 1.14 1997/07/24 23:19:18 millert Exp $ */
+/* $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 $ */
/*-
* 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.
*
/*
* 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));
+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 __P((void));
-void extract __P((void));
-void append __P((void));
-void archive __P((void));
-void copy __P((void));
+void list(void);
+void extract(void);
+void append(void);
+void archive(void);
+void copy(void);
/*
* buf_subs.c
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));
+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 __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 *));
+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 __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 *));
+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
*/
-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));
+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 __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 *));
+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 __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));
+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 __P((int, char **, char *));
+int getoldopt(int, char **, const 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));
+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 __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));
+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 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 zeroflag;
extern int vfpart;
extern int patime;
extern int pmtime;
extern char *dirptr;
extern char *ltmfrmt;
extern char *argv0;
-int main __P((int, char **));
-void sig_cleanup __P((int));
+extern FILE *listf;
+extern char *tempfile;
+extern char *tempbase;
+
+int main(int, char **);
+void sig_cleanup(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 *));
+int sel_chk(ARCHD *);
+int grp_add(char *);
+int usr_add(char *);
+int trng_add(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));
+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
*/
-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 *));
+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 __P((void));
-void tty_prnt __P((char *, ...));
-int tty_read __P((char *, int));
-void paxwarn __P((int, char *, ...));
-void syswarn __P((int, int, char *, ...));
+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 *, ...);
-/* $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 $ */
/*-
* 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.
*
#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 <sys/types.h>
+#include <sys/param.h>
#include <sys/time.h>
#include <sys/stat.h>
-#include <unistd.h>
-#include <sys/param.h>
+#include <sys/uio.h>
+#include <err.h>
+#include <errno.h>
#include <fcntl.h>
-#include <string.h>
#include <stdio.h>
-#include <errno.h>
-#include <sys/uio.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#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;
* 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.
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);
}
* 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;
/*
* 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);
/*
* 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;
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));
}
* 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));
}
* 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
*/
* 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;
*/
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);
}
/*
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,
* 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
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:
/*
*/
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:
* we should never get here
*/
paxwarn(0, "%s has an unknown file type, skipping",
- arcn->name);
+ nm);
return(-1);
}
* 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);
}
}
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.
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) {
/*
* 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
* 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;
* 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);
}
* 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;
* 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;
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)
*/
if (lstat(name, &sb) == 0) {
*(spt++) = '/';
- continue;
+ if (new_name==NULL) continue;
+ retval = 0; /* accept it one directory at a time */
+ break;
}
/*
(void)set_ids(name, st_uid, st_gid);
/*
- * make sure the user doen't have some strange umask that
+ * make sure the user doesn't have some strange umask that
* causes this newly created directory to be unusable. We fix
* the modes and restore them back to the creation default at
* the end of pax
if ((access(name, R_OK | W_OK | X_OK) < 0) &&
(lstat(name, &sb) == 0)) {
set_pmode(name, ((sb.st_mode & FILEBITS) | S_IRWXU));
- 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;
/*
* 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;
}
* 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) {
/*
#if !defined(__APPLE__)
/* Mac OS X doesn't have lchown */
-
/*
* set_lids()
* set the uid and gid of a file system node
* 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) {
/*
* 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)
* 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
* 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
/*
* 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);
/*
* 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);
}
* 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";
* 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
* 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;
* 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;
/*
* 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);
-/* $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 $ */
/*-
* 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.
*
#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 */
* 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 */
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()
* 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
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;
* 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);
}
* -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
* 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.
* stdin).
*/
-#ifdef __STDC__
static int
ftree_arg(void)
-#else
-static int
-ftree_arg()
-#endif
{
- register char *pt;
/*
* close off the current file tree
* 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;
* 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.
* 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) {
/*
* 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
/*
* 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
* 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;
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;
}
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
* 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)
}
/*
* 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;
/*
* 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);
+}
-/* $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 $ */
/*-
* 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.
*
-/* $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 $ */
/*-
* 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.
*
#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 */
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
+#include <vis.h>
#include "pax.h"
#include "extern.h"
#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);
/*
* 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);
+ }
}
/*
* 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;
break;
}
} else {
- while ((str < stop) && (*str >= '0') && (*str <= '7'))
+ while ((str < stop) && (*str >= '0') && (*str <= '7'))
tval = (tval << 3) + (*str++ - '0');
}
return(tval);
* 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;
/*
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
* 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;
break;
}
} else {
- while ((str < stop) && (*str >= '0') && (*str <= '7'))
+ while ((str < stop) && (*str >= '0') && (*str <= '7'))
tval = (tval << 3) + (*str++ - '0');
}
return(tval);
* 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;
/*
-/* $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 $ */
/*
* 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 <sys/types.h>
+#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#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;
optarg = NULL;
if (key == NULL) { /* First time */
- if (argc < 2) return EOF;
+ if (argc < 2)
+ return (-1);
key = argv[1];
if (*key == '-')
use_getopt++;
}
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++;
} else {
fprintf(stderr, "%s: %c argument missing\n",
argv[0], c);
- return('?');
+ return ('?');
}
}
- return(c);
+ return (c);
}
-/* $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 $ */
/*-
* 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.
*
#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 */
#include <stdlib.h>
#include <limits.h>
#include <paths.h>
+#include <search.h>
#include "pax.h"
#include "options.h"
#include "cpio.h"
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 */
{"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()
* 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)
{
/*
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);
}
/*
* 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':
/*
/*
* 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;
* pass format specific options
*/
flg |= OF;
- if (opt_add(optarg) < 0)
+ if (pax_format_opt_add(optarg) < 0)
pax_usage();
break;
case 'p':
* specify file characteristic options
*/
for (pt = optarg; *pt != '\0'; ++pt) {
- switch(*pt) {
+ switch (*pt) {
case 'a':
/*
* do not preserve access time
break;
case 'p':
/*
- * preserver file mode bits
+ * preserve file mode bits
*/
pmode = 1;
break;
/*
* read the archive
*/
+ pax_read_or_list_mode=1;
flg |= RF;
break;
case 's':
* 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;
}
/*
* use gzip. Non standard option.
*/
- zflag = 1;
gzip_program = GZIP_CMD;
break;
case 'B':
*/
Hflag = 1;
flg |= CHF;
+ Lflag = 0; /* -H and -L are mutually exclusive */
+ flg &= ~CLF; /* only use the last one seen */
break;
case 'L':
/*
*/
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':
/*
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;
}
}
+ /*
+ * 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
*/
if (ISLIST(flg)) {
act = LIST;
+ pax_read_or_list_mode=1;
+ listf = stdout;
bflg = flg & BDLIST;
} else if (ISEXTRACT(flg)) {
act = EXTRACT;
if (!(flg & XF) && (act == ARCHIVE))
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
*/
* 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.
* 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
*/
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':
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':
*/
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
/*
* use compress.
*/
- zflag = 1;
gzip_program = COMPRESS_CMD;
break;
case '0':
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
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)
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!
}
}
+int mkpath(char *);
+
int
mkpath(path)
char *path;
{
struct stat sb;
- register char *slash;
+ char *slash;
int done = 0;
slash = 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;
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':
/*
* list contents of archive
*/
act = LIST;
+ listf = stdout;
break;
case 'u':
/*
* replace newer files
*/
- kflag = 0;
+ uflag = 0;
break;
case 'v':
/*
/*
* use gzip. Non standard option.
*/
- zflag = 1;
gzip_program = GZIP_CMD;
break;
case 'A':
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':
* 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);
/*
* use compress. Non standard option.
*/
- zflag = 1;
gzip_program = COMPRESS_CMD;
break;
case '6':
* 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:
* 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;
* 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));
}
* pointer to next OPLIST entry or NULL (end of list).
*/
-#ifdef __STDC__
OPLIST *
opt_next(void)
-#else
-OPLIST *
-opt_next()
-#endif
{
OPLIST *opt;
* 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);
* 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);
}
* 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");
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;
* 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
# endif
return(0);
- switch(*expr) {
+ switch (*expr) {
case 'b':
t = num;
num *= 512;
break;
}
- switch(*expr) {
+ switch (*expr) {
case '\0':
break;
case '*':
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.
* 0
*/
-#ifdef __STDC__
static int
no_op(void)
-#else
-static int
-no_op()
-#endif
{
return(0);
}
* 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);
* 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);
}
* 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);
-/* $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 $ */
/*-
* 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.
*
#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
#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)
-/* $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 $ */
/*-
* 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.
*
#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 */
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
-#ifdef NET2_REGEX
-#include <regexp.h>
-#else
#include <regex.h>
-#endif
#include "pax.h"
#include "pat_rep.h"
#include "extern.h"
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
* 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
* 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);
}
}
*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);
}
* 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);
* set the options if any
*/
while (*pt2 != '\0') {
- switch(*pt2) {
+ switch (*pt2) {
case 'g':
case 'G':
rep->flgs |= GLOB;
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);
* 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
* 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,
*
* 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
/*
* 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
* 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.
*/
/*
* should never happen....
*/
- paxwarn(1, "Pattern list inconsistant");
+ paxwarn(1, "Pattern list inconsistent");
return(-1);
}
*ppt = pt->fow;
* 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;
/*
* 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;
case '*':
c = *pattern;
/*
- * Collapse multiple *'s.
+ * Collapse multiple *'s.
*/
while (c == '*')
c = *++pattern;
/* 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;
* 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.
* 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);
}
* 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;
*/
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);
* 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);
* 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;
/*
*or_len = len;
/*
- * enough space, shift
+ * enough space, shift
*/
while (src >= start)
*dest-- = *src--;
* --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.
* 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 */
* (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;
*/
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;
/*
* 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++;
* 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);
* 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;
*/
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;
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;
}
* 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
-/* $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 $ */
/*-
* 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.
*
*/
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 */
+.\" $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.
.\" 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.
.\"
.\" 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
.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
.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
.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
.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
.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
.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.
and the
.Fl w
options specifies which of the following functional modes
-.Nm
+.Nm pax
will operate under:
.Em list , read , write ,
and
.Bl -tag -width 6n
.It <none>
.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.
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
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.
.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
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
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
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
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
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.
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
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
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 <EOF>
+.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
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
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=<pattern>
+.It
+exthdr.name=<string>
+.It
+globexhdr.name=<string>
+.It
+invalid=<action> for actions
+bypass, rename, utf-8 (recognized, but ignored), and write
+.It
+linkdata
+.It
+listopt=<format>
+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
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.
.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.
.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 )
.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
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
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 <newline>
-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.
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
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 <original pathname> >> <new pathname>
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.
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
.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 <newline>
+.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 <newline> ,
-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
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 ,
.Fl U ,
.Fl Y ,
and
-.Fl Z )
+.Fl Z
+.Pc
interact as follows.
.Pp
When extracting files during a
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
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
.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.
.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.
-/* $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 $ */
/*-
* 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.
*
*/
#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 */
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
+#include <err.h>
#include <fcntl.h>
+#include <paths.h>
#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
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 */
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):
*
*
* 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.
* 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
* -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
* 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.
* 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.
* 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.
*/
return(exit_val);
}
+ /*
+ * 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
*/
return(exit_val);
/*
- * select a primary operation mode
+ * select a primary operation mode
*/
- switch(act) {
+ switch (act) {
case EXTRACT:
extract();
break;
archive();
break;
case APPND:
+ if (gzip_program != NULL)
+ errx(1, "can not gzip while appending");
append();
break;
case COPY:
* 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
* 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;
/*
* 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) ||
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;
-/* $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 $ */
/*-
* 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.
*
/* 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 */
/*
#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 */
#define ISTAPE 3 /* tape drive */
#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).
*/
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) */
/* 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 */
/* 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
*
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)
/*
* General Defines
*/
-#define HEX 16
-#define OCT 8
-#define _PAX_ 1
+#define HEX 16
+#define OCT 8
+#define _PAX_ 1
+#define _TFILE_BASE "paxXXXXXXXXXX"
--- /dev/null
+/* $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 <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "extern.h"
+#include "tar.h"
+#include <fnmatch.h>
+#include <regex.h>
+#include "pat_rep.h"
+#include <errno.h>
+
+/*
+ * 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);
+}
-/* $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 $ */
/*-
* 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.
*
#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 */
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/param.h>
-#include <pwd.h>
+#include <ctype.h>
#include <grp.h>
+#include <pwd.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <tzfile.h>
#include <unistd.h>
-#include <stdlib.h>
#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 */
/*
* 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)) ||
* 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 #.
*/
/*
* 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
}
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();
/*
* 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
* 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
}
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();
/*
* 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
* 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
}
/*
- * 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'))
else {
pt->flgs = 0;
while (*flgpt != '\0') {
- switch(*flgpt) {
+ switch (*flgpt) {
case 'M':
case 'm':
pt->flgs |= CMPMTME;
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);
}
* 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.
*/
pt = trhead;
while (pt != NULL) {
- switch(pt->flgs & CMPBOTH) {
+ switch (pt->flgs & CMPBOTH) {
case CMPBOTH:
/*
* user wants both mtime and ctime checked for this
/*
* 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);
-/* $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 $ */
/*-
* 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.
*
* 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 */
-/* $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 $ */
/*-
* 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.
*
#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 */
* 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.
*/
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
* 0 if created, -1 if failure
*/
-#ifdef __STDC__
int
lnk_start(void)
-#else
-int
-lnk_start()
-#endif
{
if (ltab != NULL)
return(0);
* 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);
if ((arcn->type == PAX_DIR) || (arcn->sb.st_nlink <= 1))
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
*/
* 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
* 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;
* 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;
* 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.
*/
* 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);
* 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);
}
* -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];
/*
* 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
* 0 if successful, -1 otherwise
*/
-#ifdef __STDC__
int
name_start(void)
-#else
-int
-name_start()
-#endif
{
if (ntab != NULL)
return(0);
* 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);
}
* 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;
* 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;
* 0 if successful, -1 otherwise
*/
-#ifdef __STDC__
int
dev_start(void)
-#else
-int
-dev_start()
-#endif
{
if (dtab != NULL)
return(0);
* 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);
* 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
* 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);
* 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;
/*
* 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
* 0 is created ok, -1 otherwise.
*/
-#ifdef __STDC__
int
atdir_start(void)
-#else
-int
-atdir_start()
-#endif
{
if (atab != NULL)
return(0);
* 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;
* 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;
* 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) {
* 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);
* 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);
}
/*
* 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;
}
/*
* 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;
}
/*
* 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;
/*
-/* $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 $ */
/*-
* 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.
*
/*
* 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 */
#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
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;
* 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
* 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;
-/* $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 $ */
/*-
* 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.
*
#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 */
* 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()
* 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)));
}
* size of trailer (2 * BLKMULT)
*/
-#ifdef __STDC__
off_t
tar_endrd(void)
-#else
-off_t
-tar_endrd()
-#endif
{
return((off_t)(NULLCNT*BLKMULT));
}
* 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
* 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;
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
* 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;
/*
* 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
* 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);
return(-1);
if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
return(-1);
+ force_one_volume = 1;
return(0);
}
* 0 if ok -1 otherwise
*/
-#ifdef __STDC__
int
tar_opt(void)
-#else
-int
-tar_opt()
-#endif
{
OPLIST *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;
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:
*/
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
*/
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;
- arcn->ln_name[0] = '\0';
- arcn->ln_nlen = 0;
break;
case AREGTYPE:
case REGTYPE:
} 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;
* strip off any trailing slash.
*/
if (*pt == '/') {
- *pt = '\0';
+ *pt = '\0';
--arcn->nlen;
}
return(0);
* 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
}
/*
- * 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;
* 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)) {
* 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 {
* 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
* 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);
* 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);
* 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);
* 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;
*/
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;
/*
*/
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
*/
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;
/*
* 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;
/*
* 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;
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:
* 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
* 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);
}
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
* 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:
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:
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:
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);
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
* 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);
return(1);
out:
- /*
+ /*
* header field is out of range
*/
paxwarn(1, "Ustar header field is too small for %s", arcn->org_name);
* 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;
*/
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);
+}
-/* $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 $ */
/*-
* 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.
*
#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
*/
-/* $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 $ */
/*-
* 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.
*
#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 */
#include <string.h>
#include "pax.h"
#include "extern.h"
-#ifdef __STDC__
#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
/*
* routines that deal with I/O to and from the user
/*
* 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;
* 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);
* 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);
* 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;
}
* 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;
/*
* line by itself
*/
if (vflag && vfpart) {
+ (void)fflush(listf);
(void)fputc('\n', stderr);
vfpart = 0;
}
* format and print the errno
*/
if (errnum > 0)
- (void)fprintf(stderr, " <%s>", strerror(errnum));
+ (void)fprintf(stderr, ": %s", strerror(errnum));
(void)fputc('\n', stderr);
}
#include <unistd.h>
#ifdef __APPLE__
+#include <pwd.h>
+#include <grp.h>
#include "get_compat.h"
#else
#define COMPAT_MODE(func, mode) 1
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
}
if (errno)
err(1, "fts_read");
+ fts_close(fts);
}
void
.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
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble stat.1
+OTHER_CFLAGS = -D__FBSDID=__RCSID
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
.\" 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
.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
.Pp
The options are as follows:
.Bl -tag -width indent
+.\" ==========
.It Fl F
As in
.Xr ls 1 ,
.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
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
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
to
.Pa / ,
you would use
-.Nm
+.Nm stat
as follows:
.Bd -literal -offset indent
\*[Gt] stat -F /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 .
#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 */
#include <time.h>
#include <unistd.h>
+#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 "
#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" \
#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'
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);
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);
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;
+++ /dev/null
-#
-# Generated by the NeXT Project Builder.
-#
-# NOTE: Do NOT change this file -- Project Builder maintains it.
-#
-# Put all of your customizations in files called Makefile.preamble
-# and Makefile.postamble (both optional), and Makefile will include them.
-#
-
-NAME = tcopy
-
-PROJECTVERSION = 2.8
-PROJECT_TYPE = Tool
-
-CFILES = tcopy.c
-
-OTHERSRCS = Makefile Makefile.preamble Makefile.postamble tcopy.1
-
-
-MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
-CODE_GEN_STYLE = DYNAMIC
-MAKEFILE = tool.make
-NEXTSTEP_INSTALLDIR = /usr/bin
-LIBS =
-DEBUG_LIBS = $(LIBS)
-PROF_LIBS = $(LIBS)
-
-
-
-
-NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/developer_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
-
-include $(MAKEFILEDIR)/platform.make
-
--include Makefile.preamble
-
-include $(MAKEFILEDIR)/$(MAKEFILE)
-
--include Makefile.postamble
-
--include Makefile.dependencies
+++ /dev/null
-include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
+++ /dev/null
-include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
+++ /dev/null
-{
- DYNAMIC_CODE_GEN = YES;
- FILESTABLE = {
- FRAMEWORKS = ();
- OTHER_LINKED = (tcopy.c);
- OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, tcopy.1);
- };
- LANGUAGE = English;
- LOCALIZABLE_FILES = {};
- MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
- NEXTSTEP_BUILDDIR = /tmp/developer_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_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
- PROJECTNAME = tcopy;
- PROJECTTYPE = Tool;
- PROJECTVERSION = 2.8;
- WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
- WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
- WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
-}
+++ /dev/null
-.\" 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
+++ /dev/null
-/*
- * 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 <sys/cdefs.h>
-
-#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 <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/mtio.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <paths.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#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);
-}
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);
}