1102245Sbde/*- 21556Srgrimes * Copyright (c) 1992 Keith Muller. 31556Srgrimes * Copyright (c) 1992, 1993 41556Srgrimes * The Regents of the University of California. All rights reserved. 51556Srgrimes * 61556Srgrimes * This code is derived from software contributed to Berkeley by 71556Srgrimes * Keith Muller of the University of California, San Diego. 81556Srgrimes * 91556Srgrimes * Redistribution and use in source and binary forms, with or without 101556Srgrimes * modification, are permitted provided that the following conditions 111556Srgrimes * are met: 121556Srgrimes * 1. Redistributions of source code must retain the above copyright 131556Srgrimes * notice, this list of conditions and the following disclaimer. 141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151556Srgrimes * notice, this list of conditions and the following disclaimer in the 161556Srgrimes * documentation and/or other materials provided with the distribution. 171556Srgrimes * 4. Neither the name of the University nor the names of its contributors 181556Srgrimes * may be used to endorse or promote products derived from this software 191556Srgrimes * without specific prior written permission. 201556Srgrimes * 211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311556Srgrimes * SUCH DAMAGE. 321556Srgrimes */ 331556Srgrimes 34102245Sbde#if 0 351556Srgrimes#ifndef lint 3636049Scharnierstatic char sccsid[] = "@(#)options.c 8.2 (Berkeley) 4/18/94"; 37102245Sbde#endif /* not lint */ 3836049Scharnier#endif 391556Srgrimes 4094553Scharnier#include <sys/cdefs.h> 4194553Scharnier__FBSDID("$FreeBSD: releng/10.3/bin/pax/options.c 281661 2015-04-17 18:33:59Z eadler $"); 4294553Scharnier 431556Srgrimes#include <sys/types.h> 441556Srgrimes#include <sys/stat.h> 451556Srgrimes#include <sys/mtio.h> 461556Srgrimes#include <stdio.h> 471556Srgrimes#include <string.h> 4876351Skris#include <errno.h> 491556Srgrimes#include <unistd.h> 501556Srgrimes#include <stdlib.h> 511556Srgrimes#include <limits.h> 5276351Skris#include <paths.h> 531556Srgrimes#include "pax.h" 541556Srgrimes#include "options.h" 551556Srgrimes#include "cpio.h" 561556Srgrimes#include "tar.h" 571556Srgrimes#include "extern.h" 581556Srgrimes 591556Srgrimes/* 601556Srgrimes * Routines which handle command line options 611556Srgrimes */ 621556Srgrimes 631556Srgrimesstatic char flgch[] = FLGCH; /* list of all possible flags */ 641556Srgrimesstatic OPLIST *ophead = NULL; /* head for format specific options -x */ 651556Srgrimesstatic OPLIST *optail = NULL; /* option tail */ 661556Srgrimes 6790110Simpstatic int no_op(void); 6890110Simpstatic void printflg(unsigned int); 6990110Simpstatic int c_frmt(const void *, const void *); 7090110Simpstatic off_t str_offt(char *); 7190110Simpstatic char *getline(FILE *fp); 7290113Simpstatic void pax_options(int, char **); 7390110Simpstatic void pax_usage(void); 7490113Simpstatic void tar_options(int, char **); 7590110Simpstatic void tar_usage(void); 7690113Simpstatic void cpio_options(int, char **); 7790110Simpstatic void cpio_usage(void); 781556Srgrimes 7976351Skris/* errors from getline */ 8076351Skris#define GETLINE_FILE_CORRUPT 1 8176351Skris#define GETLINE_OUT_OF_MEM 2 8276351Skrisstatic int getline_error; 8376351Skris 84241720Sedchar *chdname; 8576351Skris 8676286Skris#define GZIP_CMD "gzip" /* command to run as gzip */ 8776286Skris#define COMPRESS_CMD "compress" /* command to run as compress */ 8876351Skris#define BZIP2_CMD "bzip2" /* command to run as gzip */ 8976286Skris 901556Srgrimes/* 911556Srgrimes * Format specific routine table - MUST BE IN SORTED ORDER BY NAME 921556Srgrimes * (see pax.h for description of each function) 931556Srgrimes * 941556Srgrimes * name, blksz, hdsz, udev, hlk, blkagn, inhead, id, st_read, 951556Srgrimes * read, end_read, st_write, write, end_write, trail, 961556Srgrimes * rd_data, wr_data, options 971556Srgrimes */ 981556Srgrimes 991556SrgrimesFSUB fsub[] = { 1001556Srgrimes/* 0: OLD BINARY CPIO */ 1017165Sjoerg {"bcpio", 5120, sizeof(HD_BCPIO), 1, 0, 0, 1, bcpio_id, cpio_strd, 1021556Srgrimes bcpio_rd, bcpio_endrd, cpio_stwr, bcpio_wr, cpio_endwr, cpio_trail, 103114583Smarkm NULL, rd_wrfile, wr_rdfile, bad_opt}, 1041556Srgrimes 1051556Srgrimes/* 1: OLD OCTAL CHARACTER CPIO */ 1067165Sjoerg {"cpio", 5120, sizeof(HD_CPIO), 1, 0, 0, 1, cpio_id, cpio_strd, 1071556Srgrimes cpio_rd, cpio_endrd, cpio_stwr, cpio_wr, cpio_endwr, cpio_trail, 108114583Smarkm NULL, rd_wrfile, wr_rdfile, bad_opt}, 1091556Srgrimes 1101556Srgrimes/* 2: SVR4 HEX CPIO */ 1117165Sjoerg {"sv4cpio", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, vcpio_id, cpio_strd, 1121556Srgrimes vcpio_rd, vcpio_endrd, cpio_stwr, vcpio_wr, cpio_endwr, cpio_trail, 113114583Smarkm NULL, rd_wrfile, wr_rdfile, bad_opt}, 1141556Srgrimes 1151556Srgrimes/* 3: SVR4 HEX CPIO WITH CRC */ 1167165Sjoerg {"sv4crc", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd, 1171556Srgrimes vcpio_rd, vcpio_endrd, crc_stwr, vcpio_wr, cpio_endwr, cpio_trail, 118114583Smarkm NULL, rd_wrfile, wr_rdfile, bad_opt}, 1191556Srgrimes 1201556Srgrimes/* 4: OLD TAR */ 1217165Sjoerg {"tar", 10240, BLKMULT, 0, 1, BLKMULT, 0, tar_id, no_op, 122114583Smarkm tar_rd, tar_endrd, no_op, tar_wr, tar_endwr, NULL, tar_trail, 1237165Sjoerg rd_wrfile, wr_rdfile, tar_opt}, 1241556Srgrimes 1251556Srgrimes/* 5: POSIX USTAR */ 1267165Sjoerg {"ustar", 10240, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, ustar_strd, 127114583Smarkm ustar_rd, tar_endrd, ustar_stwr, ustar_wr, tar_endwr, NULL, tar_trail, 1287165Sjoerg rd_wrfile, wr_rdfile, bad_opt}, 1291556Srgrimes}; 13076351Skris#define F_OCPIO 0 /* format when called as cpio -6 */ 13176351Skris#define F_ACPIO 1 /* format when called as cpio -c */ 13276351Skris#define F_CPIO 3 /* format when called as cpio */ 13376351Skris#define F_OTAR 4 /* format when called as tar -o */ 13476351Skris#define F_TAR 5 /* format when called as tar */ 1351556Srgrimes#define DEFLT 5 /* default write format from list above */ 1361556Srgrimes 1371556Srgrimes/* 1381556Srgrimes * ford is the archive search order used by get_arc() to determine what kind 1391556Srgrimes * of archive we are dealing with. This helps to properly id archive formats 1401556Srgrimes * some formats may be subsets of others.... 1411556Srgrimes */ 1421556Srgrimesint ford[] = {5, 4, 3, 2, 1, 0, -1 }; 1431556Srgrimes 1441556Srgrimes/* 1451556Srgrimes * options() 1461556Srgrimes * figure out if we are pax, tar or cpio. Call the appropriate options 1471556Srgrimes * parser 1481556Srgrimes */ 1491556Srgrimes 1501556Srgrimesvoid 15190113Simpoptions(int argc, char **argv) 1521556Srgrimes{ 1531556Srgrimes 1541556Srgrimes /* 1551556Srgrimes * Are we acting like pax, tar or cpio (based on argv[0]) 1561556Srgrimes */ 1571556Srgrimes if ((argv0 = strrchr(argv[0], '/')) != NULL) 1581556Srgrimes argv0++; 1591556Srgrimes else 1601556Srgrimes argv0 = argv[0]; 1611556Srgrimes 16294553Scharnier if (strcmp(NM_TAR, argv0) == 0) { 16394553Scharnier tar_options(argc, argv); 16494553Scharnier return; 16594553Scharnier } 16694553Scharnier else if (strcmp(NM_CPIO, argv0) == 0) { 16794553Scharnier cpio_options(argc, argv); 16894553Scharnier return; 16994553Scharnier } 1701556Srgrimes /* 1711556Srgrimes * assume pax as the default 1721556Srgrimes */ 1731556Srgrimes argv0 = NM_PAX; 17494553Scharnier pax_options(argc, argv); 17594553Scharnier return; 1761556Srgrimes} 1771556Srgrimes 1781556Srgrimes/* 1791556Srgrimes * pax_options() 1801556Srgrimes * look at the user specified flags. set globals as required and check if 1811556Srgrimes * the user specified a legal set of flags. If not, complain and exit 1821556Srgrimes */ 1831556Srgrimes 1841556Srgrimesstatic void 18590113Simppax_options(int argc, char **argv) 1861556Srgrimes{ 18790113Simp int c; 188114469Sobrien size_t i; 1891556Srgrimes unsigned int flg = 0; 1901556Srgrimes unsigned int bflg = 0; 19190113Simp char *pt; 19276019Skris FSUB tmp; 1931556Srgrimes 1941556Srgrimes /* 1951556Srgrimes * process option flags 1961556Srgrimes */ 197281661Seadler while ((c=getopt(argc,argv,"ab:cdf:iklno:p:rs:tuvwx:zB:DE:G:HLOPT:U:XYZ")) 19824348Simp != -1) { 1991556Srgrimes switch (c) { 2001556Srgrimes case 'a': 2011556Srgrimes /* 2021556Srgrimes * append 2031556Srgrimes */ 2041556Srgrimes flg |= AF; 2051556Srgrimes break; 2061556Srgrimes case 'b': 2071556Srgrimes /* 2081556Srgrimes * specify blocksize 2091556Srgrimes */ 2101556Srgrimes flg |= BF; 2111556Srgrimes if ((wrblksz = (int)str_offt(optarg)) <= 0) { 21276017Skris paxwarn(1, "Invalid block size %s", optarg); 2131556Srgrimes pax_usage(); 2141556Srgrimes } 2151556Srgrimes break; 2161556Srgrimes case 'c': 2171556Srgrimes /* 2181556Srgrimes * inverse match on patterns 2191556Srgrimes */ 2201556Srgrimes cflag = 1; 2211556Srgrimes flg |= CF; 2221556Srgrimes break; 2231556Srgrimes case 'd': 2241556Srgrimes /* 2251556Srgrimes * match only dir on extract, not the subtree at dir 2261556Srgrimes */ 2271556Srgrimes dflag = 1; 2281556Srgrimes flg |= DF; 2291556Srgrimes break; 2301556Srgrimes case 'f': 2311556Srgrimes /* 2321556Srgrimes * filename where the archive is stored 2331556Srgrimes */ 2341556Srgrimes arcname = optarg; 2351556Srgrimes flg |= FF; 2361556Srgrimes break; 2371556Srgrimes case 'i': 2381556Srgrimes /* 2391556Srgrimes * interactive file rename 2401556Srgrimes */ 2411556Srgrimes iflag = 1; 2421556Srgrimes flg |= IF; 2431556Srgrimes break; 2441556Srgrimes case 'k': 2451556Srgrimes /* 2461556Srgrimes * do not clobber files that exist 2471556Srgrimes */ 2481556Srgrimes kflag = 1; 2491556Srgrimes flg |= KF; 2501556Srgrimes break; 2511556Srgrimes case 'l': 2521556Srgrimes /* 2531556Srgrimes * try to link src to dest with copy (-rw) 2541556Srgrimes */ 2551556Srgrimes lflag = 1; 2561556Srgrimes flg |= LF; 2571556Srgrimes break; 2581556Srgrimes case 'n': 2591556Srgrimes /* 2601556Srgrimes * select first match for a pattern only 2611556Srgrimes */ 2621556Srgrimes nflag = 1; 2631556Srgrimes flg |= NF; 2641556Srgrimes break; 2651556Srgrimes case 'o': 2661556Srgrimes /* 2671556Srgrimes * pass format specific options 2681556Srgrimes */ 2691556Srgrimes flg |= OF; 2701556Srgrimes if (opt_add(optarg) < 0) 2711556Srgrimes pax_usage(); 2721556Srgrimes break; 2731556Srgrimes case 'p': 2741556Srgrimes /* 2751556Srgrimes * specify file characteristic options 2761556Srgrimes */ 2771556Srgrimes for (pt = optarg; *pt != '\0'; ++pt) { 2781556Srgrimes switch(*pt) { 2791556Srgrimes case 'a': 2801556Srgrimes /* 2811556Srgrimes * do not preserve access time 2821556Srgrimes */ 2831556Srgrimes patime = 0; 2841556Srgrimes break; 2851556Srgrimes case 'e': 2861556Srgrimes /* 2871556Srgrimes * preserve user id, group id, file 2881556Srgrimes * mode, access/modification times 2891556Srgrimes */ 2901556Srgrimes pids = 1; 2911556Srgrimes pmode = 1; 2921556Srgrimes patime = 1; 2931556Srgrimes pmtime = 1; 2941556Srgrimes break; 2951556Srgrimes case 'm': 2961556Srgrimes /* 2971556Srgrimes * do not preserve modification time 2981556Srgrimes */ 2991556Srgrimes pmtime = 0; 3001556Srgrimes break; 3011556Srgrimes case 'o': 3021556Srgrimes /* 3031556Srgrimes * preserve uid/gid 3041556Srgrimes */ 3051556Srgrimes pids = 1; 3061556Srgrimes break; 3071556Srgrimes case 'p': 3081556Srgrimes /* 3091556Srgrimes * preserver file mode bits 3101556Srgrimes */ 3111556Srgrimes pmode = 1; 3121556Srgrimes break; 3131556Srgrimes default: 31476017Skris paxwarn(1, "Invalid -p string: %c", *pt); 3151556Srgrimes pax_usage(); 3161556Srgrimes break; 3171556Srgrimes } 3181556Srgrimes } 3191556Srgrimes flg |= PF; 3201556Srgrimes break; 3211556Srgrimes case 'r': 3221556Srgrimes /* 3231556Srgrimes * read the archive 3241556Srgrimes */ 3251556Srgrimes flg |= RF; 3261556Srgrimes break; 3271556Srgrimes case 's': 3281556Srgrimes /* 3291556Srgrimes * file name substitution name pattern 3301556Srgrimes */ 3311556Srgrimes if (rep_add(optarg) < 0) { 3321556Srgrimes pax_usage(); 3331556Srgrimes break; 3341556Srgrimes } 3351556Srgrimes flg |= SF; 3361556Srgrimes break; 3371556Srgrimes case 't': 3381556Srgrimes /* 339102230Strhodes * preserve access time on file system nodes we read 3401556Srgrimes */ 3411556Srgrimes tflag = 1; 3421556Srgrimes flg |= TF; 3431556Srgrimes break; 3441556Srgrimes case 'u': 3451556Srgrimes /* 3461556Srgrimes * ignore those older files 3471556Srgrimes */ 3481556Srgrimes uflag = 1; 3491556Srgrimes flg |= UF; 3501556Srgrimes break; 3511556Srgrimes case 'v': 3521556Srgrimes /* 3531556Srgrimes * verbose operation mode 3541556Srgrimes */ 3551556Srgrimes vflag = 1; 3561556Srgrimes flg |= VF; 3571556Srgrimes break; 3581556Srgrimes case 'w': 3591556Srgrimes /* 3601556Srgrimes * write an archive 3611556Srgrimes */ 3621556Srgrimes flg |= WF; 3631556Srgrimes break; 3641556Srgrimes case 'x': 3651556Srgrimes /* 3661556Srgrimes * specify an archive format on write 3671556Srgrimes */ 3681556Srgrimes tmp.name = optarg; 3697165Sjoerg if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub, 37076351Skris sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL) { 3711556Srgrimes flg |= XF; 3721556Srgrimes break; 3731556Srgrimes } 37476017Skris paxwarn(1, "Unknown -x format: %s", optarg); 3751556Srgrimes (void)fputs("pax: Known -x formats are:", stderr); 3761556Srgrimes for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i) 3771556Srgrimes (void)fprintf(stderr, " %s", fsub[i].name); 3781556Srgrimes (void)fputs("\n\n", stderr); 3791556Srgrimes pax_usage(); 3801556Srgrimes break; 38176286Skris case 'z': 38276286Skris /* 38376286Skris * use gzip. Non standard option. 38476286Skris */ 38576286Skris gzip_program = GZIP_CMD; 38676286Skris break; 3871556Srgrimes case 'B': 3881556Srgrimes /* 3891556Srgrimes * non-standard option on number of bytes written on a 3901556Srgrimes * single archive volume. 3911556Srgrimes */ 3921556Srgrimes if ((wrlimit = str_offt(optarg)) <= 0) { 39376017Skris paxwarn(1, "Invalid write limit %s", optarg); 3941556Srgrimes pax_usage(); 3951556Srgrimes } 3961556Srgrimes if (wrlimit % BLKMULT) { 39776017Skris paxwarn(1, "Write limit is not a %d byte multiple", 3981556Srgrimes BLKMULT); 3991556Srgrimes pax_usage(); 4001556Srgrimes } 4011556Srgrimes flg |= CBF; 4021556Srgrimes break; 4031556Srgrimes case 'D': 4041556Srgrimes /* 4051556Srgrimes * On extraction check file inode change time before the 4061556Srgrimes * modification of the file name. Non standard option. 4071556Srgrimes */ 4081556Srgrimes Dflag = 1; 4091556Srgrimes flg |= CDF; 4101556Srgrimes break; 4111556Srgrimes case 'E': 4121556Srgrimes /* 4131556Srgrimes * non-standard limit on read faults 4141556Srgrimes * 0 indicates stop after first error, values 4151556Srgrimes * indicate a limit, "NONE" try forever 4161556Srgrimes */ 4171556Srgrimes flg |= CEF; 4181556Srgrimes if (strcmp(NONE, optarg) == 0) 4191556Srgrimes maxflt = -1; 4201556Srgrimes else if ((maxflt = atoi(optarg)) < 0) { 42176017Skris paxwarn(1, "Error count value must be positive"); 4221556Srgrimes pax_usage(); 4231556Srgrimes } 4241556Srgrimes break; 4251556Srgrimes case 'G': 4261556Srgrimes /* 4271556Srgrimes * non-standard option for selecting files within an 4281556Srgrimes * archive by group (gid or name) 4291556Srgrimes */ 4301556Srgrimes if (grp_add(optarg) < 0) { 4311556Srgrimes pax_usage(); 4321556Srgrimes break; 4331556Srgrimes } 4341556Srgrimes flg |= CGF; 4351556Srgrimes break; 4361556Srgrimes case 'H': 4371556Srgrimes /* 4381556Srgrimes * follow command line symlinks only 4391556Srgrimes */ 4401556Srgrimes Hflag = 1; 4411556Srgrimes flg |= CHF; 4421556Srgrimes break; 4431556Srgrimes case 'L': 4441556Srgrimes /* 4451556Srgrimes * follow symlinks 4461556Srgrimes */ 4471556Srgrimes Lflag = 1; 4481556Srgrimes flg |= CLF; 4491556Srgrimes break; 450281661Seadler case 'O': 451281661Seadler /* 452281661Seadler * Force one volume. Non standard option. 453281661Seadler */ 454281661Seadler Oflag = 1; 455281661Seadler break; 4561556Srgrimes case 'P': 4571556Srgrimes /* 4581556Srgrimes * do NOT follow symlinks (default) 4591556Srgrimes */ 4601556Srgrimes Lflag = 0; 4611556Srgrimes flg |= CPF; 4621556Srgrimes break; 4631556Srgrimes case 'T': 4641556Srgrimes /* 4651556Srgrimes * non-standard option for selecting files within an 4661556Srgrimes * archive by modification time range (lower,upper) 4671556Srgrimes */ 4681556Srgrimes if (trng_add(optarg) < 0) { 4691556Srgrimes pax_usage(); 4701556Srgrimes break; 4711556Srgrimes } 4721556Srgrimes flg |= CTF; 4731556Srgrimes break; 4741556Srgrimes case 'U': 4751556Srgrimes /* 4761556Srgrimes * non-standard option for selecting files within an 4771556Srgrimes * archive by user (uid or name) 4781556Srgrimes */ 4791556Srgrimes if (usr_add(optarg) < 0) { 4801556Srgrimes pax_usage(); 4811556Srgrimes break; 4821556Srgrimes } 4831556Srgrimes flg |= CUF; 4841556Srgrimes break; 4851556Srgrimes case 'X': 4861556Srgrimes /* 487102230Strhodes * do not pass over mount points in the file system 4881556Srgrimes */ 4891556Srgrimes Xflag = 1; 4901556Srgrimes flg |= CXF; 4911556Srgrimes break; 4921556Srgrimes case 'Y': 4931556Srgrimes /* 4941556Srgrimes * On extraction check file inode change time after the 4951556Srgrimes * modification of the file name. Non standard option. 4961556Srgrimes */ 4971556Srgrimes Yflag = 1; 4981556Srgrimes flg |= CYF; 4991556Srgrimes break; 5001556Srgrimes case 'Z': 5011556Srgrimes /* 5021556Srgrimes * On extraction check modification time after the 5031556Srgrimes * modification of the file name. Non standard option. 5041556Srgrimes */ 5051556Srgrimes Zflag = 1; 5061556Srgrimes flg |= CZF; 5071556Srgrimes break; 5081556Srgrimes default: 5091556Srgrimes pax_usage(); 5101556Srgrimes break; 5111556Srgrimes } 5121556Srgrimes } 5131556Srgrimes 5141556Srgrimes /* 5151556Srgrimes * figure out the operation mode of pax read,write,extract,copy,append 5161556Srgrimes * or list. check that we have not been given a bogus set of flags 5171556Srgrimes * for the operation mode. 5181556Srgrimes */ 5191556Srgrimes if (ISLIST(flg)) { 5201556Srgrimes act = LIST; 52176351Skris listf = stdout; 5221556Srgrimes bflg = flg & BDLIST; 5231556Srgrimes } else if (ISEXTRACT(flg)) { 5241556Srgrimes act = EXTRACT; 5251556Srgrimes bflg = flg & BDEXTR; 5261556Srgrimes } else if (ISARCHIVE(flg)) { 5271556Srgrimes act = ARCHIVE; 5281556Srgrimes bflg = flg & BDARCH; 5291556Srgrimes } else if (ISAPPND(flg)) { 5301556Srgrimes act = APPND; 5311556Srgrimes bflg = flg & BDARCH; 5321556Srgrimes } else if (ISCOPY(flg)) { 5331556Srgrimes act = COPY; 5341556Srgrimes bflg = flg & BDCOPY; 5351556Srgrimes } else 5361556Srgrimes pax_usage(); 5371556Srgrimes if (bflg) { 5381556Srgrimes printflg(flg); 5391556Srgrimes pax_usage(); 5401556Srgrimes } 5411556Srgrimes 5421556Srgrimes /* 5431556Srgrimes * if we are writing (ARCHIVE) we use the default format if the user 5441556Srgrimes * did not specify a format. when we write during an APPEND, we will 5451556Srgrimes * adopt the format of the existing archive if none was supplied. 5461556Srgrimes */ 5471556Srgrimes if (!(flg & XF) && (act == ARCHIVE)) 5481556Srgrimes frmt = &(fsub[DEFLT]); 5491556Srgrimes 5501556Srgrimes /* 5511556Srgrimes * process the args as they are interpreted by the operation mode 5521556Srgrimes */ 5531556Srgrimes switch (act) { 5541556Srgrimes case LIST: 5551556Srgrimes case EXTRACT: 5561556Srgrimes for (; optind < argc; optind++) 55776351Skris if (pat_add(argv[optind], NULL) < 0) 5581556Srgrimes pax_usage(); 5591556Srgrimes break; 5601556Srgrimes case COPY: 5611556Srgrimes if (optind >= argc) { 56276017Skris paxwarn(0, "Destination directory was not supplied"); 5631556Srgrimes pax_usage(); 5641556Srgrimes } 5651556Srgrimes --argc; 5661556Srgrimes dirptr = argv[argc]; 56794553Scharnier /* FALLTHROUGH */ 5681556Srgrimes case ARCHIVE: 5691556Srgrimes case APPND: 5701556Srgrimes for (; optind < argc; optind++) 57176351Skris if (ftree_add(argv[optind], 0) < 0) 5721556Srgrimes pax_usage(); 5731556Srgrimes /* 5741556Srgrimes * no read errors allowed on updates/append operation! 5751556Srgrimes */ 5761556Srgrimes maxflt = 0; 5771556Srgrimes break; 5781556Srgrimes } 5791556Srgrimes} 5801556Srgrimes 5811556Srgrimes 5821556Srgrimes/* 5831556Srgrimes * tar_options() 5841556Srgrimes * look at the user specified flags. set globals as required and check if 5851556Srgrimes * the user specified a legal set of flags. If not, complain and exit 5861556Srgrimes */ 5871556Srgrimes 5881556Srgrimesstatic void 58990113Simptar_options(int argc, char **argv) 5901556Srgrimes{ 59190113Simp int c; 5921556Srgrimes int fstdin = 0; 593281661Seadler int tar_Oflag = 0; 59476351Skris int nincfiles = 0; 59576351Skris int incfiles_max = 0; 59676351Skris struct incfile { 59776351Skris char *file; 59876351Skris char *dir; 59976351Skris }; 60076351Skris struct incfile *incfiles = NULL; 6011556Srgrimes 6021556Srgrimes /* 60376351Skris * Set default values. 60476351Skris */ 60576351Skris rmleadslash = 1; 60676351Skris 60776351Skris /* 6081556Srgrimes * process option flags 6091556Srgrimes */ 61076351Skris while ((c = getoldopt(argc, argv, 61176351Skris "b:cef:hjmopqruts:vwxyzBC:HI:LOPXZ014578")) != -1) { 61276351Skris switch(c) { 6131556Srgrimes case 'b': 6141556Srgrimes /* 61576351Skris * specify blocksize in 512-byte blocks 6161556Srgrimes */ 61776351Skris if ((wrblksz = (int)str_offt(optarg)) <= 0) { 61876351Skris paxwarn(1, "Invalid block size %s", optarg); 6191556Srgrimes tar_usage(); 6201556Srgrimes } 62176351Skris wrblksz *= 512; /* XXX - check for int oflow */ 6221556Srgrimes break; 6231556Srgrimes case 'c': 6241556Srgrimes /* 6251556Srgrimes * create an archive 6261556Srgrimes */ 6271556Srgrimes act = ARCHIVE; 6281556Srgrimes break; 6291556Srgrimes case 'e': 6301556Srgrimes /* 6311556Srgrimes * stop after first error 6321556Srgrimes */ 6331556Srgrimes maxflt = 0; 6341556Srgrimes break; 6351556Srgrimes case 'f': 6361556Srgrimes /* 6371556Srgrimes * filename where the archive is stored 6381556Srgrimes */ 63976351Skris if ((optarg[0] == '-') && (optarg[1]== '\0')) { 6401556Srgrimes /* 6411556Srgrimes * treat a - as stdin 6421556Srgrimes */ 64376351Skris fstdin = 1; 64476351Skris arcname = NULL; 6451556Srgrimes break; 6461556Srgrimes } 6471556Srgrimes fstdin = 0; 64876351Skris arcname = optarg; 6491556Srgrimes break; 65076351Skris case 'h': 65176351Skris /* 65276351Skris * follow symlinks 65376351Skris */ 65476351Skris Lflag = 1; 65576351Skris break; 65676351Skris case 'j': 65776351Skris case 'y': 65876351Skris /* 65976351Skris * use bzip2. Non standard option. 66076351Skris */ 66176351Skris gzip_program = BZIP2_CMD; 66276351Skris break; 6631556Srgrimes case 'm': 6641556Srgrimes /* 6651556Srgrimes * do not preserve modification time 6661556Srgrimes */ 6671556Srgrimes pmtime = 0; 6681556Srgrimes break; 6691556Srgrimes case 'o': 6701556Srgrimes if (opt_add("write_opt=nodir") < 0) 6711556Srgrimes tar_usage(); 67276351Skris case 'O': 673281661Seadler tar_Oflag = 1; 6741556Srgrimes break; 6751556Srgrimes case 'p': 6761556Srgrimes /* 67776351Skris * preserve uid/gid and file mode, regardless of umask 6781556Srgrimes */ 67976351Skris pmode = 1; 6801556Srgrimes pids = 1; 6811556Srgrimes break; 68276351Skris case 'q': 68376351Skris /* 68476351Skris * select first match for a pattern only 68576351Skris */ 68676351Skris nflag = 1; 68776351Skris break; 6881556Srgrimes case 'r': 6891556Srgrimes case 'u': 6901556Srgrimes /* 6911556Srgrimes * append to the archive 6921556Srgrimes */ 6931556Srgrimes act = APPND; 6941556Srgrimes break; 69576351Skris case 's': 69676351Skris /* 69776351Skris * file name substitution name pattern 69876351Skris */ 69976351Skris if (rep_add(optarg) < 0) { 70076351Skris tar_usage(); 70176351Skris break; 70276351Skris } 70376351Skris break; 7041556Srgrimes case 't': 7051556Srgrimes /* 7061556Srgrimes * list contents of the tape 7071556Srgrimes */ 7081556Srgrimes act = LIST; 7091556Srgrimes break; 7101556Srgrimes case 'v': 7111556Srgrimes /* 7121556Srgrimes * verbose operation mode 7131556Srgrimes */ 71476351Skris vflag++; 7151556Srgrimes break; 7161556Srgrimes case 'w': 7171556Srgrimes /* 7181556Srgrimes * interactive file rename 7191556Srgrimes */ 7201556Srgrimes iflag = 1; 7211556Srgrimes break; 7221556Srgrimes case 'x': 7231556Srgrimes /* 72476351Skris * extract an archive, preserving mode, 72576351Skris * and mtime if possible. 7261556Srgrimes */ 7271556Srgrimes act = EXTRACT; 72876351Skris pmtime = 1; 7291556Srgrimes break; 73076286Skris case 'z': 73176286Skris /* 73276286Skris * use gzip. Non standard option. 73376286Skris */ 73476286Skris gzip_program = GZIP_CMD; 73576286Skris break; 7361556Srgrimes case 'B': 7371556Srgrimes /* 7381556Srgrimes * Nothing to do here, this is pax default 7391556Srgrimes */ 7401556Srgrimes break; 74176351Skris case 'C': 74276351Skris chdname = optarg; 74376351Skris break; 7441556Srgrimes case 'H': 7451556Srgrimes /* 7461556Srgrimes * follow command line symlinks only 7471556Srgrimes */ 7481556Srgrimes Hflag = 1; 7491556Srgrimes break; 75076351Skris case 'I': 75176351Skris if (++nincfiles > incfiles_max) { 75276351Skris incfiles_max = nincfiles + 3; 75376351Skris incfiles = realloc(incfiles, 75476351Skris sizeof(*incfiles) * incfiles_max); 75576351Skris if (incfiles == NULL) { 75676351Skris paxwarn(0, "Unable to allocate space " 75776351Skris "for option list"); 75876351Skris exit(1); 75976351Skris } 76076351Skris } 76176351Skris incfiles[nincfiles - 1].file = optarg; 76276351Skris incfiles[nincfiles - 1].dir = chdname; 76376351Skris break; 7641556Srgrimes case 'L': 7651556Srgrimes /* 7661556Srgrimes * follow symlinks 7671556Srgrimes */ 7681556Srgrimes Lflag = 1; 7691556Srgrimes break; 7701556Srgrimes case 'P': 7711556Srgrimes /* 77276351Skris * do not remove leading '/' from pathnames 7731556Srgrimes */ 77476351Skris rmleadslash = 0; 7751556Srgrimes break; 7761556Srgrimes case 'X': 7771556Srgrimes /* 778102230Strhodes * do not pass over mount points in the file system 7791556Srgrimes */ 7801556Srgrimes Xflag = 1; 7811556Srgrimes break; 78276286Skris case 'Z': 78376286Skris /* 78476286Skris * use compress. 78576286Skris */ 78676286Skris gzip_program = COMPRESS_CMD; 78776286Skris break; 7881556Srgrimes case '0': 7891556Srgrimes arcname = DEV_0; 7901556Srgrimes break; 7911556Srgrimes case '1': 7921556Srgrimes arcname = DEV_1; 7931556Srgrimes break; 7941556Srgrimes case '4': 7951556Srgrimes arcname = DEV_4; 7961556Srgrimes break; 7971556Srgrimes case '5': 7981556Srgrimes arcname = DEV_5; 7991556Srgrimes break; 8001556Srgrimes case '7': 8011556Srgrimes arcname = DEV_7; 8021556Srgrimes break; 8031556Srgrimes case '8': 8041556Srgrimes arcname = DEV_8; 8051556Srgrimes break; 8061556Srgrimes default: 8071556Srgrimes tar_usage(); 8081556Srgrimes break; 8091556Srgrimes } 8101556Srgrimes } 81176351Skris argc -= optind; 81276351Skris argv += optind; 8131556Srgrimes 81476351Skris /* Traditional tar behaviour (pax uses stderr unless in list mode) */ 81576351Skris if (fstdin == 1 && act == ARCHIVE) 81676351Skris listf = stderr; 81776351Skris else 81876351Skris listf = stdout; 81976351Skris 82076351Skris /* Traditional tar behaviour (pax wants to read file list from stdin) */ 82176351Skris if ((act == ARCHIVE || act == APPND) && argc == 0 && nincfiles == 0) 82276351Skris exit(0); 82376351Skris 8241556Srgrimes /* 8251556Srgrimes * if we are writing (ARCHIVE) specify tar, otherwise run like pax 82676351Skris * (unless -o specified) 8271556Srgrimes */ 82876351Skris if (act == ARCHIVE || act == APPND) 829281661Seadler frmt = &(fsub[tar_Oflag ? F_OTAR : F_TAR]); 830281661Seadler else if (tar_Oflag) { 83176351Skris paxwarn(1, "The -O/-o options are only valid when writing an archive"); 83276351Skris tar_usage(); /* only valid when writing */ 83376351Skris } 8341556Srgrimes 8351556Srgrimes /* 8361556Srgrimes * process the args as they are interpreted by the operation mode 8371556Srgrimes */ 8381556Srgrimes switch (act) { 8391556Srgrimes case LIST: 8401556Srgrimes case EXTRACT: 8411556Srgrimes default: 84276351Skris { 84376351Skris int sawpat = 0; 84476351Skris char *file, *dir = NULL; 84576351Skris 84676351Skris while (nincfiles || *argv != NULL) { 84776351Skris /* 84876351Skris * If we queued up any include files, 84976351Skris * pull them in now. Otherwise, check 85076351Skris * for -I and -C positional flags. 85176351Skris * Anything else must be a file to 85276351Skris * extract. 85376351Skris */ 85476351Skris if (nincfiles) { 85576351Skris file = incfiles->file; 85676351Skris dir = incfiles->dir; 85776351Skris incfiles++; 85876351Skris nincfiles--; 85976351Skris } else if (strcmp(*argv, "-I") == 0) { 86076351Skris if (*++argv == NULL) 86176351Skris break; 86276351Skris file = *argv++; 86376351Skris dir = chdname; 86476351Skris } else 86576351Skris file = NULL; 86676351Skris if (file != NULL) { 86776351Skris FILE *fp; 86876351Skris char *str; 86976351Skris 87076351Skris if (strcmp(file, "-") == 0) 87176351Skris fp = stdin; 87276351Skris else if ((fp = fopen(file, "r")) == NULL) { 87376351Skris paxwarn(1, "Unable to open file '%s' for read", file); 87476351Skris tar_usage(); 87576351Skris } 87676351Skris while ((str = getline(fp)) != NULL) { 87776351Skris if (pat_add(str, dir) < 0) 87876351Skris tar_usage(); 87976351Skris sawpat = 1; 88076351Skris } 88176351Skris if (strcmp(file, "-") != 0) 88276351Skris fclose(fp); 88376351Skris if (getline_error) { 88476351Skris paxwarn(1, "Problem with file '%s'", file); 88576351Skris tar_usage(); 88676351Skris } 88776351Skris } else if (strcmp(*argv, "-C") == 0) { 88876351Skris if (*++argv == NULL) 88976351Skris break; 89076351Skris chdname = *argv++; 89176351Skris } else if (pat_add(*argv++, chdname) < 0) 89276351Skris tar_usage(); 89376351Skris else 89476351Skris sawpat = 1; 89576351Skris } 89676351Skris /* 897222177Suqs * if patterns were added, we are doing chdir() 89876351Skris * on a file-by-file basis, else, just one 89976351Skris * global chdir (if any) after opening input. 90076351Skris */ 90176351Skris if (sawpat > 0) 90276351Skris chdname = NULL; 90376351Skris } 9041556Srgrimes break; 9051556Srgrimes case ARCHIVE: 9061556Srgrimes case APPND: 90776351Skris if (chdname != NULL) { /* initial chdir() */ 90876351Skris if (ftree_add(chdname, 1) < 0) 9091556Srgrimes tar_usage(); 91076351Skris } 91176351Skris 91276351Skris while (nincfiles || *argv != NULL) { 91376351Skris char *file, *dir = NULL; 91476351Skris 91576351Skris /* 91676351Skris * If we queued up any include files, pull them in 91776351Skris * now. Otherwise, check for -I and -C positional 91876351Skris * flags. Anything else must be a file to include 91976351Skris * in the archive. 92076351Skris */ 92176351Skris if (nincfiles) { 92276351Skris file = incfiles->file; 92376351Skris dir = incfiles->dir; 92476351Skris incfiles++; 92576351Skris nincfiles--; 92676351Skris } else if (strcmp(*argv, "-I") == 0) { 92776351Skris if (*++argv == NULL) 92876351Skris break; 92976351Skris file = *argv++; 93076351Skris dir = NULL; 93176351Skris } else 93276351Skris file = NULL; 93376351Skris if (file != NULL) { 93476351Skris FILE *fp; 93576351Skris char *str; 93676351Skris 93776351Skris /* Set directory if needed */ 93876351Skris if (dir) { 93976351Skris if (ftree_add(dir, 1) < 0) 94076351Skris tar_usage(); 94176351Skris } 94276351Skris 94376351Skris if (strcmp(file, "-") == 0) 94476351Skris fp = stdin; 94576351Skris else if ((fp = fopen(file, "r")) == NULL) { 94676351Skris paxwarn(1, "Unable to open file '%s' for read", file); 94776351Skris tar_usage(); 94876351Skris } 94976351Skris while ((str = getline(fp)) != NULL) { 95076351Skris if (ftree_add(str, 0) < 0) 95176351Skris tar_usage(); 95276351Skris } 95376351Skris if (strcmp(file, "-") != 0) 95476351Skris fclose(fp); 95576351Skris if (getline_error) { 95676351Skris paxwarn(1, "Problem with file '%s'", 95776351Skris file); 95876351Skris tar_usage(); 95976351Skris } 96076351Skris } else if (strcmp(*argv, "-C") == 0) { 96176351Skris if (*++argv == NULL) 96276351Skris break; 96376351Skris if (ftree_add(*argv++, 1) < 0) 96476351Skris tar_usage(); 96576351Skris } else if (ftree_add(*argv++, 0) < 0) 96676351Skris tar_usage(); 96776351Skris } 9681556Srgrimes /* 9691556Srgrimes * no read errors allowed on updates/append operation! 9701556Srgrimes */ 9711556Srgrimes maxflt = 0; 9721556Srgrimes break; 9731556Srgrimes } 97476017Skris if (!fstdin && ((arcname == NULL) || (*arcname == '\0'))) { 9751556Srgrimes arcname = getenv("TAPE"); 97676017Skris if ((arcname == NULL) || (*arcname == '\0')) 97776351Skris arcname = _PATH_DEFTAPE; 9781556Srgrimes } 9791556Srgrimes} 9801556Srgrimes 981114583Smarkmstatic int 982114583Smarkmmkpath(char *path) 98376351Skris{ 98476351Skris struct stat sb; 98590113Simp char *slash; 98676351Skris int done = 0; 98776351Skris 98876351Skris slash = path; 98976351Skris 99076351Skris while (!done) { 99176351Skris slash += strspn(slash, "/"); 99276351Skris slash += strcspn(slash, "/"); 99376351Skris 99476351Skris done = (*slash == '\0'); 99576351Skris *slash = '\0'; 99676351Skris 99776351Skris if (stat(path, &sb)) { 99876351Skris if (errno != ENOENT || mkdir(path, 0777)) { 99976351Skris paxwarn(1, "%s", path); 100076351Skris return (-1); 100176351Skris } 100276351Skris } else if (!S_ISDIR(sb.st_mode)) { 100376351Skris syswarn(1, ENOTDIR, "%s", path); 100476351Skris return (-1); 100576351Skris } 100676351Skris 100776351Skris if (!done) 100876351Skris *slash = '/'; 100976351Skris } 101076351Skris 101176351Skris return (0); 101276351Skris} 10131556Srgrimes/* 10141556Srgrimes * cpio_options() 10151556Srgrimes * look at the user specified flags. set globals as required and check if 10161556Srgrimes * the user specified a legal set of flags. If not, complain and exit 10171556Srgrimes */ 10181556Srgrimes 10191556Srgrimesstatic void 102090113Simpcpio_options(int argc, char **argv) 10211556Srgrimes{ 1022114469Sobrien int c; 1023114469Sobrien size_t i; 102476351Skris char *str; 102576351Skris FSUB tmp; 102676351Skris FILE *fp; 102776351Skris 102876351Skris kflag = 1; 102976351Skris pids = 1; 103076351Skris pmode = 1; 103176351Skris pmtime = 0; 103276351Skris arcname = NULL; 103376351Skris dflag = 1; 103476351Skris act = -1; 103576351Skris nodirs = 1; 103676351Skris while ((c=getopt(argc,argv,"abcdfiklmoprstuvzABC:E:F:H:I:LO:SZ6")) != -1) 103776351Skris switch (c) { 103876351Skris case 'a': 103976351Skris /* 104076351Skris * preserve access time on files read 104176351Skris */ 104276351Skris tflag = 1; 104376351Skris break; 104476351Skris case 'b': 104576351Skris /* 104676351Skris * swap bytes and half-words when reading data 104776351Skris */ 104876351Skris break; 104976351Skris case 'c': 105076351Skris /* 105176351Skris * ASCII cpio header 105276351Skris */ 105376351Skris frmt = &(fsub[F_ACPIO]); 105476351Skris break; 105576351Skris case 'd': 105676351Skris /* 105776351Skris * create directories as needed 105876351Skris */ 105976351Skris nodirs = 0; 106076351Skris break; 106176351Skris case 'f': 106276351Skris /* 106376351Skris * invert meaning of pattern list 106476351Skris */ 106576351Skris cflag = 1; 106676351Skris break; 106776351Skris case 'i': 106876351Skris /* 106976351Skris * restore an archive 107076351Skris */ 107176351Skris act = EXTRACT; 107276351Skris break; 107376351Skris case 'k': 107476351Skris break; 107576351Skris case 'l': 107676351Skris /* 107776351Skris * use links instead of copies when possible 107876351Skris */ 107976351Skris lflag = 1; 108076351Skris break; 108176351Skris case 'm': 108276351Skris /* 108376351Skris * preserve modification time 108476351Skris */ 108576351Skris pmtime = 1; 108676351Skris break; 108776351Skris case 'o': 108876351Skris /* 108976351Skris * create an archive 109076351Skris */ 109176351Skris act = ARCHIVE; 109276351Skris frmt = &(fsub[F_CPIO]); 109376351Skris break; 109476351Skris case 'p': 109576351Skris /* 109676351Skris * copy-pass mode 109776351Skris */ 109876351Skris act = COPY; 109976351Skris break; 110076351Skris case 'r': 110176351Skris /* 110276351Skris * interactively rename files 110376351Skris */ 110476351Skris iflag = 1; 110576351Skris break; 110676351Skris case 's': 110776351Skris /* 110876351Skris * swap bytes after reading data 110976351Skris */ 111076351Skris break; 111176351Skris case 't': 111276351Skris /* 111376351Skris * list contents of archive 111476351Skris */ 111576351Skris act = LIST; 111676351Skris listf = stdout; 111776351Skris break; 111876351Skris case 'u': 111976351Skris /* 112076351Skris * replace newer files 112176351Skris */ 112276351Skris kflag = 0; 112376351Skris break; 112476351Skris case 'v': 112576351Skris /* 112676351Skris * verbose operation mode 112776351Skris */ 112876351Skris vflag = 1; 112976351Skris break; 113076351Skris case 'z': 113176351Skris /* 113276351Skris * use gzip. Non standard option. 113376351Skris */ 113476351Skris gzip_program = GZIP_CMD; 113576351Skris break; 113676351Skris case 'A': 113776351Skris /* 113876351Skris * append mode 113976351Skris */ 114076351Skris act = APPND; 114176351Skris break; 114276351Skris case 'B': 114376351Skris /* 114476351Skris * Use 5120 byte block size 114576351Skris */ 114676351Skris wrblksz = 5120; 114776351Skris break; 114876351Skris case 'C': 114976351Skris /* 115076351Skris * set block size in bytes 115176351Skris */ 115276351Skris wrblksz = atoi(optarg); 115376351Skris break; 115476351Skris case 'E': 115576351Skris /* 115676351Skris * file with patterns to extract or list 115776351Skris */ 115876351Skris if ((fp = fopen(optarg, "r")) == NULL) { 115976351Skris paxwarn(1, "Unable to open file '%s' for read", optarg); 116076351Skris cpio_usage(); 116176351Skris } 116276351Skris while ((str = getline(fp)) != NULL) { 116376351Skris pat_add(str, NULL); 116476351Skris } 116576351Skris fclose(fp); 116676351Skris if (getline_error) { 116776351Skris paxwarn(1, "Problem with file '%s'", optarg); 116876351Skris cpio_usage(); 116976351Skris } 117076351Skris break; 117176351Skris case 'F': 117276351Skris case 'I': 117376351Skris case 'O': 117476351Skris /* 117576351Skris * filename where the archive is stored 117676351Skris */ 117776351Skris if ((optarg[0] == '-') && (optarg[1]== '\0')) { 117876351Skris /* 117976351Skris * treat a - as stdin 118076351Skris */ 118176351Skris arcname = NULL; 118276351Skris break; 118376351Skris } 118476351Skris arcname = optarg; 118576351Skris break; 118676351Skris case 'H': 118776351Skris /* 118876351Skris * specify an archive format on write 118976351Skris */ 119076351Skris tmp.name = optarg; 119176351Skris if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub, 119276351Skris sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL) 119376351Skris break; 119476351Skris paxwarn(1, "Unknown -H format: %s", optarg); 119576351Skris (void)fputs("cpio: Known -H formats are:", stderr); 119676351Skris for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i) 119776351Skris (void)fprintf(stderr, " %s", fsub[i].name); 119876351Skris (void)fputs("\n\n", stderr); 119976351Skris cpio_usage(); 120076351Skris break; 120176351Skris case 'L': 120276351Skris /* 120376351Skris * follow symbolic links 120476351Skris */ 120576351Skris Lflag = 1; 120676351Skris break; 120776351Skris case 'S': 120876351Skris /* 120976351Skris * swap halfwords after reading data 121076351Skris */ 121176351Skris break; 121276351Skris case 'Z': 121376351Skris /* 121476351Skris * use compress. Non standard option. 121576351Skris */ 121676351Skris gzip_program = COMPRESS_CMD; 121776351Skris break; 121876351Skris case '6': 121976351Skris /* 122076351Skris * process Version 6 cpio format 122176351Skris */ 122276351Skris frmt = &(fsub[F_OCPIO]); 122376351Skris break; 122476351Skris case '?': 122576351Skris default: 122676351Skris cpio_usage(); 122776351Skris break; 122876351Skris } 122976351Skris argc -= optind; 123076351Skris argv += optind; 123176351Skris 123276351Skris /* 123376351Skris * process the args as they are interpreted by the operation mode 123476351Skris */ 123576351Skris switch (act) { 123676351Skris case LIST: 123776351Skris case EXTRACT: 123876351Skris while (*argv != NULL) 123976351Skris if (pat_add(*argv++, NULL) < 0) 124076351Skris cpio_usage(); 124176351Skris break; 124276351Skris case COPY: 124376351Skris if (*argv == NULL) { 124476351Skris paxwarn(0, "Destination directory was not supplied"); 124576351Skris cpio_usage(); 124676351Skris } 124776351Skris dirptr = *argv; 124876351Skris if (mkpath(dirptr) < 0) 124976351Skris cpio_usage(); 125076351Skris --argc; 125176351Skris ++argv; 125294553Scharnier /* FALLTHROUGH */ 125376351Skris case ARCHIVE: 125476351Skris case APPND: 125576351Skris if (*argv != NULL) 125676351Skris cpio_usage(); 125776351Skris /* 125876351Skris * no read errors allowed on updates/append operation! 125976351Skris */ 126076351Skris maxflt = 0; 126176351Skris while ((str = getline(stdin)) != NULL) { 1262126643Smarkm ftree_add(str, 0); 126376351Skris } 126476351Skris if (getline_error) { 126576351Skris paxwarn(1, "Problem while reading stdin"); 126676351Skris cpio_usage(); 126776351Skris } 126876351Skris break; 126976351Skris default: 127076351Skris cpio_usage(); 127176351Skris break; 127276351Skris } 12731556Srgrimes} 12741556Srgrimes 12751556Srgrimes/* 12761556Srgrimes * printflg() 12771556Srgrimes * print out those invalid flag sets found to the user 12781556Srgrimes */ 12791556Srgrimes 12801556Srgrimesstatic void 12811556Srgrimesprintflg(unsigned int flg) 12821556Srgrimes{ 12831556Srgrimes int nxt; 12841556Srgrimes int pos = 0; 12851556Srgrimes 12861556Srgrimes (void)fprintf(stderr,"%s: Invalid combination of options:", argv0); 128776351Skris while ((nxt = ffs(flg)) != 0) { 12881556Srgrimes flg = flg >> nxt; 12891556Srgrimes pos += nxt; 12901556Srgrimes (void)fprintf(stderr, " -%c", flgch[pos-1]); 12911556Srgrimes } 12921556Srgrimes (void)putc('\n', stderr); 12931556Srgrimes} 12941556Srgrimes 12951556Srgrimes/* 12961556Srgrimes * c_frmt() 12971556Srgrimes * comparison routine used by bsearch to find the format specified 12981556Srgrimes * by the user 12991556Srgrimes */ 13001556Srgrimes 13011556Srgrimesstatic int 13021556Srgrimesc_frmt(const void *a, const void *b) 13031556Srgrimes{ 1304114583Smarkm return(strcmp(((const FSUB *)a)->name, ((const FSUB *)b)->name)); 13051556Srgrimes} 13061556Srgrimes 13071556Srgrimes/* 13081556Srgrimes * opt_next() 13091556Srgrimes * called by format specific options routines to get each format specific 13101556Srgrimes * flag and value specified with -o 13111556Srgrimes * Return: 13121556Srgrimes * pointer to next OPLIST entry or NULL (end of list). 13131556Srgrimes */ 13141556Srgrimes 13151556SrgrimesOPLIST * 13161556Srgrimesopt_next(void) 13171556Srgrimes{ 13181556Srgrimes OPLIST *opt; 13191556Srgrimes 13201556Srgrimes if ((opt = ophead) != NULL) 13211556Srgrimes ophead = ophead->fow; 13221556Srgrimes return(opt); 13231556Srgrimes} 13241556Srgrimes 13251556Srgrimes/* 13261556Srgrimes * bad_opt() 13271556Srgrimes * generic routine used to complain about a format specific options 13281556Srgrimes * when the format does not support options. 13291556Srgrimes */ 13301556Srgrimes 13311556Srgrimesint 13321556Srgrimesbad_opt(void) 13331556Srgrimes{ 133490113Simp OPLIST *opt; 13351556Srgrimes 13361556Srgrimes if (ophead == NULL) 13371556Srgrimes return(0); 13381556Srgrimes /* 13391556Srgrimes * print all we were given 13401556Srgrimes */ 134176017Skris paxwarn(1,"These format options are not supported"); 13421556Srgrimes while ((opt = opt_next()) != NULL) 13431556Srgrimes (void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value); 13441556Srgrimes pax_usage(); 13451556Srgrimes return(0); 13461556Srgrimes} 13471556Srgrimes 13481556Srgrimes/* 13491556Srgrimes * opt_add() 1350108533Sschweikh * breaks the value supplied to -o into an option name and value. Options 13511556Srgrimes * are given to -o in the form -o name-value,name=value 135246684Skris * multiple -o may be specified. 13531556Srgrimes * Return: 1354108533Sschweikh * 0 if format in name=value format, -1 if -o is passed junk. 13551556Srgrimes */ 13561556Srgrimes 13571556Srgrimesint 1358114583Smarkmopt_add(const char *str) 13591556Srgrimes{ 136090113Simp OPLIST *opt; 136190113Simp char *frpt; 136290113Simp char *pt; 136390113Simp char *endpt; 1364114583Smarkm char *lstr; 13651556Srgrimes 13661556Srgrimes if ((str == NULL) || (*str == '\0')) { 136776017Skris paxwarn(0, "Invalid option name"); 13681556Srgrimes return(-1); 13691556Srgrimes } 1370114583Smarkm if ((lstr = strdup(str)) == NULL) { 137176351Skris paxwarn(0, "Unable to allocate space for option list"); 137276351Skris return(-1); 137376351Skris } 1374114583Smarkm frpt = endpt = lstr; 13751556Srgrimes 13761556Srgrimes /* 13771556Srgrimes * break into name and values pieces and stuff each one into a 13781556Srgrimes * OPLIST structure. When we know the format, the format specific 13791556Srgrimes * option function will go through this list 13801556Srgrimes */ 13811556Srgrimes while ((frpt != NULL) && (*frpt != '\0')) { 13821556Srgrimes if ((endpt = strchr(frpt, ',')) != NULL) 13831556Srgrimes *endpt = '\0'; 13841556Srgrimes if ((pt = strchr(frpt, '=')) == NULL) { 138576017Skris paxwarn(0, "Invalid options format"); 1386114583Smarkm free(lstr); 13871556Srgrimes return(-1); 13881556Srgrimes } 13891556Srgrimes if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) { 139076017Skris paxwarn(0, "Unable to allocate space for option list"); 1391114583Smarkm free(lstr); 13921556Srgrimes return(-1); 13931556Srgrimes } 13941556Srgrimes *pt++ = '\0'; 13951556Srgrimes opt->name = frpt; 13961556Srgrimes opt->value = pt; 13971556Srgrimes opt->fow = NULL; 13981556Srgrimes if (endpt != NULL) 13991556Srgrimes frpt = endpt + 1; 14001556Srgrimes else 14011556Srgrimes frpt = NULL; 14021556Srgrimes if (ophead == NULL) { 14031556Srgrimes optail = ophead = opt; 14041556Srgrimes continue; 14051556Srgrimes } 14061556Srgrimes optail->fow = opt; 14071556Srgrimes optail = opt; 14081556Srgrimes } 14091556Srgrimes return(0); 14101556Srgrimes} 14111556Srgrimes 14121556Srgrimes/* 14131556Srgrimes * str_offt() 14141556Srgrimes * Convert an expression of the following forms to an off_t > 0. 14151556Srgrimes * 1) A positive decimal number. 14161556Srgrimes * 2) A positive decimal number followed by a b (mult by 512). 14171556Srgrimes * 3) A positive decimal number followed by a k (mult by 1024). 14181556Srgrimes * 4) A positive decimal number followed by a m (mult by 512). 14191556Srgrimes * 5) A positive decimal number followed by a w (mult by sizeof int) 14201556Srgrimes * 6) Two or more positive decimal numbers (with/without k,b or w). 142172089Sasmodai * separated by x (also * for backwards compatibility), specifying 14221556Srgrimes * the product of the indicated values. 14231556Srgrimes * Return: 14241556Srgrimes * 0 for an error, a positive value o.w. 14251556Srgrimes */ 14261556Srgrimes 14271556Srgrimesstatic off_t 14281556Srgrimesstr_offt(char *val) 14291556Srgrimes{ 14301556Srgrimes char *expr; 14311556Srgrimes off_t num, t; 14321556Srgrimes 14331556Srgrimes# ifdef NET2_STAT 14341556Srgrimes num = strtol(val, &expr, 0); 14351556Srgrimes if ((num == LONG_MAX) || (num <= 0) || (expr == val)) 14361556Srgrimes# else 14371556Srgrimes num = strtoq(val, &expr, 0); 14381556Srgrimes if ((num == QUAD_MAX) || (num <= 0) || (expr == val)) 14391556Srgrimes# endif 14401556Srgrimes return(0); 14411556Srgrimes 14421556Srgrimes switch(*expr) { 14431556Srgrimes case 'b': 14441556Srgrimes t = num; 14451556Srgrimes num *= 512; 14461556Srgrimes if (t > num) 14471556Srgrimes return(0); 14481556Srgrimes ++expr; 14491556Srgrimes break; 14501556Srgrimes case 'k': 14511556Srgrimes t = num; 14521556Srgrimes num *= 1024; 14531556Srgrimes if (t > num) 14541556Srgrimes return(0); 14551556Srgrimes ++expr; 14561556Srgrimes break; 14571556Srgrimes case 'm': 14581556Srgrimes t = num; 14591556Srgrimes num *= 1048576; 14601556Srgrimes if (t > num) 14611556Srgrimes return(0); 14621556Srgrimes ++expr; 14631556Srgrimes break; 14641556Srgrimes case 'w': 14651556Srgrimes t = num; 14661556Srgrimes num *= sizeof(int); 14671556Srgrimes if (t > num) 14681556Srgrimes return(0); 14691556Srgrimes ++expr; 14701556Srgrimes break; 14711556Srgrimes } 14721556Srgrimes 14731556Srgrimes switch(*expr) { 14741556Srgrimes case '\0': 14751556Srgrimes break; 14761556Srgrimes case '*': 14771556Srgrimes case 'x': 14781556Srgrimes t = num; 14791556Srgrimes num *= str_offt(expr + 1); 14801556Srgrimes if (t > num) 14811556Srgrimes return(0); 14821556Srgrimes break; 14831556Srgrimes default: 14841556Srgrimes return(0); 14851556Srgrimes } 14861556Srgrimes return(num); 14871556Srgrimes} 14881556Srgrimes 148976351Skrischar * 149076351Skrisgetline(FILE *f) 149176351Skris{ 149276351Skris char *name, *temp; 149376351Skris size_t len; 149476351Skris 149576351Skris name = fgetln(f, &len); 149676351Skris if (!name) { 149776351Skris getline_error = ferror(f) ? GETLINE_FILE_CORRUPT : 0; 149876351Skris return(0); 149976351Skris } 150076351Skris if (name[len-1] != '\n') 150176351Skris len++; 150276351Skris temp = malloc(len); 150376351Skris if (!temp) { 150476351Skris getline_error = GETLINE_OUT_OF_MEM; 150576351Skris return(0); 150676351Skris } 150776351Skris memcpy(temp, name, len-1); 150876351Skris temp[len-1] = 0; 150976351Skris return(temp); 151076351Skris} 151176351Skris 15121556Srgrimes/* 15131556Srgrimes * no_op() 15141556Srgrimes * for those option functions where the archive format has nothing to do. 15151556Srgrimes * Return: 15161556Srgrimes * 0 15171556Srgrimes */ 15181556Srgrimes 15191556Srgrimesstatic int 15201556Srgrimesno_op(void) 15211556Srgrimes{ 15221556Srgrimes return(0); 15231556Srgrimes} 15241556Srgrimes 15251556Srgrimes/* 15261556Srgrimes * pax_usage() 15271556Srgrimes * print the usage summary to the user 15281556Srgrimes */ 15291556Srgrimes 15301556Srgrimesvoid 15311556Srgrimespax_usage(void) 15321556Srgrimes{ 1533281661Seadler (void)fputs("usage: pax [-cdnOvz] [-E limit] [-f archive] ", stderr); 15341556Srgrimes (void)fputs("[-s replstr] ... [-U user] ...", stderr); 153576019Skris (void)fputs("\n [-G group] ... ", stderr); 15361556Srgrimes (void)fputs("[-T [from_date][,to_date]] ... ", stderr); 15371556Srgrimes (void)fputs("[pattern ...]\n", stderr); 1538281661Seadler (void)fputs(" pax -r [-cdiknOuvzDYZ] [-E limit] ", stderr); 15391556Srgrimes (void)fputs("[-f archive] [-o options] ... \n", stderr); 154076019Skris (void)fputs(" [-p string] ... [-s replstr] ... ", stderr); 154176019Skris (void)fputs("[-U user] ... [-G group] ...\n ", stderr); 15421556Srgrimes (void)fputs("[-T [from_date][,to_date]] ... ", stderr); 15431556Srgrimes (void)fputs(" [pattern ...]\n", stderr); 1544281661Seadler (void)fputs(" pax -w [-dituvzHLOPX] [-b blocksize] ", stderr); 15451556Srgrimes (void)fputs("[ [-a] [-f archive] ] [-x format] \n", stderr); 154676019Skris (void)fputs(" [-B bytes] [-s replstr] ... ", stderr); 15471556Srgrimes (void)fputs("[-o options] ... [-U user] ...", stderr); 154876019Skris (void)fputs("\n [-G group] ... ", stderr); 15491556Srgrimes (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr); 15501556Srgrimes (void)fputs("[file ...]\n", stderr); 1551281661Seadler (void)fputs(" pax -r -w [-diklntuvDHLOPXYZ] ", stderr); 15521556Srgrimes (void)fputs("[-p string] ... [-s replstr] ...", stderr); 155376019Skris (void)fputs("\n [-U user] ... [-G group] ... ", stderr); 15541556Srgrimes (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr); 155576019Skris (void)fputs("\n [file ...] directory\n", stderr); 15561556Srgrimes exit(1); 15571556Srgrimes} 15581556Srgrimes 15591556Srgrimes/* 15601556Srgrimes * tar_usage() 15611556Srgrimes * print the usage summary to the user 15621556Srgrimes */ 15631556Srgrimes 15641556Srgrimesvoid 15651556Srgrimestar_usage(void) 15661556Srgrimes{ 156776351Skris (void)fputs("usage: tar [-]{crtux}[-befhjmopqsvwyzHLOPXZ014578] [blocksize] ", 15681556Srgrimes stderr); 156976351Skris (void)fputs("[archive] [replstr] [-C directory] [-I file] [file ...]\n", 157076351Skris stderr); 15711556Srgrimes exit(1); 15721556Srgrimes} 15731556Srgrimes 15741556Srgrimes/* 15751556Srgrimes * cpio_usage() 15761556Srgrimes * print the usage summary to the user 15771556Srgrimes */ 15781556Srgrimes 15791556Srgrimesvoid 15801556Srgrimescpio_usage(void) 15811556Srgrimes{ 158276351Skris (void)fputs("usage: cpio -o [-aABcLvVzZ] [-C bytes] [-H format] [-O archive]\n", stderr); 158376351Skris (void)fputs(" [-F archive] < name-list [> archive]\n", stderr); 158476351Skris (void)fputs(" cpio -i [-bBcdfmnrsStuvVzZ6] [-C bytes] [-E file] [-H format]\n", stderr); 158576351Skris (void)fputs(" [-I archive] [-F archive] [pattern...] [< archive]\n", stderr); 158676351Skris (void)fputs(" cpio -p [-adlLmuvV] destination-directory < name-list\n", stderr); 15871556Srgrimes exit(1); 15881556Srgrimes} 1589