-/* $OpenBSD: options.c,v 1.34 1998/09/20 02:22:22 millert Exp $ */
+/* $OpenBSD: options.c,v 1.70 2008/06/11 00:49:08 pvalchev 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[] = "$OpenBSD: options.c,v 1.34 1998/09/20 02:22:22 millert Exp $";
+static const char rcsid[] = "$OpenBSD: options.c,v 1.70 2008/06/11 00:49:08 pvalchev Exp $";
#endif
#endif /* not lint */
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 *bsd_getline(FILE *fp);
+static void pax_options(int, char **);
+static void pax_usage(void);
+static void tar_options(int, char **);
+static void tar_usage(void);
+static void cpio_options(int, char **);
+static void cpio_usage(void);
+
+/* errors from getline */
+#define GETLINE_FILE_CORRUPT 1
+#define GETLINE_OUT_OF_MEM 2
+static int getline_error;
+
#define GZIP_CMD "gzip" /* command to run as gzip */
#define COMPRESS_CMD "compress" /* command to run as compress */
/*
* 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 };
+/*
+ * Do we have -C anywhere?
+ */
+int havechd = 0;
+
/*
* options()
* figure out if we are pax, tar or cpio. Call the appropriate 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;
/*
* process option flags
*/
- while ((c=getopt(argc,argv,"ab:cdf:ijklno:p:rs:tuvwx:zB:DE:G:HLPT:U:XYZ"))
- != EOF) {
+ while ((c=getopt(argc,argv,"ab:cdf:ijklno:p:rs:tuvwx:zB:DE:G:HLOPT:U:XYZ0"))
+ != -1) {
switch (c) {
case 'a':
/*
/*
* use bzip2. Non standard option.
*/
- zflag = 1;
gzip_program = BZIP2_CMD;
break;
case 'k':
* 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;
/*
* use gzip. Non standard option.
*/
- zflag = 1;
gzip_program = GZIP_CMD;
break;
case 'B':
Lflag = 1;
flg |= CLF;
break;
+ case 'O':
+ /*
+ * Force one volume. Non standard option.
+ */
+ force_one_volume = 1;
+ break;
case 'P':
/*
* do NOT follow symlinks (default)
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;
* 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:hjmopruts:vwxzBC:HLOPXZ014578"))
- != EOF) {
- switch(c) {
+ "b:cef:hjmopqruts:vwxzBC:HI:LOPXZ014578")) != -1) {
+ switch (c) {
case 'b':
/*
* specify blocksize in 512-byte blocks
/*
* use bzip2. Non standard option.
*/
- zflag = 1;
gzip_program = BZIP2_CMD;
break;
case 'm':
*/
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 uid/gid and file mode, regardless of umask
pmode = 1;
pids = 1;
break;
+ case 'q':
+ /*
+ * select first match for a pattern only
+ */
+ nflag = 1;
+ break;
case 'r':
case 'u':
/*
/*
* use gzip. Non standard option.
*/
- zflag = 1;
gzip_program = GZIP_CMD;
break;
case 'B':
*/
break;
case 'C':
+ havechd++;
chdname = optarg;
break;
case 'H':
*/
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':
else
listf = stdout;
- /* Traditional tar behaviour (pax wants to read filelist from stdin) */
- if ((act == ARCHIVE || act == APPND) && argc == 0)
+ /* Traditional tar behaviour (pax wants to read file list from stdin) */
+ if ((act == ARCHIVE || act == APPND) && argc == 0 && nincfiles == 0)
exit(0);
- /*
- * if we are writing (ARCHIVE) specify tar, otherwise run like pax
- * (unless -o specified)
- */
- if (act == ARCHIVE || act == APPND)
- frmt = &(fsub[Oflag ? F_OTAR : F_TAR]);
- else if (Oflag) {
- paxwarn(1, "The -O/-o options are only valid when writing an archive");
- tar_usage(); /* only valid when writing */
- }
-
/*
* process the args as they are interpreted by the operation mode
*/
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 = bsd_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)
+ havechd++;
+ } 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 = bsd_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();
- }
+ havechd++;
+ } 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;
dflag = 1;
act = -1;
nodirs = 1;
- while ((c=getopt(argc,argv,"abcdfijklmoprstuvzABC:E:F:H:I:LO:SZ6")) != EOF)
+ while ((c=getopt(argc,argv,"abcdfijklmoprstuvzABC:E:F:H:I:LO:SZ6")) != -1)
switch (c) {
case 'a':
/*
/*
* use bzip2. Non standard option.
*/
- zflag = 1;
gzip_program = BZIP2_CMD;
break;
case 'k':
/*
* 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 = bsd_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':
/*
* 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 = bsd_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);
* 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
-int
-opt_add(str)
- register char *str;
-#endif
+opt_add(const char *str)
{
- register OPLIST *opt;
- register char *frpt;
- register char *pt;
- register char *endpt;
+ OPLIST *opt;
+ char *frpt;
+ char *pt;
+ char *endpt;
+ char *dstr;
if ((str == NULL) || (*str == '\0')) {
paxwarn(0, "Invalid option name");
return(-1);
}
- if ((str = strdup(str)) == NULL) {
+ if ((dstr = strdup(str)) == NULL) {
paxwarn(0, "Unable to allocate space for option list");
return(-1);
}
- frpt = endpt = str;
+ frpt = endpt = dstr;
/*
* break into name and values pieces and stuff each one into a
*endpt = '\0';
if ((pt = strchr(frpt, '=')) == NULL) {
paxwarn(0, "Invalid options format");
- free(str);
+ free(dstr);
return(-1);
}
if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) {
paxwarn(0, "Unable to allocate space for option list");
- free(str);
+ free(dstr);
return(-1);
}
*pt++ = '\0';
* 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
num = strtoq(val, &expr, 0);
- if ((num == QUAD_MAX) || (num <= 0) || (expr == val))
+ if ((num == LLONG_MAX) || (num <= 0) || (expr == val))
# 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 *
+bsd_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 [-cdjnvz] [-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 [-cdijknuvzDYZ] [-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 [-dijtuvzHLPX] [-b blocksize] ", stderr);
- (void)fputs("[ [-a] [-f archive] ] [-x format] \n", stderr);
- (void)fputs(" [-B bytes] [-s replstr] ... ", stderr);
- (void)fputs("[-o options] ... [-U user] ...", stderr);
- (void)fputs("\n [-G group] ... ", stderr);
- (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
- (void)fputs("[file ...]\n", stderr);
- (void)fputs(" pax -r -w [-diklntuvDHLPXYZ] ", stderr);
- (void)fputs("[-p string] ... [-s replstr] ...", stderr);
- (void)fputs("\n [-U user] ... [-G group] ... ", stderr);
- (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
- (void)fputs("\n [file ...] directory\n", stderr);
+ (void)fputs(
+ "usage: pax [-0cdjnOvz] [-E limit] [-f archive] [-G group] [-s replstr]\n"
+ " [-T range] [-U user] [pattern ...]\n"
+ " pax -r [-0cDdijknOuvYZz] [-E limit] [-f archive] [-G group] [-o options]\n"
+ " [-p string] [-s replstr] [-T range] [-U user] [pattern ...]\n"
+ " pax -w [-0adHijLOPtuvXz] [-B bytes] [-b blocksize] [-f archive]\n"
+ " [-G group] [-o options] [-s replstr] [-T range] [-U user]\n"
+ " [-x format] [file ...]\n"
+ " pax -rw [-0DdHikLlnOPtuvXYZ] [-G group] [-p string] [-s replstr]\n"
+ " [-T range] [-U user] [file ...] directory\n",
+ stderr);
exit(1);
}
* print the usage summary to the user
*/
-#ifdef __STDC__
void
tar_usage(void)
-#else
-void
-tar_usage()
-#endif
{
- (void)fputs("usage: tar -{txru}[cevfbjmopswzBHLPXZ014578] [tapefile] ",
- stderr);
- (void)fputs("[blocksize] [replstr] [-C directory] file1 file2...\n",
+ (void)fputs(
+ "usage: tar {crtux}[014578befHhjLmOoPpqsvwXZz]\n"
+ " [blocking-factor | archive | replstr] [-C directory] [-I file]\n"
+ " [file ...]\n"
+ " tar {-crtux} [-014578eHhjLmOoPpqvwXZz] [-b blocking-factor]\n"
+ " [-C directory] [-f archive] [-I file] [-s replstr] [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 [-aABcjLvVzZ] [-C bytes] [-H format] [-O archive]\n", stderr);
- (void)fputs(" [-F archive] < name-list [> archive]\n", stderr);
- (void)fputs(" cpio -i [-bBcdfjmnrsStuvVzZ6] [-C bytes] [-E file] [-H format]\n", stderr);
- (void)fputs(" [-I archive] [-F archive] [pattern...] [< archive]\n", stderr);
- (void)fputs(" cpio -p [-adlLmuvV] destination-directory < name-list\n", stderr);
+ (void)fputs(
+ "usage: cpio -o [-AaBcjLvZz] [-C bytes] [-F archive] [-H format]\n"
+ " [-O archive] < name-list [> archive]\n"
+ " cpio -i [-6BbcdfjmrSstuvZz] [-C bytes] [-E file] [-F archive] [-H format]\n"
+ " [-I archive] [pattern ...] [< archive]\n"
+ " cpio -p [-adLlmuv] destination-directory < name-list\n",
+ stderr);
exit(1);
}