static void tar_options(int argc, char **argv) { int c; int fstdin = 0; int Oflag = 0; int nincfiles = 0; int incfiles_max = 0; struct incfile { char *file; char *dir; }; struct incfile *incfiles = NULL; /* * Set default values. */ rmleadslash = 1; is_gnutar = 1; /* * process option flags */ while ((c = getoldopt(argc, argv, "+b:cef:hjklmopqrs:tuvwxzBC:HI:JOPST:X:Z014578", tar_longopts, NULL)) != -1) { switch(c) { case 'b': /* * specify blocksize in 512-byte blocks */ if ((wrblksz = (int)str_offt(optarg)) <= 0) { tty_warn(1, "Invalid block size %s", optarg); tar_usage(); } wrblksz *= 512; /* XXX - check for int oflow */ break; case 'c': /* * create an archive */ tar_set_action(ARCHIVE); break; case 'e': /* * stop after first error */ maxflt = 0; break; case 'f': /* * filename where the archive is stored */ if ((optarg[0] == '-') && (optarg[1]== '\0')) { /* * treat a - as stdin */ fstdin = 1; arcname = NULL; break; } fstdin = 0; arcname = optarg; break; case 'h': /* * follow symlinks */ Lflag = 1; break; case 'j': /* * pass through bzip2. not a standard option */ gzip_program = BZIP2_CMD; break; case 'k': /* * do not clobber files that exist */ kflag = 1; break; case 'l': /* * do not pass over mount points in the file system */ Xflag = 1; break; case 'm': /* * do not preserve modification time */ pmtime = 0; break; case 'o': /* * This option does several things based on whether * this is a create or extract operation. */ if (act == ARCHIVE) { /* GNU tar: write V7 format archives. */ Oflag = 1; /* 4.2BSD: don't add directory entries. */ if (opt_add("write_opt=nodir") < 0) tar_usage(); } else { /* SUS: don't preserve owner/group. */ pids = 0; nopids = 1; } break; case 'p': /* * preserve user id, group id, file * mode, access/modification times */ if (!nopids) pids = 1; pmode = 1; patime = 1; pmtime = 1; break; case 'q': /* * select first match for a pattern only */ nflag = 1; break; case 'r': case 'u': /* * append to the archive */ tar_set_action(APPND); break; case 's': /* * file name substitution name pattern */ if (rep_add(optarg) < 0) { tar_usage(); break; } break; case 't': /* * list contents of the tape */ tar_set_action(LIST); break; case 'v': /* * verbose operation mode */ vflag = 1; break; case 'w': /* * interactive file rename */ iflag = 1; break; case 'x': /* * extract an archive, preserving mode, * and mtime if possible. */ tar_set_action(EXTRACT); pmtime = 1; break; case 'z': /* * use gzip. Non standard option. */ gzip_program = GZIP_CMD; break; case 'B': /* * Nothing to do here, this is pax default */ break; case 'C': havechd++; chdname = optarg; break; case 'H': /* * follow command line symlinks only */ Hflag = 1; break; case 'I': case 'T': if (++nincfiles > incfiles_max) { incfiles_max = nincfiles + 3; incfiles = realloc(incfiles, sizeof(*incfiles) * incfiles_max); if (incfiles == NULL) { tty_warn(0, "Unable to allocate space " "for option list"); exit(1); } } incfiles[nincfiles - 1].file = optarg; incfiles[nincfiles - 1].dir = chdname; break; case 'J': gzip_program = XZ_CMD; break; case 'O': Oflag = 1; break; case 'P': /* * do not remove leading '/' from pathnames */ rmleadslash = 0; Aflag = 1; break; case 'S': /* do nothing; we already generate sparse files */ break; case 'V': /* * semi-verbose operation mode (no listing) */ Vflag = 1; break; case 'X': /* * GNU tar compat: exclude the files listed in optarg */ if (tar_gnutar_X_compat(optarg) != 0) tar_usage(); break; case 'Z': /* * use compress. */ gzip_program = COMPRESS_CMD; break; case '0': arcname = DEV_0; break; case '1': arcname = DEV_1; break; case '4': arcname = DEV_4; break; case '5': arcname = DEV_5; break; case '7': arcname = DEV_7; break; case '8': arcname = DEV_8; break; case OPT_ATIME_PRESERVE: patime = 1; break; case OPT_UNLINK: /* Just ignore -- we always unlink first. */ break; case OPT_USE_COMPRESS_PROGRAM: gzip_program = optarg; break; case OPT_FORCE_LOCAL: forcelocal = 1; break; case OPT_INSECURE: secure = 0; break; case OPT_STRICT: /* disable gnu extensions */ is_gnutar = 0; break; case OPT_EXCLUDE: if (tar_gnutar_minus_minus_exclude(optarg) != 0) tar_usage(); break; case OPT_NORECURSE: dflag = 1; break; #if !HAVE_NBTOOL_CONFIG_H case OPT_CHROOT: do_chroot = 1; break; #endif default: tar_usage(); break; } } argc -= optind; argv += optind; /* Tar requires an action. */ if (act == ERROR) tar_usage(); /* Traditional tar behaviour (pax uses stderr unless in list mode) */ if (fstdin == 1 && act == ARCHIVE) listf = stderr; else listf = stdout; /* Traditional tar behaviour (pax wants to read file list from stdin) */ if ((act == ARCHIVE || act == APPND) && argc == 0 && nincfiles == 0) exit(0); /* * if we are writing (ARCHIVE) specify tar, otherwise run like pax * (unless -o specified) */ if (act == ARCHIVE || act == APPND) frmt = &(fsub[Oflag ? F_TAR : F_USTAR]); else if (Oflag) { if (act == EXTRACT) to_stdout = 1; else { tty_warn(1, "The -O/-o options are only valid when " "writing or extracting an archive"); tar_usage(); } } /* * process the args as they are interpreted by the operation mode */ switch (act) { case LIST: case EXTRACT: default: { int sawpat = 0; int dirisnext = 0; char *file, *dir = NULL; int mustfreedir = 0; 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; mustfreedir = 0; incfiles++; nincfiles--; } else if (strcmp(*argv, "-I") == 0) { if (*++argv == NULL) break; file = *argv++; dir = chdname; mustfreedir = 0; } else { file = NULL; dir = NULL; mustfreedir = 0; } if (file != NULL) { FILE *fp; char *str; if (strcmp(file, "-") == 0) fp = stdin; else if ((fp = fopen(file, "r")) == NULL) { tty_warn(1, "Unable to open file '%s' for read", file); tar_usage(); } while ((str = get_line(fp)) != NULL) { if (dirisnext) { if (dir && mustfreedir) free(dir); dir = str; mustfreedir = 1; dirisnext = 0; continue; } if (strcmp(str, "-C") == 0) { havechd++; dirisnext = 1; free(str); continue; } if (strncmp(str, "-C ", 3) == 0) { havechd++; if (dir && mustfreedir) free(dir); dir = strdup(str + 3); mustfreedir = 1; free(str); continue; } if (pat_add(str, dir, NOGLOB_MTCH) < 0) tar_usage(); sawpat = 1; } /* Bomb if given -C w/out a dir. */ if (dirisnext) tar_usage(); if (dir && mustfreedir) free(dir); if (strcmp(file, "-") != 0) fclose(fp); if (get_line_error) { tty_warn(1, "Problem with file '%s'", file); tar_usage(); } } else if (strcmp(*argv, "-C") == 0) { if (*++argv == NULL) break; chdname = *argv++; havechd++; } else if (pat_add(*argv++, chdname, 0) < 0) tar_usage(); else sawpat = 1; } /* * if patterns were added, we are doing chdir() * on a file-by-file basis, else, just one * global chdir (if any) after opening input. */ if (sawpat > 0) chdname = NULL; } break; case ARCHIVE: case APPND: if (chdname != NULL) { /* initial chdir() */ if (ftree_add(chdname, 1) < 0) tar_usage(); } 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; file = *argv++; dir = NULL; } else { file = NULL; dir = NULL; } if (file != NULL) { FILE *fp; char *str; int dirisnext = 0; /* 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) { tty_warn(1, "Unable to open file '%s' for read", file); tar_usage(); } while ((str = get_line(fp)) != NULL) { if (dirisnext) { if (ftree_add(str, 1) < 0) tar_usage(); dirisnext = 0; continue; } if (strcmp(str, "-C") == 0) { dirisnext = 1; continue; } if (strncmp(str, "-C ", 3) == 0) { if (ftree_add(str + 3, 1) < 0) tar_usage(); continue; } if (ftree_add(str, 0) < 0) tar_usage(); } /* Bomb if given -C w/out a dir. */ if (dirisnext) tar_usage(); if (strcmp(file, "-") != 0) fclose(fp); if (get_line_error) { tty_warn(1, "Problem with file '%s'", file); tar_usage(); } } else if (strcmp(*argv, "-C") == 0) { if (*++argv == NULL) break; if (ftree_add(*argv++, 1) < 0) tar_usage(); } else if (ftree_add(*argv++, 0) < 0) tar_usage(); } /* * no read errors allowed on updates/append operation! */ maxflt = 0; break; } if (!fstdin && ((arcname == NULL) || (*arcname == '\0'))) { arcname = getenv("TAPE"); if ((arcname == NULL) || (*arcname == '\0')) arcname = _PATH_DEFTAPE; } }
static void tar_options(int argc, char **argv) { int c; int fstdin = 0; int Oflag = 0; int nincfiles = 0; int incfiles_max = 0; struct incfile { char *file; char *dir; }; struct incfile *incfiles = NULL; /* * Set default values. */ rmleadslash = 1; /* * process option flags */ while ((c = getoldopt(argc, argv, "b:cef:hjmopqruts:vwxyzBC:HI:LOPXZ014578")) != -1) { switch(c) { case 'b': /* * specify blocksize in 512-byte blocks */ if ((wrblksz = (int)str_offt(optarg)) <= 0) { paxwarn(1, "Invalid block size %s", optarg); tar_usage(); } wrblksz *= 512; /* XXX - check for int oflow */ break; case 'c': /* * create an archive */ tar_set_action(ARCHIVE); break; case 'e': /* * stop after first error */ maxflt = 0; break; case 'f': /* * filename where the archive is stored */ if ((optarg[0] == '-') && (optarg[1]== '\0')) { /* * treat a - as stdin */ fstdin = 1; arcname = NULL; break; } fstdin = 0; arcname = optarg; break; case 'h': /* * follow symlinks */ Lflag = 1; break; case 'j': case 'y': /* * use bzip2. Non standard option. */ gzip_program = BZIP2_CMD; break; case 'm': /* * do not preserve modification time */ pmtime = 0; break; case 'o': if (opt_add("write_opt=nodir") < 0) tar_usage(); case 'O': Oflag = 1; 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': /* * append to the archive */ tar_set_action(APPND); break; case 's': /* * file name substitution name pattern */ if (rep_add(optarg) < 0) { tar_usage(); break; } break; case 't': /* * list contents of the tape */ tar_set_action(LIST); break; case 'v': /* * verbose operation mode */ vflag++; break; case 'w': /* * interactive file rename */ iflag = 1; break; case 'x': /* * extract an archive, preserving mode, * and mtime if possible. */ tar_set_action(EXTRACT); pmtime = 1; break; case 'z': /* * use gzip. Non standard option. */ gzip_program = GZIP_CMD; break; case 'B': /* * Nothing to do here, this is pax default */ break; case 'C': chdname = optarg; break; case 'H': /* * follow command line symlinks only */ Hflag = 1; break; case 'I': if (++nincfiles > incfiles_max) { incfiles_max = nincfiles + 3; incfiles = realloc(incfiles, sizeof(*incfiles) * incfiles_max); if (incfiles == NULL) { paxwarn(0, "Unable to allocate space " "for option list"); exit(1); } } incfiles[nincfiles - 1].file = optarg; incfiles[nincfiles - 1].dir = chdname; break; case 'L': /* * follow symlinks */ Lflag = 1; break; case 'P': /* * do not remove leading '/' from pathnames */ rmleadslash = 0; break; case 'X': /* * do not pass over mount points in the file system */ Xflag = 1; break; case 'Z': /* * use compress. */ gzip_program = COMPRESS_CMD; break; case '0': arcname = DEV_0; break; case '1': arcname = DEV_1; break; case '4': arcname = DEV_4; break; case '5': arcname = DEV_5; break; case '7': arcname = DEV_7; break; case '8': arcname = DEV_8; break; default: tar_usage(); break; } } argc -= optind; argv += optind; /* Tar requires an action. */ if (act == ERROR) tar_usage(); /* Traditional tar behaviour (pax uses stderr unless in list mode) */ if (fstdin == 1 && act == ARCHIVE) listf = stderr; else listf = stdout; /* Traditional tar behaviour (pax wants to read file list from stdin) */ if ((act == ARCHIVE || act == APPND) && argc == 0 && nincfiles == 0) exit(0); /* * if we are writing (ARCHIVE) specify tar, otherwise run like pax * (unless -o specified) */ if (act == ARCHIVE || 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 */ switch (act) { case LIST: case EXTRACT: default: { int sawpat = 0; char *file, *dir = NULL; while (nincfiles || *argv != NULL) { /* * If we queued up any include files, * pull them in now. Otherwise, check * for -I and -C positional flags. * Anything else must be a file to * extract. */ if (nincfiles) { file = incfiles->file; dir = incfiles->dir; incfiles++; nincfiles--; } else if (strcmp(*argv, "-I") == 0) { if (*++argv == NULL) break; file = *argv++; dir = chdname; } else file = NULL; if (file != NULL) { FILE *fp; char *str; if (strcmp(file, "-") == 0) fp = stdin; else if ((fp = fopen(file, "r")) == NULL) { paxwarn(1, "Unable to open file '%s' for read", file); tar_usage(); } while ((str = getline(fp)) != NULL) { if (pat_add(str, dir) < 0) tar_usage(); sawpat = 1; } if (strcmp(file, "-") != 0) fclose(fp); if (getline_error) { paxwarn(1, "Problem with file '%s'", file); tar_usage(); } } else if (strcmp(*argv, "-C") == 0) { if (*++argv == NULL) break; chdname = *argv++; } else if (pat_add(*argv++, chdname) < 0) tar_usage(); else sawpat = 1; } /* * if patterns were added, we are doing chdir() * on a file-by-file basis, else, just one * global chdir (if any) after opening input. */ if (sawpat > 0) chdname = NULL; } break; case ARCHIVE: case APPND: if (chdname != NULL) { /* initial chdir() */ if (ftree_add(chdname, 1) < 0) tar_usage(); } while (nincfiles || *argv != NULL) { char *file, *dir = NULL; /* * If we queued up any include files, pull them in * now. Otherwise, check for -I and -C positional * flags. Anything else must be a file to include * in the archive. */ if (nincfiles) { file = incfiles->file; dir = incfiles->dir; incfiles++; nincfiles--; } else if (strcmp(*argv, "-I") == 0) { if (*++argv == NULL) break; file = *argv++; dir = NULL; } else file = NULL; if (file != NULL) { FILE *fp; char *str; /* Set directory if needed */ if (dir) { if (ftree_add(dir, 1) < 0) tar_usage(); } if (strcmp(file, "-") == 0) fp = stdin; else if ((fp = fopen(file, "r")) == NULL) { paxwarn(1, "Unable to open file '%s' for read", file); tar_usage(); } while ((str = getline(fp)) != NULL) { if (ftree_add(str, 0) < 0) tar_usage(); } if (strcmp(file, "-") != 0) fclose(fp); if (getline_error) { paxwarn(1, "Problem with file '%s'", file); tar_usage(); } } else if (strcmp(*argv, "-C") == 0) { if (*++argv == NULL) break; if (ftree_add(*argv++, 1) < 0) tar_usage(); } else if (ftree_add(*argv++, 0) < 0) tar_usage(); } /* * no read errors allowed on updates/append operation! */ maxflt = 0; break; } if (!fstdin && ((arcname == NULL) || (*arcname == '\0'))) { arcname = getenv("TAPE"); if ((arcname == NULL) || (*arcname == '\0')) arcname = _PATH_DEFTAPE; } }