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$"); 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 */ 19776286Skris while ((c=getopt(argc,argv,"ab:cdf:iklno:p:rs:tuvwx:zB:DE:G:HLPT: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; 4501556Srgrimes case 'P': 4511556Srgrimes /* 4521556Srgrimes * do NOT follow symlinks (default) 4531556Srgrimes */ 4541556Srgrimes Lflag = 0; 4551556Srgrimes flg |= CPF; 4561556Srgrimes break; 4571556Srgrimes case 'T': 4581556Srgrimes /* 4591556Srgrimes * non-standard option for selecting files within an 4601556Srgrimes * archive by modification time range (lower,upper) 4611556Srgrimes */ 4621556Srgrimes if (trng_add(optarg) < 0) { 4631556Srgrimes pax_usage(); 4641556Srgrimes break; 4651556Srgrimes } 4661556Srgrimes flg |= CTF; 4671556Srgrimes break; 4681556Srgrimes case 'U': 4691556Srgrimes /* 4701556Srgrimes * non-standard option for selecting files within an 4711556Srgrimes * archive by user (uid or name) 4721556Srgrimes */ 4731556Srgrimes if (usr_add(optarg) < 0) { 4741556Srgrimes pax_usage(); 4751556Srgrimes break; 4761556Srgrimes } 4771556Srgrimes flg |= CUF; 4781556Srgrimes break; 4791556Srgrimes case 'X': 4801556Srgrimes /* 481102230Strhodes * do not pass over mount points in the file system 4821556Srgrimes */ 4831556Srgrimes Xflag = 1; 4841556Srgrimes flg |= CXF; 4851556Srgrimes break; 4861556Srgrimes case 'Y': 4871556Srgrimes /* 4881556Srgrimes * On extraction check file inode change time after the 4891556Srgrimes * modification of the file name. Non standard option. 4901556Srgrimes */ 4911556Srgrimes Yflag = 1; 4921556Srgrimes flg |= CYF; 4931556Srgrimes break; 4941556Srgrimes case 'Z': 4951556Srgrimes /* 4961556Srgrimes * On extraction check modification time after the 4971556Srgrimes * modification of the file name. Non standard option. 4981556Srgrimes */ 4991556Srgrimes Zflag = 1; 5001556Srgrimes flg |= CZF; 5011556Srgrimes break; 5021556Srgrimes default: 5031556Srgrimes pax_usage(); 5041556Srgrimes break; 5051556Srgrimes } 5061556Srgrimes } 5071556Srgrimes 5081556Srgrimes /* 5091556Srgrimes * figure out the operation mode of pax read,write,extract,copy,append 5101556Srgrimes * or list. check that we have not been given a bogus set of flags 5111556Srgrimes * for the operation mode. 5121556Srgrimes */ 5131556Srgrimes if (ISLIST(flg)) { 5141556Srgrimes act = LIST; 51576351Skris listf = stdout; 5161556Srgrimes bflg = flg & BDLIST; 5171556Srgrimes } else if (ISEXTRACT(flg)) { 5181556Srgrimes act = EXTRACT; 5191556Srgrimes bflg = flg & BDEXTR; 5201556Srgrimes } else if (ISARCHIVE(flg)) { 5211556Srgrimes act = ARCHIVE; 5221556Srgrimes bflg = flg & BDARCH; 5231556Srgrimes } else if (ISAPPND(flg)) { 5241556Srgrimes act = APPND; 5251556Srgrimes bflg = flg & BDARCH; 5261556Srgrimes } else if (ISCOPY(flg)) { 5271556Srgrimes act = COPY; 5281556Srgrimes bflg = flg & BDCOPY; 5291556Srgrimes } else 5301556Srgrimes pax_usage(); 5311556Srgrimes if (bflg) { 5321556Srgrimes printflg(flg); 5331556Srgrimes pax_usage(); 5341556Srgrimes } 5351556Srgrimes 5361556Srgrimes /* 5371556Srgrimes * if we are writing (ARCHIVE) we use the default format if the user 5381556Srgrimes * did not specify a format. when we write during an APPEND, we will 5391556Srgrimes * adopt the format of the existing archive if none was supplied. 5401556Srgrimes */ 5411556Srgrimes if (!(flg & XF) && (act == ARCHIVE)) 5421556Srgrimes frmt = &(fsub[DEFLT]); 5431556Srgrimes 5441556Srgrimes /* 5451556Srgrimes * process the args as they are interpreted by the operation mode 5461556Srgrimes */ 5471556Srgrimes switch (act) { 5481556Srgrimes case LIST: 5491556Srgrimes case EXTRACT: 5501556Srgrimes for (; optind < argc; optind++) 55176351Skris if (pat_add(argv[optind], NULL) < 0) 5521556Srgrimes pax_usage(); 5531556Srgrimes break; 5541556Srgrimes case COPY: 5551556Srgrimes if (optind >= argc) { 55676017Skris paxwarn(0, "Destination directory was not supplied"); 5571556Srgrimes pax_usage(); 5581556Srgrimes } 5591556Srgrimes --argc; 5601556Srgrimes dirptr = argv[argc]; 56194553Scharnier /* FALLTHROUGH */ 5621556Srgrimes case ARCHIVE: 5631556Srgrimes case APPND: 5641556Srgrimes for (; optind < argc; optind++) 56576351Skris if (ftree_add(argv[optind], 0) < 0) 5661556Srgrimes pax_usage(); 5671556Srgrimes /* 5681556Srgrimes * no read errors allowed on updates/append operation! 5691556Srgrimes */ 5701556Srgrimes maxflt = 0; 5711556Srgrimes break; 5721556Srgrimes } 5731556Srgrimes} 5741556Srgrimes 5751556Srgrimes 5761556Srgrimes/* 5771556Srgrimes * tar_options() 5781556Srgrimes * look at the user specified flags. set globals as required and check if 5791556Srgrimes * the user specified a legal set of flags. If not, complain and exit 5801556Srgrimes */ 5811556Srgrimes 5821556Srgrimesstatic void 58390113Simptar_options(int argc, char **argv) 5841556Srgrimes{ 58590113Simp int c; 5861556Srgrimes int fstdin = 0; 58776351Skris int Oflag = 0; 58876351Skris int nincfiles = 0; 58976351Skris int incfiles_max = 0; 59076351Skris struct incfile { 59176351Skris char *file; 59276351Skris char *dir; 59376351Skris }; 59476351Skris struct incfile *incfiles = NULL; 5951556Srgrimes 5961556Srgrimes /* 59776351Skris * Set default values. 59876351Skris */ 59976351Skris rmleadslash = 1; 60076351Skris 60176351Skris /* 6021556Srgrimes * process option flags 6031556Srgrimes */ 60476351Skris while ((c = getoldopt(argc, argv, 60576351Skris "b:cef:hjmopqruts:vwxyzBC:HI:LOPXZ014578")) != -1) { 60676351Skris switch(c) { 6071556Srgrimes case 'b': 6081556Srgrimes /* 60976351Skris * specify blocksize in 512-byte blocks 6101556Srgrimes */ 61176351Skris if ((wrblksz = (int)str_offt(optarg)) <= 0) { 61276351Skris paxwarn(1, "Invalid block size %s", optarg); 6131556Srgrimes tar_usage(); 6141556Srgrimes } 61576351Skris wrblksz *= 512; /* XXX - check for int oflow */ 6161556Srgrimes break; 6171556Srgrimes case 'c': 6181556Srgrimes /* 6191556Srgrimes * create an archive 6201556Srgrimes */ 6211556Srgrimes act = ARCHIVE; 6221556Srgrimes break; 6231556Srgrimes case 'e': 6241556Srgrimes /* 6251556Srgrimes * stop after first error 6261556Srgrimes */ 6271556Srgrimes maxflt = 0; 6281556Srgrimes break; 6291556Srgrimes case 'f': 6301556Srgrimes /* 6311556Srgrimes * filename where the archive is stored 6321556Srgrimes */ 63376351Skris if ((optarg[0] == '-') && (optarg[1]== '\0')) { 6341556Srgrimes /* 6351556Srgrimes * treat a - as stdin 6361556Srgrimes */ 63776351Skris fstdin = 1; 63876351Skris arcname = NULL; 6391556Srgrimes break; 6401556Srgrimes } 6411556Srgrimes fstdin = 0; 64276351Skris arcname = optarg; 6431556Srgrimes break; 64476351Skris case 'h': 64576351Skris /* 64676351Skris * follow symlinks 64776351Skris */ 64876351Skris Lflag = 1; 64976351Skris break; 65076351Skris case 'j': 65176351Skris case 'y': 65276351Skris /* 65376351Skris * use bzip2. Non standard option. 65476351Skris */ 65576351Skris gzip_program = BZIP2_CMD; 65676351Skris break; 6571556Srgrimes case 'm': 6581556Srgrimes /* 6591556Srgrimes * do not preserve modification time 6601556Srgrimes */ 6611556Srgrimes pmtime = 0; 6621556Srgrimes break; 6631556Srgrimes case 'o': 6641556Srgrimes if (opt_add("write_opt=nodir") < 0) 6651556Srgrimes tar_usage(); 66676351Skris case 'O': 66776351Skris Oflag = 1; 6681556Srgrimes break; 6691556Srgrimes case 'p': 6701556Srgrimes /* 67176351Skris * preserve uid/gid and file mode, regardless of umask 6721556Srgrimes */ 67376351Skris pmode = 1; 6741556Srgrimes pids = 1; 6751556Srgrimes break; 67676351Skris case 'q': 67776351Skris /* 67876351Skris * select first match for a pattern only 67976351Skris */ 68076351Skris nflag = 1; 68176351Skris break; 6821556Srgrimes case 'r': 6831556Srgrimes case 'u': 6841556Srgrimes /* 6851556Srgrimes * append to the archive 6861556Srgrimes */ 6871556Srgrimes act = APPND; 6881556Srgrimes break; 68976351Skris case 's': 69076351Skris /* 69176351Skris * file name substitution name pattern 69276351Skris */ 69376351Skris if (rep_add(optarg) < 0) { 69476351Skris tar_usage(); 69576351Skris break; 69676351Skris } 69776351Skris break; 6981556Srgrimes case 't': 6991556Srgrimes /* 7001556Srgrimes * list contents of the tape 7011556Srgrimes */ 7021556Srgrimes act = LIST; 7031556Srgrimes break; 7041556Srgrimes case 'v': 7051556Srgrimes /* 7061556Srgrimes * verbose operation mode 7071556Srgrimes */ 70876351Skris vflag++; 7091556Srgrimes break; 7101556Srgrimes case 'w': 7111556Srgrimes /* 7121556Srgrimes * interactive file rename 7131556Srgrimes */ 7141556Srgrimes iflag = 1; 7151556Srgrimes break; 7161556Srgrimes case 'x': 7171556Srgrimes /* 71876351Skris * extract an archive, preserving mode, 71976351Skris * and mtime if possible. 7201556Srgrimes */ 7211556Srgrimes act = EXTRACT; 72276351Skris pmtime = 1; 7231556Srgrimes break; 72476286Skris case 'z': 72576286Skris /* 72676286Skris * use gzip. Non standard option. 72776286Skris */ 72876286Skris gzip_program = GZIP_CMD; 72976286Skris break; 7301556Srgrimes case 'B': 7311556Srgrimes /* 7321556Srgrimes * Nothing to do here, this is pax default 7331556Srgrimes */ 7341556Srgrimes break; 73576351Skris case 'C': 73676351Skris chdname = optarg; 73776351Skris break; 7381556Srgrimes case 'H': 7391556Srgrimes /* 7401556Srgrimes * follow command line symlinks only 7411556Srgrimes */ 7421556Srgrimes Hflag = 1; 7431556Srgrimes break; 74476351Skris case 'I': 74576351Skris if (++nincfiles > incfiles_max) { 74676351Skris incfiles_max = nincfiles + 3; 74776351Skris incfiles = realloc(incfiles, 74876351Skris sizeof(*incfiles) * incfiles_max); 74976351Skris if (incfiles == NULL) { 75076351Skris paxwarn(0, "Unable to allocate space " 75176351Skris "for option list"); 75276351Skris exit(1); 75376351Skris } 75476351Skris } 75576351Skris incfiles[nincfiles - 1].file = optarg; 75676351Skris incfiles[nincfiles - 1].dir = chdname; 75776351Skris break; 7581556Srgrimes case 'L': 7591556Srgrimes /* 7601556Srgrimes * follow symlinks 7611556Srgrimes */ 7621556Srgrimes Lflag = 1; 7631556Srgrimes break; 7641556Srgrimes case 'P': 7651556Srgrimes /* 76676351Skris * do not remove leading '/' from pathnames 7671556Srgrimes */ 76876351Skris rmleadslash = 0; 7691556Srgrimes break; 7701556Srgrimes case 'X': 7711556Srgrimes /* 772102230Strhodes * do not pass over mount points in the file system 7731556Srgrimes */ 7741556Srgrimes Xflag = 1; 7751556Srgrimes break; 77676286Skris case 'Z': 77776286Skris /* 77876286Skris * use compress. 77976286Skris */ 78076286Skris gzip_program = COMPRESS_CMD; 78176286Skris break; 7821556Srgrimes case '0': 7831556Srgrimes arcname = DEV_0; 7841556Srgrimes break; 7851556Srgrimes case '1': 7861556Srgrimes arcname = DEV_1; 7871556Srgrimes break; 7881556Srgrimes case '4': 7891556Srgrimes arcname = DEV_4; 7901556Srgrimes break; 7911556Srgrimes case '5': 7921556Srgrimes arcname = DEV_5; 7931556Srgrimes break; 7941556Srgrimes case '7': 7951556Srgrimes arcname = DEV_7; 7961556Srgrimes break; 7971556Srgrimes case '8': 7981556Srgrimes arcname = DEV_8; 7991556Srgrimes break; 8001556Srgrimes default: 8011556Srgrimes tar_usage(); 8021556Srgrimes break; 8031556Srgrimes } 8041556Srgrimes } 80576351Skris argc -= optind; 80676351Skris argv += optind; 8071556Srgrimes 80876351Skris /* Traditional tar behaviour (pax uses stderr unless in list mode) */ 80976351Skris if (fstdin == 1 && act == ARCHIVE) 81076351Skris listf = stderr; 81176351Skris else 81276351Skris listf = stdout; 81376351Skris 81476351Skris /* Traditional tar behaviour (pax wants to read file list from stdin) */ 81576351Skris if ((act == ARCHIVE || act == APPND) && argc == 0 && nincfiles == 0) 81676351Skris exit(0); 81776351Skris 8181556Srgrimes /* 8191556Srgrimes * if we are writing (ARCHIVE) specify tar, otherwise run like pax 82076351Skris * (unless -o specified) 8211556Srgrimes */ 82276351Skris if (act == ARCHIVE || act == APPND) 82376351Skris frmt = &(fsub[Oflag ? F_OTAR : F_TAR]); 82476351Skris else if (Oflag) { 82576351Skris paxwarn(1, "The -O/-o options are only valid when writing an archive"); 82676351Skris tar_usage(); /* only valid when writing */ 82776351Skris } 8281556Srgrimes 8291556Srgrimes /* 8301556Srgrimes * process the args as they are interpreted by the operation mode 8311556Srgrimes */ 8321556Srgrimes switch (act) { 8331556Srgrimes case LIST: 8341556Srgrimes case EXTRACT: 8351556Srgrimes default: 83676351Skris { 83776351Skris int sawpat = 0; 83876351Skris char *file, *dir = NULL; 83976351Skris 84076351Skris while (nincfiles || *argv != NULL) { 84176351Skris /* 84276351Skris * If we queued up any include files, 84376351Skris * pull them in now. Otherwise, check 84476351Skris * for -I and -C positional flags. 84576351Skris * Anything else must be a file to 84676351Skris * extract. 84776351Skris */ 84876351Skris if (nincfiles) { 84976351Skris file = incfiles->file; 85076351Skris dir = incfiles->dir; 85176351Skris incfiles++; 85276351Skris nincfiles--; 85376351Skris } else if (strcmp(*argv, "-I") == 0) { 85476351Skris if (*++argv == NULL) 85576351Skris break; 85676351Skris file = *argv++; 85776351Skris dir = chdname; 85876351Skris } else 85976351Skris file = NULL; 86076351Skris if (file != NULL) { 86176351Skris FILE *fp; 86276351Skris char *str; 86376351Skris 86476351Skris if (strcmp(file, "-") == 0) 86576351Skris fp = stdin; 86676351Skris else if ((fp = fopen(file, "r")) == NULL) { 86776351Skris paxwarn(1, "Unable to open file '%s' for read", file); 86876351Skris tar_usage(); 86976351Skris } 87076351Skris while ((str = getline(fp)) != NULL) { 87176351Skris if (pat_add(str, dir) < 0) 87276351Skris tar_usage(); 87376351Skris sawpat = 1; 87476351Skris } 87576351Skris if (strcmp(file, "-") != 0) 87676351Skris fclose(fp); 87776351Skris if (getline_error) { 87876351Skris paxwarn(1, "Problem with file '%s'", file); 87976351Skris tar_usage(); 88076351Skris } 88176351Skris } else if (strcmp(*argv, "-C") == 0) { 88276351Skris if (*++argv == NULL) 88376351Skris break; 88476351Skris chdname = *argv++; 88576351Skris } else if (pat_add(*argv++, chdname) < 0) 88676351Skris tar_usage(); 88776351Skris else 88876351Skris sawpat = 1; 88976351Skris } 89076351Skris /* 891222177Suqs * if patterns were added, we are doing chdir() 89276351Skris * on a file-by-file basis, else, just one 89376351Skris * global chdir (if any) after opening input. 89476351Skris */ 89576351Skris if (sawpat > 0) 89676351Skris chdname = NULL; 89776351Skris } 8981556Srgrimes break; 8991556Srgrimes case ARCHIVE: 9001556Srgrimes case APPND: 90176351Skris if (chdname != NULL) { /* initial chdir() */ 90276351Skris if (ftree_add(chdname, 1) < 0) 9031556Srgrimes tar_usage(); 90476351Skris } 90576351Skris 90676351Skris while (nincfiles || *argv != NULL) { 90776351Skris char *file, *dir = NULL; 90876351Skris 90976351Skris /* 91076351Skris * If we queued up any include files, pull them in 91176351Skris * now. Otherwise, check for -I and -C positional 91276351Skris * flags. Anything else must be a file to include 91376351Skris * in the archive. 91476351Skris */ 91576351Skris if (nincfiles) { 91676351Skris file = incfiles->file; 91776351Skris dir = incfiles->dir; 91876351Skris incfiles++; 91976351Skris nincfiles--; 92076351Skris } else if (strcmp(*argv, "-I") == 0) { 92176351Skris if (*++argv == NULL) 92276351Skris break; 92376351Skris file = *argv++; 92476351Skris dir = NULL; 92576351Skris } else 92676351Skris file = NULL; 92776351Skris if (file != NULL) { 92876351Skris FILE *fp; 92976351Skris char *str; 93076351Skris 93176351Skris /* Set directory if needed */ 93276351Skris if (dir) { 93376351Skris if (ftree_add(dir, 1) < 0) 93476351Skris tar_usage(); 93576351Skris } 93676351Skris 93776351Skris if (strcmp(file, "-") == 0) 93876351Skris fp = stdin; 93976351Skris else if ((fp = fopen(file, "r")) == NULL) { 94076351Skris paxwarn(1, "Unable to open file '%s' for read", file); 94176351Skris tar_usage(); 94276351Skris } 94376351Skris while ((str = getline(fp)) != NULL) { 94476351Skris if (ftree_add(str, 0) < 0) 94576351Skris tar_usage(); 94676351Skris } 94776351Skris if (strcmp(file, "-") != 0) 94876351Skris fclose(fp); 94976351Skris if (getline_error) { 95076351Skris paxwarn(1, "Problem with file '%s'", 95176351Skris file); 95276351Skris tar_usage(); 95376351Skris } 95476351Skris } else if (strcmp(*argv, "-C") == 0) { 95576351Skris if (*++argv == NULL) 95676351Skris break; 95776351Skris if (ftree_add(*argv++, 1) < 0) 95876351Skris tar_usage(); 95976351Skris } else if (ftree_add(*argv++, 0) < 0) 96076351Skris tar_usage(); 96176351Skris } 9621556Srgrimes /* 9631556Srgrimes * no read errors allowed on updates/append operation! 9641556Srgrimes */ 9651556Srgrimes maxflt = 0; 9661556Srgrimes break; 9671556Srgrimes } 96876017Skris if (!fstdin && ((arcname == NULL) || (*arcname == '\0'))) { 9691556Srgrimes arcname = getenv("TAPE"); 97076017Skris if ((arcname == NULL) || (*arcname == '\0')) 97176351Skris arcname = _PATH_DEFTAPE; 9721556Srgrimes } 9731556Srgrimes} 9741556Srgrimes 975114583Smarkmstatic int 976114583Smarkmmkpath(char *path) 97776351Skris{ 97876351Skris struct stat sb; 97990113Simp char *slash; 98076351Skris int done = 0; 98176351Skris 98276351Skris slash = path; 98376351Skris 98476351Skris while (!done) { 98576351Skris slash += strspn(slash, "/"); 98676351Skris slash += strcspn(slash, "/"); 98776351Skris 98876351Skris done = (*slash == '\0'); 98976351Skris *slash = '\0'; 99076351Skris 99176351Skris if (stat(path, &sb)) { 99276351Skris if (errno != ENOENT || mkdir(path, 0777)) { 99376351Skris paxwarn(1, "%s", path); 99476351Skris return (-1); 99576351Skris } 99676351Skris } else if (!S_ISDIR(sb.st_mode)) { 99776351Skris syswarn(1, ENOTDIR, "%s", path); 99876351Skris return (-1); 99976351Skris } 100076351Skris 100176351Skris if (!done) 100276351Skris *slash = '/'; 100376351Skris } 100476351Skris 100576351Skris return (0); 100676351Skris} 10071556Srgrimes/* 10081556Srgrimes * cpio_options() 10091556Srgrimes * look at the user specified flags. set globals as required and check if 10101556Srgrimes * the user specified a legal set of flags. If not, complain and exit 10111556Srgrimes */ 10121556Srgrimes 10131556Srgrimesstatic void 101490113Simpcpio_options(int argc, char **argv) 10151556Srgrimes{ 1016114469Sobrien int c; 1017114469Sobrien size_t i; 101876351Skris char *str; 101976351Skris FSUB tmp; 102076351Skris FILE *fp; 102176351Skris 102276351Skris kflag = 1; 102376351Skris pids = 1; 102476351Skris pmode = 1; 102576351Skris pmtime = 0; 102676351Skris arcname = NULL; 102776351Skris dflag = 1; 102876351Skris act = -1; 102976351Skris nodirs = 1; 103076351Skris while ((c=getopt(argc,argv,"abcdfiklmoprstuvzABC:E:F:H:I:LO:SZ6")) != -1) 103176351Skris switch (c) { 103276351Skris case 'a': 103376351Skris /* 103476351Skris * preserve access time on files read 103576351Skris */ 103676351Skris tflag = 1; 103776351Skris break; 103876351Skris case 'b': 103976351Skris /* 104076351Skris * swap bytes and half-words when reading data 104176351Skris */ 104276351Skris break; 104376351Skris case 'c': 104476351Skris /* 104576351Skris * ASCII cpio header 104676351Skris */ 104776351Skris frmt = &(fsub[F_ACPIO]); 104876351Skris break; 104976351Skris case 'd': 105076351Skris /* 105176351Skris * create directories as needed 105276351Skris */ 105376351Skris nodirs = 0; 105476351Skris break; 105576351Skris case 'f': 105676351Skris /* 105776351Skris * invert meaning of pattern list 105876351Skris */ 105976351Skris cflag = 1; 106076351Skris break; 106176351Skris case 'i': 106276351Skris /* 106376351Skris * restore an archive 106476351Skris */ 106576351Skris act = EXTRACT; 106676351Skris break; 106776351Skris case 'k': 106876351Skris break; 106976351Skris case 'l': 107076351Skris /* 107176351Skris * use links instead of copies when possible 107276351Skris */ 107376351Skris lflag = 1; 107476351Skris break; 107576351Skris case 'm': 107676351Skris /* 107776351Skris * preserve modification time 107876351Skris */ 107976351Skris pmtime = 1; 108076351Skris break; 108176351Skris case 'o': 108276351Skris /* 108376351Skris * create an archive 108476351Skris */ 108576351Skris act = ARCHIVE; 108676351Skris frmt = &(fsub[F_CPIO]); 108776351Skris break; 108876351Skris case 'p': 108976351Skris /* 109076351Skris * copy-pass mode 109176351Skris */ 109276351Skris act = COPY; 109376351Skris break; 109476351Skris case 'r': 109576351Skris /* 109676351Skris * interactively rename files 109776351Skris */ 109876351Skris iflag = 1; 109976351Skris break; 110076351Skris case 's': 110176351Skris /* 110276351Skris * swap bytes after reading data 110376351Skris */ 110476351Skris break; 110576351Skris case 't': 110676351Skris /* 110776351Skris * list contents of archive 110876351Skris */ 110976351Skris act = LIST; 111076351Skris listf = stdout; 111176351Skris break; 111276351Skris case 'u': 111376351Skris /* 111476351Skris * replace newer files 111576351Skris */ 111676351Skris kflag = 0; 111776351Skris break; 111876351Skris case 'v': 111976351Skris /* 112076351Skris * verbose operation mode 112176351Skris */ 112276351Skris vflag = 1; 112376351Skris break; 112476351Skris case 'z': 112576351Skris /* 112676351Skris * use gzip. Non standard option. 112776351Skris */ 112876351Skris gzip_program = GZIP_CMD; 112976351Skris break; 113076351Skris case 'A': 113176351Skris /* 113276351Skris * append mode 113376351Skris */ 113476351Skris act = APPND; 113576351Skris break; 113676351Skris case 'B': 113776351Skris /* 113876351Skris * Use 5120 byte block size 113976351Skris */ 114076351Skris wrblksz = 5120; 114176351Skris break; 114276351Skris case 'C': 114376351Skris /* 114476351Skris * set block size in bytes 114576351Skris */ 114676351Skris wrblksz = atoi(optarg); 114776351Skris break; 114876351Skris case 'E': 114976351Skris /* 115076351Skris * file with patterns to extract or list 115176351Skris */ 115276351Skris if ((fp = fopen(optarg, "r")) == NULL) { 115376351Skris paxwarn(1, "Unable to open file '%s' for read", optarg); 115476351Skris cpio_usage(); 115576351Skris } 115676351Skris while ((str = getline(fp)) != NULL) { 115776351Skris pat_add(str, NULL); 115876351Skris } 115976351Skris fclose(fp); 116076351Skris if (getline_error) { 116176351Skris paxwarn(1, "Problem with file '%s'", optarg); 116276351Skris cpio_usage(); 116376351Skris } 116476351Skris break; 116576351Skris case 'F': 116676351Skris case 'I': 116776351Skris case 'O': 116876351Skris /* 116976351Skris * filename where the archive is stored 117076351Skris */ 117176351Skris if ((optarg[0] == '-') && (optarg[1]== '\0')) { 117276351Skris /* 117376351Skris * treat a - as stdin 117476351Skris */ 117576351Skris arcname = NULL; 117676351Skris break; 117776351Skris } 117876351Skris arcname = optarg; 117976351Skris break; 118076351Skris case 'H': 118176351Skris /* 118276351Skris * specify an archive format on write 118376351Skris */ 118476351Skris tmp.name = optarg; 118576351Skris if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub, 118676351Skris sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL) 118776351Skris break; 118876351Skris paxwarn(1, "Unknown -H format: %s", optarg); 118976351Skris (void)fputs("cpio: Known -H formats are:", stderr); 119076351Skris for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i) 119176351Skris (void)fprintf(stderr, " %s", fsub[i].name); 119276351Skris (void)fputs("\n\n", stderr); 119376351Skris cpio_usage(); 119476351Skris break; 119576351Skris case 'L': 119676351Skris /* 119776351Skris * follow symbolic links 119876351Skris */ 119976351Skris Lflag = 1; 120076351Skris break; 120176351Skris case 'S': 120276351Skris /* 120376351Skris * swap halfwords after reading data 120476351Skris */ 120576351Skris break; 120676351Skris case 'Z': 120776351Skris /* 120876351Skris * use compress. Non standard option. 120976351Skris */ 121076351Skris gzip_program = COMPRESS_CMD; 121176351Skris break; 121276351Skris case '6': 121376351Skris /* 121476351Skris * process Version 6 cpio format 121576351Skris */ 121676351Skris frmt = &(fsub[F_OCPIO]); 121776351Skris break; 121876351Skris case '?': 121976351Skris default: 122076351Skris cpio_usage(); 122176351Skris break; 122276351Skris } 122376351Skris argc -= optind; 122476351Skris argv += optind; 122576351Skris 122676351Skris /* 122776351Skris * process the args as they are interpreted by the operation mode 122876351Skris */ 122976351Skris switch (act) { 123076351Skris case LIST: 123176351Skris case EXTRACT: 123276351Skris while (*argv != NULL) 123376351Skris if (pat_add(*argv++, NULL) < 0) 123476351Skris cpio_usage(); 123576351Skris break; 123676351Skris case COPY: 123776351Skris if (*argv == NULL) { 123876351Skris paxwarn(0, "Destination directory was not supplied"); 123976351Skris cpio_usage(); 124076351Skris } 124176351Skris dirptr = *argv; 124276351Skris if (mkpath(dirptr) < 0) 124376351Skris cpio_usage(); 124476351Skris --argc; 124576351Skris ++argv; 124694553Scharnier /* FALLTHROUGH */ 124776351Skris case ARCHIVE: 124876351Skris case APPND: 124976351Skris if (*argv != NULL) 125076351Skris cpio_usage(); 125176351Skris /* 125276351Skris * no read errors allowed on updates/append operation! 125376351Skris */ 125476351Skris maxflt = 0; 125576351Skris while ((str = getline(stdin)) != NULL) { 1256126643Smarkm ftree_add(str, 0); 125776351Skris } 125876351Skris if (getline_error) { 125976351Skris paxwarn(1, "Problem while reading stdin"); 126076351Skris cpio_usage(); 126176351Skris } 126276351Skris break; 126376351Skris default: 126476351Skris cpio_usage(); 126576351Skris break; 126676351Skris } 12671556Srgrimes} 12681556Srgrimes 12691556Srgrimes/* 12701556Srgrimes * printflg() 12711556Srgrimes * print out those invalid flag sets found to the user 12721556Srgrimes */ 12731556Srgrimes 12741556Srgrimesstatic void 12751556Srgrimesprintflg(unsigned int flg) 12761556Srgrimes{ 12771556Srgrimes int nxt; 12781556Srgrimes int pos = 0; 12791556Srgrimes 12801556Srgrimes (void)fprintf(stderr,"%s: Invalid combination of options:", argv0); 128176351Skris while ((nxt = ffs(flg)) != 0) { 12821556Srgrimes flg = flg >> nxt; 12831556Srgrimes pos += nxt; 12841556Srgrimes (void)fprintf(stderr, " -%c", flgch[pos-1]); 12851556Srgrimes } 12861556Srgrimes (void)putc('\n', stderr); 12871556Srgrimes} 12881556Srgrimes 12891556Srgrimes/* 12901556Srgrimes * c_frmt() 12911556Srgrimes * comparison routine used by bsearch to find the format specified 12921556Srgrimes * by the user 12931556Srgrimes */ 12941556Srgrimes 12951556Srgrimesstatic int 12961556Srgrimesc_frmt(const void *a, const void *b) 12971556Srgrimes{ 1298114583Smarkm return(strcmp(((const FSUB *)a)->name, ((const FSUB *)b)->name)); 12991556Srgrimes} 13001556Srgrimes 13011556Srgrimes/* 13021556Srgrimes * opt_next() 13031556Srgrimes * called by format specific options routines to get each format specific 13041556Srgrimes * flag and value specified with -o 13051556Srgrimes * Return: 13061556Srgrimes * pointer to next OPLIST entry or NULL (end of list). 13071556Srgrimes */ 13081556Srgrimes 13091556SrgrimesOPLIST * 13101556Srgrimesopt_next(void) 13111556Srgrimes{ 13121556Srgrimes OPLIST *opt; 13131556Srgrimes 13141556Srgrimes if ((opt = ophead) != NULL) 13151556Srgrimes ophead = ophead->fow; 13161556Srgrimes return(opt); 13171556Srgrimes} 13181556Srgrimes 13191556Srgrimes/* 13201556Srgrimes * bad_opt() 13211556Srgrimes * generic routine used to complain about a format specific options 13221556Srgrimes * when the format does not support options. 13231556Srgrimes */ 13241556Srgrimes 13251556Srgrimesint 13261556Srgrimesbad_opt(void) 13271556Srgrimes{ 132890113Simp OPLIST *opt; 13291556Srgrimes 13301556Srgrimes if (ophead == NULL) 13311556Srgrimes return(0); 13321556Srgrimes /* 13331556Srgrimes * print all we were given 13341556Srgrimes */ 133576017Skris paxwarn(1,"These format options are not supported"); 13361556Srgrimes while ((opt = opt_next()) != NULL) 13371556Srgrimes (void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value); 13381556Srgrimes pax_usage(); 13391556Srgrimes return(0); 13401556Srgrimes} 13411556Srgrimes 13421556Srgrimes/* 13431556Srgrimes * opt_add() 1344108533Sschweikh * breaks the value supplied to -o into an option name and value. Options 13451556Srgrimes * are given to -o in the form -o name-value,name=value 134646684Skris * multiple -o may be specified. 13471556Srgrimes * Return: 1348108533Sschweikh * 0 if format in name=value format, -1 if -o is passed junk. 13491556Srgrimes */ 13501556Srgrimes 13511556Srgrimesint 1352114583Smarkmopt_add(const char *str) 13531556Srgrimes{ 135490113Simp OPLIST *opt; 135590113Simp char *frpt; 135690113Simp char *pt; 135790113Simp char *endpt; 1358114583Smarkm char *lstr; 13591556Srgrimes 13601556Srgrimes if ((str == NULL) || (*str == '\0')) { 136176017Skris paxwarn(0, "Invalid option name"); 13621556Srgrimes return(-1); 13631556Srgrimes } 1364114583Smarkm if ((lstr = strdup(str)) == NULL) { 136576351Skris paxwarn(0, "Unable to allocate space for option list"); 136676351Skris return(-1); 136776351Skris } 1368114583Smarkm frpt = endpt = lstr; 13691556Srgrimes 13701556Srgrimes /* 13711556Srgrimes * break into name and values pieces and stuff each one into a 13721556Srgrimes * OPLIST structure. When we know the format, the format specific 13731556Srgrimes * option function will go through this list 13741556Srgrimes */ 13751556Srgrimes while ((frpt != NULL) && (*frpt != '\0')) { 13761556Srgrimes if ((endpt = strchr(frpt, ',')) != NULL) 13771556Srgrimes *endpt = '\0'; 13781556Srgrimes if ((pt = strchr(frpt, '=')) == NULL) { 137976017Skris paxwarn(0, "Invalid options format"); 1380114583Smarkm free(lstr); 13811556Srgrimes return(-1); 13821556Srgrimes } 13831556Srgrimes if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) { 138476017Skris paxwarn(0, "Unable to allocate space for option list"); 1385114583Smarkm free(lstr); 13861556Srgrimes return(-1); 13871556Srgrimes } 13881556Srgrimes *pt++ = '\0'; 13891556Srgrimes opt->name = frpt; 13901556Srgrimes opt->value = pt; 13911556Srgrimes opt->fow = NULL; 13921556Srgrimes if (endpt != NULL) 13931556Srgrimes frpt = endpt + 1; 13941556Srgrimes else 13951556Srgrimes frpt = NULL; 13961556Srgrimes if (ophead == NULL) { 13971556Srgrimes optail = ophead = opt; 13981556Srgrimes continue; 13991556Srgrimes } 14001556Srgrimes optail->fow = opt; 14011556Srgrimes optail = opt; 14021556Srgrimes } 14031556Srgrimes return(0); 14041556Srgrimes} 14051556Srgrimes 14061556Srgrimes/* 14071556Srgrimes * str_offt() 14081556Srgrimes * Convert an expression of the following forms to an off_t > 0. 14091556Srgrimes * 1) A positive decimal number. 14101556Srgrimes * 2) A positive decimal number followed by a b (mult by 512). 14111556Srgrimes * 3) A positive decimal number followed by a k (mult by 1024). 14121556Srgrimes * 4) A positive decimal number followed by a m (mult by 512). 14131556Srgrimes * 5) A positive decimal number followed by a w (mult by sizeof int) 14141556Srgrimes * 6) Two or more positive decimal numbers (with/without k,b or w). 141572089Sasmodai * separated by x (also * for backwards compatibility), specifying 14161556Srgrimes * the product of the indicated values. 14171556Srgrimes * Return: 14181556Srgrimes * 0 for an error, a positive value o.w. 14191556Srgrimes */ 14201556Srgrimes 14211556Srgrimesstatic off_t 14221556Srgrimesstr_offt(char *val) 14231556Srgrimes{ 14241556Srgrimes char *expr; 14251556Srgrimes off_t num, t; 14261556Srgrimes 14271556Srgrimes# ifdef NET2_STAT 14281556Srgrimes num = strtol(val, &expr, 0); 14291556Srgrimes if ((num == LONG_MAX) || (num <= 0) || (expr == val)) 14301556Srgrimes# else 14311556Srgrimes num = strtoq(val, &expr, 0); 14321556Srgrimes if ((num == QUAD_MAX) || (num <= 0) || (expr == val)) 14331556Srgrimes# endif 14341556Srgrimes return(0); 14351556Srgrimes 14361556Srgrimes switch(*expr) { 14371556Srgrimes case 'b': 14381556Srgrimes t = num; 14391556Srgrimes num *= 512; 14401556Srgrimes if (t > num) 14411556Srgrimes return(0); 14421556Srgrimes ++expr; 14431556Srgrimes break; 14441556Srgrimes case 'k': 14451556Srgrimes t = num; 14461556Srgrimes num *= 1024; 14471556Srgrimes if (t > num) 14481556Srgrimes return(0); 14491556Srgrimes ++expr; 14501556Srgrimes break; 14511556Srgrimes case 'm': 14521556Srgrimes t = num; 14531556Srgrimes num *= 1048576; 14541556Srgrimes if (t > num) 14551556Srgrimes return(0); 14561556Srgrimes ++expr; 14571556Srgrimes break; 14581556Srgrimes case 'w': 14591556Srgrimes t = num; 14601556Srgrimes num *= sizeof(int); 14611556Srgrimes if (t > num) 14621556Srgrimes return(0); 14631556Srgrimes ++expr; 14641556Srgrimes break; 14651556Srgrimes } 14661556Srgrimes 14671556Srgrimes switch(*expr) { 14681556Srgrimes case '\0': 14691556Srgrimes break; 14701556Srgrimes case '*': 14711556Srgrimes case 'x': 14721556Srgrimes t = num; 14731556Srgrimes num *= str_offt(expr + 1); 14741556Srgrimes if (t > num) 14751556Srgrimes return(0); 14761556Srgrimes break; 14771556Srgrimes default: 14781556Srgrimes return(0); 14791556Srgrimes } 14801556Srgrimes return(num); 14811556Srgrimes} 14821556Srgrimes 148376351Skrischar * 148476351Skrisgetline(FILE *f) 148576351Skris{ 148676351Skris char *name, *temp; 148776351Skris size_t len; 148876351Skris 148976351Skris name = fgetln(f, &len); 149076351Skris if (!name) { 149176351Skris getline_error = ferror(f) ? GETLINE_FILE_CORRUPT : 0; 149276351Skris return(0); 149376351Skris } 149476351Skris if (name[len-1] != '\n') 149576351Skris len++; 149676351Skris temp = malloc(len); 149776351Skris if (!temp) { 149876351Skris getline_error = GETLINE_OUT_OF_MEM; 149976351Skris return(0); 150076351Skris } 150176351Skris memcpy(temp, name, len-1); 150276351Skris temp[len-1] = 0; 150376351Skris return(temp); 150476351Skris} 150576351Skris 15061556Srgrimes/* 15071556Srgrimes * no_op() 15081556Srgrimes * for those option functions where the archive format has nothing to do. 15091556Srgrimes * Return: 15101556Srgrimes * 0 15111556Srgrimes */ 15121556Srgrimes 15131556Srgrimesstatic int 15141556Srgrimesno_op(void) 15151556Srgrimes{ 15161556Srgrimes return(0); 15171556Srgrimes} 15181556Srgrimes 15191556Srgrimes/* 15201556Srgrimes * pax_usage() 15211556Srgrimes * print the usage summary to the user 15221556Srgrimes */ 15231556Srgrimes 15241556Srgrimesvoid 15251556Srgrimespax_usage(void) 15261556Srgrimes{ 152776286Skris (void)fputs("usage: pax [-cdnvz] [-E limit] [-f archive] ", stderr); 15281556Srgrimes (void)fputs("[-s replstr] ... [-U user] ...", stderr); 152976019Skris (void)fputs("\n [-G group] ... ", stderr); 15301556Srgrimes (void)fputs("[-T [from_date][,to_date]] ... ", stderr); 15311556Srgrimes (void)fputs("[pattern ...]\n", stderr); 153276286Skris (void)fputs(" pax -r [-cdiknuvzDYZ] [-E limit] ", stderr); 15331556Srgrimes (void)fputs("[-f archive] [-o options] ... \n", stderr); 153476019Skris (void)fputs(" [-p string] ... [-s replstr] ... ", stderr); 153576019Skris (void)fputs("[-U user] ... [-G group] ...\n ", stderr); 15361556Srgrimes (void)fputs("[-T [from_date][,to_date]] ... ", stderr); 15371556Srgrimes (void)fputs(" [pattern ...]\n", stderr); 153876286Skris (void)fputs(" pax -w [-dituvzHLPX] [-b blocksize] ", stderr); 15391556Srgrimes (void)fputs("[ [-a] [-f archive] ] [-x format] \n", stderr); 154076019Skris (void)fputs(" [-B bytes] [-s replstr] ... ", stderr); 15411556Srgrimes (void)fputs("[-o options] ... [-U user] ...", stderr); 154276019Skris (void)fputs("\n [-G group] ... ", stderr); 15431556Srgrimes (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr); 15441556Srgrimes (void)fputs("[file ...]\n", stderr); 15451556Srgrimes (void)fputs(" pax -r -w [-diklntuvDHLPXYZ] ", stderr); 15461556Srgrimes (void)fputs("[-p string] ... [-s replstr] ...", stderr); 154776019Skris (void)fputs("\n [-U user] ... [-G group] ... ", stderr); 15481556Srgrimes (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr); 154976019Skris (void)fputs("\n [file ...] directory\n", stderr); 15501556Srgrimes exit(1); 15511556Srgrimes} 15521556Srgrimes 15531556Srgrimes/* 15541556Srgrimes * tar_usage() 15551556Srgrimes * print the usage summary to the user 15561556Srgrimes */ 15571556Srgrimes 15581556Srgrimesvoid 15591556Srgrimestar_usage(void) 15601556Srgrimes{ 156176351Skris (void)fputs("usage: tar [-]{crtux}[-befhjmopqsvwyzHLOPXZ014578] [blocksize] ", 15621556Srgrimes stderr); 156376351Skris (void)fputs("[archive] [replstr] [-C directory] [-I file] [file ...]\n", 156476351Skris stderr); 15651556Srgrimes exit(1); 15661556Srgrimes} 15671556Srgrimes 15681556Srgrimes/* 15691556Srgrimes * cpio_usage() 15701556Srgrimes * print the usage summary to the user 15711556Srgrimes */ 15721556Srgrimes 15731556Srgrimesvoid 15741556Srgrimescpio_usage(void) 15751556Srgrimes{ 157676351Skris (void)fputs("usage: cpio -o [-aABcLvVzZ] [-C bytes] [-H format] [-O archive]\n", stderr); 157776351Skris (void)fputs(" [-F archive] < name-list [> archive]\n", stderr); 157876351Skris (void)fputs(" cpio -i [-bBcdfmnrsStuvVzZ6] [-C bytes] [-E file] [-H format]\n", stderr); 157976351Skris (void)fputs(" [-I archive] [-F archive] [pattern...] [< archive]\n", stderr); 158076351Skris (void)fputs(" cpio -p [-adlLmuvV] destination-directory < name-list\n", stderr); 15811556Srgrimes exit(1); 15821556Srgrimes} 1583