1*8758bb59Smillert /* $OpenBSD: options.c,v 1.115 2024/05/10 20:28:31 millert Exp $ */
28ab05b7eSderaadt /* $NetBSD: options.c,v 1.6 1996/03/26 23:54:18 mrg Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*-
5df930be7Sderaadt * Copyright (c) 1992 Keith Muller.
6df930be7Sderaadt * Copyright (c) 1992, 1993
7df930be7Sderaadt * The Regents of the University of California. All rights reserved.
8df930be7Sderaadt *
9df930be7Sderaadt * This code is derived from software contributed to Berkeley by
10df930be7Sderaadt * Keith Muller of the University of California, San Diego.
11df930be7Sderaadt *
12df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
13df930be7Sderaadt * modification, are permitted provided that the following conditions
14df930be7Sderaadt * are met:
15df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
16df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
17df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
18df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
19df930be7Sderaadt * documentation and/or other materials provided with the distribution.
2029295d1cSmillert * 3. Neither the name of the University nor the names of its contributors
21df930be7Sderaadt * may be used to endorse or promote products derived from this software
22df930be7Sderaadt * without specific prior written permission.
23df930be7Sderaadt *
24df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34df930be7Sderaadt * SUCH DAMAGE.
35df930be7Sderaadt */
36df930be7Sderaadt
37df930be7Sderaadt #include <sys/types.h>
38df930be7Sderaadt #include <sys/stat.h>
393c2af966Sdownsj #include <errno.h>
40df930be7Sderaadt #include <limits.h>
41ea101a60Smillert #include <paths.h>
42bcbfc94fSguenther #include <stdio.h>
43bcbfc94fSguenther #include <stdlib.h>
44bcbfc94fSguenther #include <string.h>
45bcbfc94fSguenther #include <unistd.h>
46bcbfc94fSguenther
47df930be7Sderaadt #include "pax.h"
48df930be7Sderaadt #include "cpio.h"
49df930be7Sderaadt #include "tar.h"
50df930be7Sderaadt #include "extern.h"
51df930be7Sderaadt
52c01bd743Sespie static int bad_opt(void);
53c01bd743Sespie static int opt_add(const char *);
54df930be7Sderaadt /*
55bcbfc94fSguenther * argv[0] names. Used for tar and cpio emulation
56bcbfc94fSguenther */
57bcbfc94fSguenther
58bcbfc94fSguenther #define NM_TAR "tar"
59bcbfc94fSguenther #define NM_CPIO "cpio"
60bcbfc94fSguenther #define NM_PAX "pax"
61bcbfc94fSguenther
62bcbfc94fSguenther /*
63bcbfc94fSguenther * Constants used to specify the legal sets of flags in pax. For each major
64bcbfc94fSguenther * operation mode of pax, a set of illegal flags is defined. If any one of
65bcbfc94fSguenther * those illegal flags are found set, we scream and exit
66bcbfc94fSguenther */
67bcbfc94fSguenther
68bcbfc94fSguenther /*
69bcbfc94fSguenther * flags (one for each option).
70bcbfc94fSguenther */
71bcbfc94fSguenther #define AF 0x00000001
72bcbfc94fSguenther #define BF 0x00000002
73bcbfc94fSguenther #define CF 0x00000004
74bcbfc94fSguenther #define DF 0x00000008
75bcbfc94fSguenther #define FF 0x00000010
76bcbfc94fSguenther #define IF 0x00000020
77bcbfc94fSguenther #define KF 0x00000040
78bcbfc94fSguenther #define LF 0x00000080
79bcbfc94fSguenther #define NF 0x00000100
80bcbfc94fSguenther #define OF 0x00000200
81bcbfc94fSguenther #define PF 0x00000400
82bcbfc94fSguenther #define RF 0x00000800
83bcbfc94fSguenther #define SF 0x00001000
84bcbfc94fSguenther #define TF 0x00002000
85bcbfc94fSguenther #define UF 0x00004000
86bcbfc94fSguenther #define VF 0x00008000
87bcbfc94fSguenther #define WF 0x00010000
88bcbfc94fSguenther #define XF 0x00020000
89bcbfc94fSguenther #define CBF 0x00040000 /* nonstandard extension */
90bcbfc94fSguenther #define CDF 0x00080000 /* nonstandard extension */
91bcbfc94fSguenther #define CEF 0x00100000 /* nonstandard extension */
92bcbfc94fSguenther #define CGF 0x00200000 /* nonstandard extension */
93bcbfc94fSguenther #define CHF 0x00400000 /* nonstandard extension */
94bcbfc94fSguenther #define CLF 0x00800000 /* nonstandard extension */
95bcbfc94fSguenther #define CPF 0x01000000 /* nonstandard extension */
96bcbfc94fSguenther #define CTF 0x02000000 /* nonstandard extension */
97bcbfc94fSguenther #define CUF 0x04000000 /* nonstandard extension */
98bcbfc94fSguenther #define CXF 0x08000000
99bcbfc94fSguenther #define CYF 0x10000000 /* nonstandard extension */
100bcbfc94fSguenther #define CZF 0x20000000 /* nonstandard extension */
101bcbfc94fSguenther #define C0F 0x40000000 /* nonstandard extension */
102bcbfc94fSguenther
103bcbfc94fSguenther /*
104bcbfc94fSguenther * ascii string indexed by bit position above (alter the above and you must
105bcbfc94fSguenther * alter this string) used to tell the user what flags caused us to complain
106bcbfc94fSguenther */
107bcbfc94fSguenther #define FLGCH "abcdfiklnoprstuvwxBDEGHLPTUXYZ0"
108bcbfc94fSguenther
109bcbfc94fSguenther /*
110bcbfc94fSguenther * legal pax operation bit patterns
111bcbfc94fSguenther */
112bcbfc94fSguenther
113bcbfc94fSguenther #define ISLIST(x) (((x) & (RF|WF)) == 0)
114bcbfc94fSguenther #define ISEXTRACT(x) (((x) & (RF|WF)) == RF)
115bcbfc94fSguenther #define ISARCHIVE(x) (((x) & (AF|RF|WF)) == WF)
116bcbfc94fSguenther #define ISAPPND(x) (((x) & (AF|RF|WF)) == (AF|WF))
117bcbfc94fSguenther #define ISCOPY(x) (((x) & (RF|WF)) == (RF|WF))
118bcbfc94fSguenther #define ISWRITE(x) (((x) & (RF|WF)) == WF)
119bcbfc94fSguenther
120bcbfc94fSguenther /*
121bcbfc94fSguenther * Illegal option flag subsets based on pax operation
122bcbfc94fSguenther */
123bcbfc94fSguenther
124bcbfc94fSguenther #define BDEXTR (AF|BF|LF|TF|WF|XF|CBF|CHF|CLF|CPF|CXF)
125bcbfc94fSguenther #define BDARCH (CF|KF|LF|NF|PF|RF|CDF|CEF|CYF|CZF)
126bcbfc94fSguenther #define BDCOPY (AF|BF|FF|OF|XF|CBF|CEF)
127bcbfc94fSguenther #define BDLIST (AF|BF|IF|KF|LF|OF|PF|RF|TF|UF|WF|XF|CBF|CDF|CHF|CLF|CPF|CXF|CYF|CZF)
128bcbfc94fSguenther
129bcbfc94fSguenther
130bcbfc94fSguenther /*
131df930be7Sderaadt * Routines which handle command line options
132df930be7Sderaadt */
133df930be7Sderaadt
134df930be7Sderaadt static char flgch[] = FLGCH; /* list of all possible flags */
135df930be7Sderaadt static OPLIST *ophead = NULL; /* head for format specific options -x */
136df930be7Sderaadt static OPLIST *optail = NULL; /* option tail */
137df930be7Sderaadt
138c72b5b24Smillert static int no_op(void);
139c72b5b24Smillert static void printflg(unsigned int);
140c72b5b24Smillert static off_t str_offt(char *);
141f9bbbf45Sfgsch static char *get_line(FILE *fp);
142be87792eSmillert static void pax_options(int, char **);
143c72b5b24Smillert static void pax_usage(void);
144be87792eSmillert static void tar_options(int, char **);
145c72b5b24Smillert static void tar_usage(void);
1469a195818Skrw #ifndef NOCPIO
147be87792eSmillert static void cpio_options(int, char **);
148c72b5b24Smillert static void cpio_usage(void);
1499a195818Skrw #endif
150df930be7Sderaadt
151a48f739dSguenther static int compress_id(char *_blk, int _size);
152a48f739dSguenther static int gzip_id(char *_blk, int _size);
153a48f739dSguenther static int bzip2_id(char *_blk, int _size);
154a48f739dSguenther static int xz_id(char *_blk, int _size);
155a48f739dSguenther
156c7117be0Sderaadt #define GZIP_CMD "gzip" /* command to run as gzip */
157c7117be0Sderaadt #define COMPRESS_CMD "compress" /* command to run as compress */
158a914b46dSpvalchev #define BZIP2_CMD "bzip2" /* command to run as bzip2 */
159c7117be0Sderaadt
160df930be7Sderaadt /*
161e1fb501dShalex * Format specific routine table
162df930be7Sderaadt * (see pax.h for description of each function)
163df930be7Sderaadt *
164df930be7Sderaadt * name, blksz, hdsz, udev, hlk, blkagn, inhead, id, st_read,
165df930be7Sderaadt * read, end_read, st_write, write, end_write, trail,
166df930be7Sderaadt * rd_data, wr_data, options
167df930be7Sderaadt */
168df930be7Sderaadt
169df930be7Sderaadt FSUB fsub[] = {
170f3e2c552Sderaadt #ifdef NOCPIO
171f3e2c552Sderaadt /* 0: OLD BINARY CPIO */
172f3e2c552Sderaadt { },
173f3e2c552Sderaadt /* 1: OLD OCTAL CHARACTER CPIO */
174f3e2c552Sderaadt { },
175f3e2c552Sderaadt /* 2: SVR4 HEX CPIO */
176f3e2c552Sderaadt { },
177f3e2c552Sderaadt /* 3: SVR4 HEX CPIO WITH CRC */
178f3e2c552Sderaadt { },
179f3e2c552Sderaadt #else
180df930be7Sderaadt /* 0: OLD BINARY CPIO */
18142cf9836Stholo {"bcpio", 5120, sizeof(HD_BCPIO), 1, 0, 0, 1, bcpio_id, cpio_strd,
182df930be7Sderaadt bcpio_rd, bcpio_endrd, cpio_stwr, bcpio_wr, cpio_endwr, cpio_trail,
1835647df80Sespie bad_opt},
184df930be7Sderaadt
185df930be7Sderaadt /* 1: OLD OCTAL CHARACTER CPIO */
18642cf9836Stholo {"cpio", 5120, sizeof(HD_CPIO), 1, 0, 0, 1, cpio_id, cpio_strd,
187df930be7Sderaadt cpio_rd, cpio_endrd, cpio_stwr, cpio_wr, cpio_endwr, cpio_trail,
1885647df80Sespie bad_opt},
189df930be7Sderaadt
190df930be7Sderaadt /* 2: SVR4 HEX CPIO */
19142cf9836Stholo {"sv4cpio", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, vcpio_id, cpio_strd,
192df930be7Sderaadt vcpio_rd, vcpio_endrd, cpio_stwr, vcpio_wr, cpio_endwr, cpio_trail,
1935647df80Sespie bad_opt},
194df930be7Sderaadt
195df930be7Sderaadt /* 3: SVR4 HEX CPIO WITH CRC */
19642cf9836Stholo {"sv4crc", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd,
197df930be7Sderaadt vcpio_rd, vcpio_endrd, crc_stwr, vcpio_wr, cpio_endwr, cpio_trail,
1985647df80Sespie bad_opt},
199f3e2c552Sderaadt #endif
200df930be7Sderaadt /* 4: OLD TAR */
20142cf9836Stholo {"tar", 10240, BLKMULT, 0, 1, BLKMULT, 0, tar_id, no_op,
202df930be7Sderaadt tar_rd, tar_endrd, no_op, tar_wr, tar_endwr, tar_trail,
2035647df80Sespie tar_opt},
204df930be7Sderaadt
205df930be7Sderaadt /* 5: POSIX USTAR */
206f84583feSmillert {"ustar", 10240, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, no_op,
2074c043852Sguenther ustar_rd, tar_endrd, no_op, ustar_wr, tar_endwr, tar_trail,
2085647df80Sespie tar_opt},
209a48f739dSguenther
210a48f739dSguenther #ifdef SMALL
211a48f739dSguenther /* 6: compress, to detect failure to use -Z */
212a48f739dSguenther { },
213a48f739dSguenther /* 7: xz, to detect failure to decompress it */
214a48f739dSguenther { },
215a48f739dSguenther /* 8: bzip2, to detect failure to use -j */
216a48f739dSguenther { },
217a48f739dSguenther /* 9: gzip, to detect failure to use -z */
218a48f739dSguenther { },
219013e174aSjca /* 10: POSIX PAX */
220013e174aSjca { },
221a48f739dSguenther #else
222a48f739dSguenther /* 6: compress, to detect failure to use -Z */
223a48f739dSguenther {NULL, 0, 4, 0, 0, 0, 0, compress_id},
224a48f739dSguenther /* 7: xz, to detect failure to decompress it */
225a48f739dSguenther {NULL, 0, 4, 0, 0, 0, 0, xz_id},
226a48f739dSguenther /* 8: bzip2, to detect failure to use -j */
227a48f739dSguenther {NULL, 0, 4, 0, 0, 0, 0, bzip2_id},
228a48f739dSguenther /* 9: gzip, to detect failure to use -z */
229a48f739dSguenther {NULL, 0, 4, 0, 0, 0, 0, gzip_id},
230013e174aSjca /* 10: POSIX PAX */
231ce1e26fbSjca {"pax", 5120, BLKMULT, 0, 1, BLKMULT, 0, pax_id, no_op,
232013e174aSjca ustar_rd, tar_endrd, no_op, pax_wr, tar_endwr, tar_trail,
2338df76133Sjca pax_opt},
234a48f739dSguenther #endif
235df930be7Sderaadt };
23619e7eef2Stholo #define F_OCPIO 0 /* format when called as cpio -6 */
23719e7eef2Stholo #define F_ACPIO 1 /* format when called as cpio -c */
23819e7eef2Stholo #define F_CPIO 3 /* format when called as cpio */
23998fcb8acSmillert #define F_OTAR 4 /* format when called as tar -o */
2409dcb0c6dSjca #ifdef SMALL
241e313d3ebSjca # define F_TAR 5 /* default write format when called as tar: ustar */
24285d4a8a2Scaspar # define DEFLT 5 /* default write format when called as pax: ustar */
2439dcb0c6dSjca #else
2444ce91cbeSjca # define F_TAR 10 /* default write format when called as tar: pax */
24585d4a8a2Scaspar # define DEFLT 10 /* default write format when called as pax: pax */
2469dcb0c6dSjca #endif
247df930be7Sderaadt
248df930be7Sderaadt /*
249df930be7Sderaadt * ford is the archive search order used by get_arc() to determine what kind
250df930be7Sderaadt * of archive we are dealing with. This helps to properly id archive formats
251df930be7Sderaadt * some formats may be subsets of others....
252df930be7Sderaadt */
253ce1e26fbSjca int ford[] = {10, 5, 4, 9, 8, 7, 6, 3, 2, 1, 0, -1};
254df930be7Sderaadt
255df930be7Sderaadt /*
256da5fb823Sguenther * Do we have -C anywhere and what is it?
257a7a4d07aSotto */
258a7a4d07aSotto int havechd = 0;
259da5fb823Sguenther char *chdname = NULL;
260a7a4d07aSotto
261a7a4d07aSotto /*
262df930be7Sderaadt * options()
263df930be7Sderaadt * figure out if we are pax, tar or cpio. Call the appropriate options
264df930be7Sderaadt * parser
265df930be7Sderaadt */
266df930be7Sderaadt
267df930be7Sderaadt void
options(int argc,char ** argv)268be87792eSmillert options(int argc, char **argv)
269df930be7Sderaadt {
270dab586c4Stobias extern char *__progname;
271df930be7Sderaadt
272df930be7Sderaadt /*
273df930be7Sderaadt * Are we acting like pax, tar or cpio (based on argv[0])
274df930be7Sderaadt */
275dab586c4Stobias argv0 = __progname;
276df930be7Sderaadt
2776118013aSderaadt if (strcmp(NM_TAR, argv0) == 0) {
2783228b364Sguenther op_mode = OP_TAR;
2796118013aSderaadt tar_options(argc, argv);
280f3e2c552Sderaadt #ifndef NOCPIO
281*8758bb59Smillert } else if (strcmp(NM_CPIO, argv0) == 0) {
2823228b364Sguenther op_mode = OP_CPIO;
2836118013aSderaadt cpio_options(argc, argv);
284f3e2c552Sderaadt #endif /* !NOCPIO */
285*8758bb59Smillert } else {
286df930be7Sderaadt argv0 = NM_PAX;
2873228b364Sguenther op_mode = OP_PAX;
2886118013aSderaadt pax_options(argc, argv);
289df930be7Sderaadt }
290df930be7Sderaadt
291*8758bb59Smillert /* Line-buffer the file list output as needed. */
292*8758bb59Smillert if (listf != stderr)
293*8758bb59Smillert setvbuf(listf, NULL, _IOLBF, 0);
294*8758bb59Smillert }
295*8758bb59Smillert
296df930be7Sderaadt /*
297df930be7Sderaadt * pax_options()
298df930be7Sderaadt * look at the user specified flags. set globals as required and check if
299df930be7Sderaadt * the user specified a legal set of flags. If not, complain and exit
300df930be7Sderaadt */
301df930be7Sderaadt
302df930be7Sderaadt static void
pax_options(int argc,char ** argv)303be87792eSmillert pax_options(int argc, char **argv)
304df930be7Sderaadt {
305be87792eSmillert int c;
306e1fb501dShalex unsigned i;
307df930be7Sderaadt unsigned int flg = 0;
308df930be7Sderaadt unsigned int bflg = 0;
309a47b6461Sderaadt const char *errstr;
310be87792eSmillert char *pt;
311df930be7Sderaadt
312df930be7Sderaadt /*
313df930be7Sderaadt * process option flags
314df930be7Sderaadt */
315a914b46dSpvalchev while ((c=getopt(argc,argv,"ab:cdf:ijklno:p:rs:tuvwx:zB:DE:G:HLOPT:U:XYZ0"))
3168781354eSaaron != -1) {
317df930be7Sderaadt switch (c) {
318df930be7Sderaadt case 'a':
319df930be7Sderaadt /*
320df930be7Sderaadt * append
321df930be7Sderaadt */
322df930be7Sderaadt flg |= AF;
323df930be7Sderaadt break;
324df930be7Sderaadt case 'b':
325df930be7Sderaadt /*
326df930be7Sderaadt * specify blocksize
327df930be7Sderaadt */
328df930be7Sderaadt flg |= BF;
329df930be7Sderaadt if ((wrblksz = (int)str_offt(optarg)) <= 0) {
33042cf9836Stholo paxwarn(1, "Invalid block size %s", optarg);
331df930be7Sderaadt pax_usage();
332df930be7Sderaadt }
333df930be7Sderaadt break;
334df930be7Sderaadt case 'c':
335df930be7Sderaadt /*
336df930be7Sderaadt * inverse match on patterns
337df930be7Sderaadt */
338df930be7Sderaadt cflag = 1;
339df930be7Sderaadt flg |= CF;
340df930be7Sderaadt break;
341df930be7Sderaadt case 'd':
342df930be7Sderaadt /*
343df930be7Sderaadt * match only dir on extract, not the subtree at dir
344df930be7Sderaadt */
345df930be7Sderaadt dflag = 1;
346df930be7Sderaadt flg |= DF;
347df930be7Sderaadt break;
348df930be7Sderaadt case 'f':
349df930be7Sderaadt /*
350df930be7Sderaadt * filename where the archive is stored
351df930be7Sderaadt */
352df930be7Sderaadt arcname = optarg;
353df930be7Sderaadt flg |= FF;
354df930be7Sderaadt break;
355df930be7Sderaadt case 'i':
356df930be7Sderaadt /*
357df930be7Sderaadt * interactive file rename
358df930be7Sderaadt */
359df930be7Sderaadt iflag = 1;
360df930be7Sderaadt flg |= IF;
361df930be7Sderaadt break;
362a914b46dSpvalchev case 'j':
363a914b46dSpvalchev /*
364a914b46dSpvalchev * use bzip2. Non standard option.
365a914b46dSpvalchev */
366a914b46dSpvalchev gzip_program = BZIP2_CMD;
367a914b46dSpvalchev break;
368df930be7Sderaadt case 'k':
369df930be7Sderaadt /*
370df930be7Sderaadt * do not clobber files that exist
371df930be7Sderaadt */
372df930be7Sderaadt kflag = 1;
373df930be7Sderaadt flg |= KF;
374df930be7Sderaadt break;
375df930be7Sderaadt case 'l':
376df930be7Sderaadt /*
377df930be7Sderaadt * try to link src to dest with copy (-rw)
378df930be7Sderaadt */
379df930be7Sderaadt lflag = 1;
380df930be7Sderaadt flg |= LF;
381df930be7Sderaadt break;
382df930be7Sderaadt case 'n':
383df930be7Sderaadt /*
384df930be7Sderaadt * select first match for a pattern only
385df930be7Sderaadt */
386df930be7Sderaadt nflag = 1;
387df930be7Sderaadt flg |= NF;
388df930be7Sderaadt break;
389df930be7Sderaadt case 'o':
390df930be7Sderaadt /*
391df930be7Sderaadt * pass format specific options
392df930be7Sderaadt */
393df930be7Sderaadt flg |= OF;
394df930be7Sderaadt if (opt_add(optarg) < 0)
395df930be7Sderaadt pax_usage();
396df930be7Sderaadt break;
397df930be7Sderaadt case 'p':
398df930be7Sderaadt /*
399df930be7Sderaadt * specify file characteristic options
400df930be7Sderaadt */
401df930be7Sderaadt for (pt = optarg; *pt != '\0'; ++pt) {
402df930be7Sderaadt switch (*pt) {
403df930be7Sderaadt case 'a':
404df930be7Sderaadt /*
405df930be7Sderaadt * do not preserve access time
406df930be7Sderaadt */
407df930be7Sderaadt patime = 0;
408df930be7Sderaadt break;
409df930be7Sderaadt case 'e':
410df930be7Sderaadt /*
411df930be7Sderaadt * preserve user id, group id, file
412df930be7Sderaadt * mode, access/modification times
413df930be7Sderaadt */
414df930be7Sderaadt pids = 1;
415df930be7Sderaadt pmode = 1;
416df930be7Sderaadt patime = 1;
417df930be7Sderaadt pmtime = 1;
418df930be7Sderaadt break;
419df930be7Sderaadt case 'm':
420df930be7Sderaadt /*
421df930be7Sderaadt * do not preserve modification time
422df930be7Sderaadt */
423df930be7Sderaadt pmtime = 0;
424df930be7Sderaadt break;
425df930be7Sderaadt case 'o':
426df930be7Sderaadt /*
427df930be7Sderaadt * preserve uid/gid
428df930be7Sderaadt */
429df930be7Sderaadt pids = 1;
430df930be7Sderaadt break;
431df930be7Sderaadt case 'p':
432df930be7Sderaadt /*
4334eb0b000Smillert * preserve file mode bits
434df930be7Sderaadt */
435df930be7Sderaadt pmode = 1;
436df930be7Sderaadt break;
437df930be7Sderaadt default:
43842cf9836Stholo paxwarn(1, "Invalid -p string: %c", *pt);
439df930be7Sderaadt pax_usage();
440df930be7Sderaadt break;
441df930be7Sderaadt }
442df930be7Sderaadt }
443df930be7Sderaadt flg |= PF;
444df930be7Sderaadt break;
445df930be7Sderaadt case 'r':
446df930be7Sderaadt /*
447df930be7Sderaadt * read the archive
448df930be7Sderaadt */
449df930be7Sderaadt flg |= RF;
450df930be7Sderaadt break;
451df930be7Sderaadt case 's':
452df930be7Sderaadt /*
453df930be7Sderaadt * file name substitution name pattern
454df930be7Sderaadt */
455df930be7Sderaadt if (rep_add(optarg) < 0) {
456df930be7Sderaadt pax_usage();
457df930be7Sderaadt break;
458df930be7Sderaadt }
459df930be7Sderaadt flg |= SF;
460df930be7Sderaadt break;
461df930be7Sderaadt case 't':
462df930be7Sderaadt /*
463df930be7Sderaadt * preserve access time on filesystem nodes we read
464df930be7Sderaadt */
465df930be7Sderaadt tflag = 1;
466df930be7Sderaadt flg |= TF;
467df930be7Sderaadt break;
468df930be7Sderaadt case 'u':
469df930be7Sderaadt /*
470df930be7Sderaadt * ignore those older files
471df930be7Sderaadt */
472df930be7Sderaadt uflag = 1;
473df930be7Sderaadt flg |= UF;
474df930be7Sderaadt break;
475df930be7Sderaadt case 'v':
476df930be7Sderaadt /*
477df930be7Sderaadt * verbose operation mode
478df930be7Sderaadt */
479df930be7Sderaadt vflag = 1;
480df930be7Sderaadt flg |= VF;
481df930be7Sderaadt break;
482df930be7Sderaadt case 'w':
483df930be7Sderaadt /*
484df930be7Sderaadt * write an archive
485df930be7Sderaadt */
486df930be7Sderaadt flg |= WF;
487df930be7Sderaadt break;
488df930be7Sderaadt case 'x':
489df930be7Sderaadt /*
490df930be7Sderaadt * specify an archive format on write
491df930be7Sderaadt */
492e1fb501dShalex for (i = 0; i < sizeof(fsub)/sizeof(FSUB); ++i)
493e1fb501dShalex if (fsub[i].name != NULL &&
494e1fb501dShalex strcmp(fsub[i].name, optarg) == 0)
495e1fb501dShalex break;
496e1fb501dShalex if (i < sizeof(fsub)/sizeof(FSUB)) {
497e43eba20Sguenther frmt = &fsub[i];
498df930be7Sderaadt flg |= XF;
499df930be7Sderaadt break;
500df930be7Sderaadt }
50142cf9836Stholo paxwarn(1, "Unknown -x format: %s", optarg);
502df930be7Sderaadt (void)fputs("pax: Known -x formats are:", stderr);
503df930be7Sderaadt for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i)
504e1fb501dShalex if (fsub[i].name != NULL)
505e1fb501dShalex (void)fprintf(stderr, " %s",
506e1fb501dShalex fsub[i].name);
507df930be7Sderaadt (void)fputs("\n\n", stderr);
508df930be7Sderaadt pax_usage();
509df930be7Sderaadt break;
5108ab05b7eSderaadt case 'z':
5118ab05b7eSderaadt /*
5128ab05b7eSderaadt * use gzip. Non standard option.
5138ab05b7eSderaadt */
514c7117be0Sderaadt gzip_program = GZIP_CMD;
5158ab05b7eSderaadt break;
516df930be7Sderaadt case 'B':
517df930be7Sderaadt /*
518df930be7Sderaadt * non-standard option on number of bytes written on a
519df930be7Sderaadt * single archive volume.
520df930be7Sderaadt */
521df930be7Sderaadt if ((wrlimit = str_offt(optarg)) <= 0) {
52242cf9836Stholo paxwarn(1, "Invalid write limit %s", optarg);
523df930be7Sderaadt pax_usage();
524df930be7Sderaadt }
525df930be7Sderaadt if (wrlimit % BLKMULT) {
52642cf9836Stholo paxwarn(1, "Write limit is not a %d byte multiple",
527df930be7Sderaadt BLKMULT);
528df930be7Sderaadt pax_usage();
529df930be7Sderaadt }
530df930be7Sderaadt flg |= CBF;
531df930be7Sderaadt break;
532df930be7Sderaadt case 'D':
533df930be7Sderaadt /*
534df930be7Sderaadt * On extraction check file inode change time before the
535df930be7Sderaadt * modification of the file name. Non standard option.
536df930be7Sderaadt */
537df930be7Sderaadt Dflag = 1;
538df930be7Sderaadt flg |= CDF;
539df930be7Sderaadt break;
540df930be7Sderaadt case 'E':
541df930be7Sderaadt /*
542df930be7Sderaadt * non-standard limit on read faults
543df930be7Sderaadt * 0 indicates stop after first error, values
54412086188Sguenther * indicate a limit
545df930be7Sderaadt */
546df930be7Sderaadt flg |= CEF;
547a47b6461Sderaadt maxflt = strtonum(optarg, 0, INT_MAX, &errstr);
548a47b6461Sderaadt if (errstr) {
549a47b6461Sderaadt paxwarn(1, "Error count value: %s", errstr);
550df930be7Sderaadt pax_usage();
551df930be7Sderaadt }
552df930be7Sderaadt break;
553df930be7Sderaadt case 'G':
554df930be7Sderaadt /*
555df930be7Sderaadt * non-standard option for selecting files within an
556df930be7Sderaadt * archive by group (gid or name)
557df930be7Sderaadt */
558df930be7Sderaadt if (grp_add(optarg) < 0) {
559df930be7Sderaadt pax_usage();
560df930be7Sderaadt break;
561df930be7Sderaadt }
562df930be7Sderaadt flg |= CGF;
563df930be7Sderaadt break;
564df930be7Sderaadt case 'H':
565df930be7Sderaadt /*
566df930be7Sderaadt * follow command line symlinks only
567df930be7Sderaadt */
568df930be7Sderaadt Hflag = 1;
569df930be7Sderaadt flg |= CHF;
570df930be7Sderaadt break;
571df930be7Sderaadt case 'L':
572df930be7Sderaadt /*
573df930be7Sderaadt * follow symlinks
574df930be7Sderaadt */
575df930be7Sderaadt Lflag = 1;
576df930be7Sderaadt flg |= CLF;
577df930be7Sderaadt break;
578da60b202Smillert case 'O':
579da60b202Smillert /*
580da60b202Smillert * Force one volume. Non standard option.
581da60b202Smillert */
582da60b202Smillert force_one_volume = 1;
583da60b202Smillert break;
584df930be7Sderaadt case 'P':
585df930be7Sderaadt /*
586df930be7Sderaadt * do NOT follow symlinks (default)
587df930be7Sderaadt */
588df930be7Sderaadt Lflag = 0;
589df930be7Sderaadt flg |= CPF;
590df930be7Sderaadt break;
591df930be7Sderaadt case 'T':
592df930be7Sderaadt /*
593df930be7Sderaadt * non-standard option for selecting files within an
594df930be7Sderaadt * archive by modification time range (lower,upper)
595df930be7Sderaadt */
596df930be7Sderaadt if (trng_add(optarg) < 0) {
597df930be7Sderaadt pax_usage();
598df930be7Sderaadt break;
599df930be7Sderaadt }
600df930be7Sderaadt flg |= CTF;
601df930be7Sderaadt break;
602df930be7Sderaadt case 'U':
603df930be7Sderaadt /*
604df930be7Sderaadt * non-standard option for selecting files within an
605df930be7Sderaadt * archive by user (uid or name)
606df930be7Sderaadt */
607df930be7Sderaadt if (usr_add(optarg) < 0) {
608df930be7Sderaadt pax_usage();
609df930be7Sderaadt break;
610df930be7Sderaadt }
611df930be7Sderaadt flg |= CUF;
612df930be7Sderaadt break;
613df930be7Sderaadt case 'X':
614df930be7Sderaadt /*
615df930be7Sderaadt * do not pass over mount points in the file system
616df930be7Sderaadt */
617df930be7Sderaadt Xflag = 1;
618df930be7Sderaadt flg |= CXF;
619df930be7Sderaadt break;
620df930be7Sderaadt case 'Y':
621df930be7Sderaadt /*
622df930be7Sderaadt * On extraction check file inode change time after the
623df930be7Sderaadt * modification of the file name. Non standard option.
624df930be7Sderaadt */
625df930be7Sderaadt Yflag = 1;
626df930be7Sderaadt flg |= CYF;
627df930be7Sderaadt break;
628df930be7Sderaadt case 'Z':
629df930be7Sderaadt /*
630df930be7Sderaadt * On extraction check modification time after the
631df930be7Sderaadt * modification of the file name. Non standard option.
632df930be7Sderaadt */
633df930be7Sderaadt Zflag = 1;
634df930be7Sderaadt flg |= CZF;
635df930be7Sderaadt break;
6369cd57097Smillert case '0':
6379cd57097Smillert /*
6389cd57097Smillert * Use \0 as pathname terminator.
6399cd57097Smillert * (For use with the -print0 option of find(1).)
6409cd57097Smillert */
6419cd57097Smillert zeroflag = 1;
6429cd57097Smillert flg |= C0F;
6439cd57097Smillert break;
644df930be7Sderaadt default:
645df930be7Sderaadt pax_usage();
646df930be7Sderaadt break;
647df930be7Sderaadt }
648df930be7Sderaadt }
649df930be7Sderaadt
650df930be7Sderaadt /*
651df930be7Sderaadt * figure out the operation mode of pax read,write,extract,copy,append
652df930be7Sderaadt * or list. check that we have not been given a bogus set of flags
653df930be7Sderaadt * for the operation mode.
654df930be7Sderaadt */
655df930be7Sderaadt if (ISLIST(flg)) {
656df930be7Sderaadt act = LIST;
65710854502Smillert listf = stdout;
658df930be7Sderaadt bflg = flg & BDLIST;
659df930be7Sderaadt } else if (ISEXTRACT(flg)) {
660df930be7Sderaadt act = EXTRACT;
661df930be7Sderaadt bflg = flg & BDEXTR;
662df930be7Sderaadt } else if (ISARCHIVE(flg)) {
663df930be7Sderaadt act = ARCHIVE;
664df930be7Sderaadt bflg = flg & BDARCH;
665df930be7Sderaadt } else if (ISAPPND(flg)) {
666df930be7Sderaadt act = APPND;
667df930be7Sderaadt bflg = flg & BDARCH;
668df930be7Sderaadt } else if (ISCOPY(flg)) {
669df930be7Sderaadt act = COPY;
670df930be7Sderaadt bflg = flg & BDCOPY;
671df930be7Sderaadt } else
672df930be7Sderaadt pax_usage();
673df930be7Sderaadt if (bflg) {
674df930be7Sderaadt printflg(flg);
675df930be7Sderaadt pax_usage();
676df930be7Sderaadt }
677df930be7Sderaadt
678df930be7Sderaadt /*
679df930be7Sderaadt * if we are writing (ARCHIVE) we use the default format if the user
680df930be7Sderaadt * did not specify a format. when we write during an APPEND, we will
681df930be7Sderaadt * adopt the format of the existing archive if none was supplied.
682df930be7Sderaadt */
683df930be7Sderaadt if (!(flg & XF) && (act == ARCHIVE))
684df930be7Sderaadt frmt = &(fsub[DEFLT]);
685df930be7Sderaadt
686df930be7Sderaadt /*
687df930be7Sderaadt * process the args as they are interpreted by the operation mode
688df930be7Sderaadt */
689df930be7Sderaadt switch (act) {
690df930be7Sderaadt case LIST:
691df930be7Sderaadt case EXTRACT:
692df930be7Sderaadt for (; optind < argc; optind++)
6933c2af966Sdownsj if (pat_add(argv[optind], NULL) < 0)
694df930be7Sderaadt pax_usage();
695df930be7Sderaadt break;
696df930be7Sderaadt case COPY:
697df930be7Sderaadt if (optind >= argc) {
69842cf9836Stholo paxwarn(0, "Destination directory was not supplied");
699df930be7Sderaadt pax_usage();
700df930be7Sderaadt }
701df930be7Sderaadt --argc;
702df930be7Sderaadt dirptr = argv[argc];
703df930be7Sderaadt /* FALL THROUGH */
704df930be7Sderaadt case ARCHIVE:
705df930be7Sderaadt case APPND:
706df930be7Sderaadt for (; optind < argc; optind++)
7073c2af966Sdownsj if (ftree_add(argv[optind], 0) < 0)
708df930be7Sderaadt pax_usage();
709df930be7Sderaadt /*
710df930be7Sderaadt * no read errors allowed on updates/append operation!
711df930be7Sderaadt */
712df930be7Sderaadt maxflt = 0;
713df930be7Sderaadt break;
714df930be7Sderaadt }
715df930be7Sderaadt }
716df930be7Sderaadt
717df930be7Sderaadt
718df930be7Sderaadt /*
719df930be7Sderaadt * tar_options()
720df930be7Sderaadt * look at the user specified flags. set globals as required and check if
721df930be7Sderaadt * the user specified a legal set of flags. If not, complain and exit
722df930be7Sderaadt */
723df930be7Sderaadt
724df930be7Sderaadt static void
tar_options(int argc,char ** argv)725be87792eSmillert tar_options(int argc, char **argv)
726df930be7Sderaadt {
727be87792eSmillert int c;
72829e8fb76Smillert int nincfiles = 0;
72929e8fb76Smillert int incfiles_max = 0;
730f30fa552Sjca unsigned int i;
731f30fa552Sjca unsigned int format = F_TAR;
73229e8fb76Smillert struct incfile {
73329e8fb76Smillert char *file;
73429e8fb76Smillert char *dir;
73529e8fb76Smillert };
73629e8fb76Smillert struct incfile *incfiles = NULL;
737df930be7Sderaadt
738df930be7Sderaadt /*
739c7e58f96Smillert * Set default values.
740c7e58f96Smillert */
741c7e58f96Smillert rmleadslash = 1;
742c7e58f96Smillert
743c7e58f96Smillert /*
744df930be7Sderaadt * process option flags
745df930be7Sderaadt */
746d2b23181Sderaadt while ((c = getoldopt(argc, argv,
747f30fa552Sjca "b:cef:hjmopqruts:vwxzBC:F:HI:LNOPXZ014578")) != -1) {
748df930be7Sderaadt switch (c) {
749df930be7Sderaadt case 'b':
750df930be7Sderaadt /*
75123853f2fSmillert * specify blocksize in 512-byte blocks
752df930be7Sderaadt */
753df930be7Sderaadt if ((wrblksz = (int)str_offt(optarg)) <= 0) {
75442cf9836Stholo paxwarn(1, "Invalid block size %s", optarg);
755df930be7Sderaadt tar_usage();
756df930be7Sderaadt }
75723853f2fSmillert wrblksz *= 512; /* XXX - check for int oflow */
758df930be7Sderaadt break;
759df930be7Sderaadt case 'c':
760df930be7Sderaadt /*
761df930be7Sderaadt * create an archive
762df930be7Sderaadt */
763df930be7Sderaadt act = ARCHIVE;
764df930be7Sderaadt break;
765df930be7Sderaadt case 'e':
766df930be7Sderaadt /*
767df930be7Sderaadt * stop after first error
768df930be7Sderaadt */
769df930be7Sderaadt maxflt = 0;
770df930be7Sderaadt break;
771df930be7Sderaadt case 'f':
772df930be7Sderaadt /*
773df930be7Sderaadt * filename where the archive is stored
774df930be7Sderaadt */
775df930be7Sderaadt arcname = optarg;
776df930be7Sderaadt break;
777c2e82e9eStholo case 'h':
778c2e82e9eStholo /*
779c2e82e9eStholo * follow symlinks
780c2e82e9eStholo */
781c2e82e9eStholo Lflag = 1;
782c2e82e9eStholo break;
783a914b46dSpvalchev case 'j':
784a914b46dSpvalchev /*
785a914b46dSpvalchev * use bzip2. Non standard option.
786a914b46dSpvalchev */
787a914b46dSpvalchev gzip_program = BZIP2_CMD;
788a914b46dSpvalchev break;
789df930be7Sderaadt case 'm':
790df930be7Sderaadt /*
791df930be7Sderaadt * do not preserve modification time
792df930be7Sderaadt */
793df930be7Sderaadt pmtime = 0;
794df930be7Sderaadt break;
79598fcb8acSmillert case 'O':
796f30fa552Sjca format = F_OTAR;
797df930be7Sderaadt break;
7984b311c3bSmillert case 'o':
799f30fa552Sjca format = F_OTAR;
8002d53aafbSguenther tar_nodir = 1;
8014b311c3bSmillert break;
802df930be7Sderaadt case 'p':
803df930be7Sderaadt /*
8041d097e52Smillert * preserve uid/gid and file mode, regardless of umask
805df930be7Sderaadt */
806df930be7Sderaadt pmode = 1;
8071d097e52Smillert pids = 1;
808df930be7Sderaadt break;
8098f296fddSespie case 'q':
8108f296fddSespie /*
8118f296fddSespie * select first match for a pattern only
8128f296fddSespie */
8138f296fddSespie nflag = 1;
8148f296fddSespie break;
815df930be7Sderaadt case 'r':
816df930be7Sderaadt case 'u':
817df930be7Sderaadt /*
818df930be7Sderaadt * append to the archive
819df930be7Sderaadt */
820df930be7Sderaadt act = APPND;
821df930be7Sderaadt break;
822d2b23181Sderaadt case 's':
823d2b23181Sderaadt /*
824d2b23181Sderaadt * file name substitution name pattern
825d2b23181Sderaadt */
826d2b23181Sderaadt if (rep_add(optarg) < 0) {
827d2b23181Sderaadt tar_usage();
828d2b23181Sderaadt break;
829d2b23181Sderaadt }
830d2b23181Sderaadt break;
831df930be7Sderaadt case 't':
832df930be7Sderaadt /*
833df930be7Sderaadt * list contents of the tape
834df930be7Sderaadt */
835df930be7Sderaadt act = LIST;
836df930be7Sderaadt break;
837df930be7Sderaadt case 'v':
838df930be7Sderaadt /*
839df930be7Sderaadt * verbose operation mode
840df930be7Sderaadt */
841f2d26cdcSmillert vflag++;
842df930be7Sderaadt break;
843df930be7Sderaadt case 'w':
844df930be7Sderaadt /*
845df930be7Sderaadt * interactive file rename
846df930be7Sderaadt */
847df930be7Sderaadt iflag = 1;
848df930be7Sderaadt break;
849df930be7Sderaadt case 'x':
850df930be7Sderaadt /*
8513230eb4dSmillert * extract an archive, preserving mode,
8521d097e52Smillert * and mtime if possible.
853df930be7Sderaadt */
854df930be7Sderaadt act = EXTRACT;
8553230eb4dSmillert pmtime = 1;
856df930be7Sderaadt break;
8578ab05b7eSderaadt case 'z':
8588ab05b7eSderaadt /*
8598ab05b7eSderaadt * use gzip. Non standard option.
8608ab05b7eSderaadt */
861c7117be0Sderaadt gzip_program = GZIP_CMD;
8628ab05b7eSderaadt break;
863df930be7Sderaadt case 'B':
864df930be7Sderaadt /*
865df930be7Sderaadt * Nothing to do here, this is pax default
866df930be7Sderaadt */
867df930be7Sderaadt break;
8683c2af966Sdownsj case 'C':
869a7a4d07aSotto havechd++;
870fd899314Smichaels chdname = optarg;
8713c2af966Sdownsj break;
872f30fa552Sjca case 'F':
873f30fa552Sjca for (i = 0; i < sizeof(fsub)/sizeof(FSUB); ++i)
874f30fa552Sjca if (fsub[i].name != NULL &&
875f30fa552Sjca strcmp(fsub[i].name, optarg) == 0)
876f30fa552Sjca break;
877f30fa552Sjca if (i < sizeof(fsub)/sizeof(FSUB)) {
878f30fa552Sjca format = i;
879f30fa552Sjca break;
880f30fa552Sjca }
881f30fa552Sjca paxwarn(1, "Unknown -F format: %s", optarg);
882f30fa552Sjca (void)fputs("tar: Known -F formats are:", stderr);
883f30fa552Sjca for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i)
884f30fa552Sjca if (fsub[i].name != NULL)
885f30fa552Sjca (void)fprintf(stderr, " %s",
886f30fa552Sjca fsub[i].name);
887f30fa552Sjca (void)fputs("\n\n", stderr);
888f30fa552Sjca tar_usage();
889f30fa552Sjca break;
890df930be7Sderaadt case 'H':
891df930be7Sderaadt /*
892df930be7Sderaadt * follow command line symlinks only
893df930be7Sderaadt */
894df930be7Sderaadt Hflag = 1;
895df930be7Sderaadt break;
89629e8fb76Smillert case 'I':
89729e8fb76Smillert if (++nincfiles > incfiles_max) {
898968415c8Sderaadt size_t n = nincfiles + 3;
899968415c8Sderaadt struct incfile *p;
900968415c8Sderaadt
901547153d7Stedu p = reallocarray(incfiles, n,
902547153d7Stedu sizeof(*incfiles));
903968415c8Sderaadt if (p == NULL) {
90429e8fb76Smillert paxwarn(0, "Unable to allocate space "
90529e8fb76Smillert "for option list");
90629e8fb76Smillert exit(1);
90729e8fb76Smillert }
908968415c8Sderaadt incfiles = p;
909968415c8Sderaadt incfiles_max = n;
91029e8fb76Smillert }
91129e8fb76Smillert incfiles[nincfiles - 1].file = optarg;
91229e8fb76Smillert incfiles[nincfiles - 1].dir = chdname;
91329e8fb76Smillert break;
914df930be7Sderaadt case 'L':
915df930be7Sderaadt /*
916df930be7Sderaadt * follow symlinks
917df930be7Sderaadt */
918df930be7Sderaadt Lflag = 1;
919df930be7Sderaadt break;
9205e460854Stedu case 'N':
9215e460854Stedu /* numeric uid and gid only */
9225e460854Stedu Nflag = 1;
9235e460854Stedu break;
924df930be7Sderaadt case 'P':
925df930be7Sderaadt /*
926c7e58f96Smillert * do not remove leading '/' from pathnames
927c7e58f96Smillert */
928c7e58f96Smillert rmleadslash = 0;
929c7e58f96Smillert break;
930df930be7Sderaadt case 'X':
931df930be7Sderaadt /*
932df930be7Sderaadt * do not pass over mount points in the file system
933df930be7Sderaadt */
934df930be7Sderaadt Xflag = 1;
935df930be7Sderaadt break;
9368ab05b7eSderaadt case 'Z':
9378ab05b7eSderaadt /*
9388ab05b7eSderaadt * use compress.
9398ab05b7eSderaadt */
940c7117be0Sderaadt gzip_program = COMPRESS_CMD;
9418ab05b7eSderaadt break;
942df930be7Sderaadt case '0':
943df930be7Sderaadt arcname = DEV_0;
944df930be7Sderaadt break;
945df930be7Sderaadt case '1':
946df930be7Sderaadt arcname = DEV_1;
947df930be7Sderaadt break;
948df930be7Sderaadt case '4':
949df930be7Sderaadt arcname = DEV_4;
950df930be7Sderaadt break;
951df930be7Sderaadt case '5':
952df930be7Sderaadt arcname = DEV_5;
953df930be7Sderaadt break;
954df930be7Sderaadt case '7':
955df930be7Sderaadt arcname = DEV_7;
956df930be7Sderaadt break;
957df930be7Sderaadt case '8':
958df930be7Sderaadt arcname = DEV_8;
959df930be7Sderaadt break;
960df930be7Sderaadt default:
961df930be7Sderaadt tar_usage();
962df930be7Sderaadt break;
963df930be7Sderaadt }
964df930be7Sderaadt }
965df930be7Sderaadt argc -= optind;
966df930be7Sderaadt argv += optind;
967df930be7Sderaadt
968e98b7d12Sguenther if ((arcname == NULL) || (*arcname == '\0')) {
969f2baad8dSczarkoff arcname = getenv("TAPE");
970f2baad8dSczarkoff if ((arcname == NULL) || (*arcname == '\0'))
971f2baad8dSczarkoff arcname = _PATH_DEFTAPE;
972e98b7d12Sguenther }
973e98b7d12Sguenther if ((arcname[0] == '-') && (arcname[1]== '\0'))
974f2baad8dSczarkoff arcname = NULL;
975f2baad8dSczarkoff
976e98b7d12Sguenther /*
977e98b7d12Sguenther * Traditional tar behaviour: list-like output goes to stdout unless
978e98b7d12Sguenther * writing the archive there. (pax uses stderr unless in list mode)
979e98b7d12Sguenther */
980e98b7d12Sguenther if (act == LIST || act == EXTRACT || arcname != NULL)
98110854502Smillert listf = stdout;
98210854502Smillert
9831e43a87cSmillert /* Traditional tar behaviour (pax wants to read file list from stdin) */
98429e8fb76Smillert if ((act == ARCHIVE || act == APPND) && argc == 0 && nincfiles == 0)
9851e43a87cSmillert exit(0);
9861e43a87cSmillert
987df930be7Sderaadt /*
988df930be7Sderaadt * process the args as they are interpreted by the operation mode
989df930be7Sderaadt */
990df930be7Sderaadt switch (act) {
991df930be7Sderaadt case LIST:
992df930be7Sderaadt case EXTRACT:
993df930be7Sderaadt default:
9943c2af966Sdownsj {
9953c2af966Sdownsj int sawpat = 0;
99629e8fb76Smillert char *file, *dir;
9973c2af966Sdownsj
99829e8fb76Smillert while (nincfiles || *argv != NULL) {
99929e8fb76Smillert /*
100029e8fb76Smillert * If we queued up any include files,
100129e8fb76Smillert * pull them in now. Otherwise, check
100229e8fb76Smillert * for -I and -C positional flags.
100329e8fb76Smillert * Anything else must be a file to
100429e8fb76Smillert * extract.
100529e8fb76Smillert */
100629e8fb76Smillert if (nincfiles) {
100729e8fb76Smillert file = incfiles->file;
100829e8fb76Smillert dir = incfiles->dir;
100929e8fb76Smillert incfiles++;
101029e8fb76Smillert nincfiles--;
101129e8fb76Smillert } else if (strcmp(*argv, "-I") == 0) {
10124bbb0cd1Skstailey if (*++argv == NULL)
10133c2af966Sdownsj break;
101429e8fb76Smillert file = *argv++;
101529e8fb76Smillert dir = chdname;
101629e8fb76Smillert } else
101729e8fb76Smillert file = NULL;
101829e8fb76Smillert if (file != NULL) {
101976b0a314Sespie FILE *fp;
102076b0a314Sespie char *str;
102176b0a314Sespie
102229e8fb76Smillert if (strcmp(file, "-") == 0)
102329e8fb76Smillert fp = stdin;
102429e8fb76Smillert else if ((fp = fopen(file, "r")) == NULL) {
1025fc5cb1eaSguenther syswarn(1, errno,
1026fc5cb1eaSguenther "Unable to open %s", file);
102776b0a314Sespie tar_usage();
102876b0a314Sespie }
1029f9bbbf45Sfgsch while ((str = get_line(fp)) != NULL) {
103029e8fb76Smillert if (pat_add(str, dir) < 0)
103176b0a314Sespie tar_usage();
103229e8fb76Smillert sawpat = 1;
103376b0a314Sespie }
1034fc5cb1eaSguenther if (ferror(fp)) {
1035fc5cb1eaSguenther syswarn(1, errno,
1036fc5cb1eaSguenther "Unable to read from %s",
1037fc5cb1eaSguenther strcmp(file, "-") ? file :
1038fc5cb1eaSguenther "stdin");
103976b0a314Sespie tar_usage();
104076b0a314Sespie }
1041fc5cb1eaSguenther if (strcmp(file, "-") != 0)
1042fc5cb1eaSguenther fclose(fp);
104329e8fb76Smillert } else if (strcmp(*argv, "-C") == 0) {
104429e8fb76Smillert if (*++argv == NULL)
104529e8fb76Smillert break;
104629e8fb76Smillert chdname = *argv++;
1047a7a4d07aSotto havechd++;
104829e8fb76Smillert } else if (pat_add(*argv++, chdname) < 0)
1049df930be7Sderaadt tar_usage();
105029e8fb76Smillert else
105129e8fb76Smillert sawpat = 1;
10523c2af966Sdownsj }
10533c2af966Sdownsj /*
1054fd899314Smichaels * if patterns were added, we are doing chdir()
1055fd899314Smichaels * on a file-by-file basis, else, just one
1056fd899314Smichaels * global chdir (if any) after opening input.
10573c2af966Sdownsj */
1058fd899314Smichaels if (sawpat > 0)
1059fd899314Smichaels chdname = NULL;
10603c2af966Sdownsj }
1061df930be7Sderaadt break;
1062df930be7Sderaadt case ARCHIVE:
1063df930be7Sderaadt case APPND:
1064f30fa552Sjca frmt = &fsub[format];
10654b311c3bSmillert
10664bbb0cd1Skstailey if (chdname != NULL) { /* initial chdir() */
1067fd899314Smichaels if (ftree_add(chdname, 1) < 0)
1068df930be7Sderaadt tar_usage();
10693c2af966Sdownsj }
10703c2af966Sdownsj
107129e8fb76Smillert while (nincfiles || *argv != NULL) {
107229e8fb76Smillert char *file, *dir;
107329e8fb76Smillert
107429e8fb76Smillert /*
107529e8fb76Smillert * If we queued up any include files, pull them in
107629e8fb76Smillert * now. Otherwise, check for -I and -C positional
107729e8fb76Smillert * flags. Anything else must be a file to include
107829e8fb76Smillert * in the archive.
107929e8fb76Smillert */
108029e8fb76Smillert if (nincfiles) {
108129e8fb76Smillert file = incfiles->file;
108229e8fb76Smillert dir = incfiles->dir;
108329e8fb76Smillert incfiles++;
108429e8fb76Smillert nincfiles--;
108529e8fb76Smillert } else if (strcmp(*argv, "-I") == 0) {
10864bbb0cd1Skstailey if (*++argv == NULL)
10873c2af966Sdownsj break;
108829e8fb76Smillert file = *argv++;
108929e8fb76Smillert dir = NULL;
109029e8fb76Smillert } else
109129e8fb76Smillert file = NULL;
109229e8fb76Smillert if (file != NULL) {
109376b0a314Sespie FILE *fp;
109476b0a314Sespie char *str;
109576b0a314Sespie
109629e8fb76Smillert /* Set directory if needed */
109729e8fb76Smillert if (dir) {
109829e8fb76Smillert if (ftree_add(dir, 1) < 0)
109929e8fb76Smillert tar_usage();
110029e8fb76Smillert }
110176b0a314Sespie
110229e8fb76Smillert if (strcmp(file, "-") == 0)
110329e8fb76Smillert fp = stdin;
110429e8fb76Smillert else if ((fp = fopen(file, "r")) == NULL) {
1105fc5cb1eaSguenther syswarn(1, errno, "Unable to open %s",
1106fc5cb1eaSguenther file);
110776b0a314Sespie tar_usage();
110876b0a314Sespie }
1109f9bbbf45Sfgsch while ((str = get_line(fp)) != NULL) {
111076b0a314Sespie if (ftree_add(str, 0) < 0)
111176b0a314Sespie tar_usage();
111276b0a314Sespie }
1113fc5cb1eaSguenther if (ferror(fp)) {
1114fc5cb1eaSguenther syswarn(1, errno,
1115fc5cb1eaSguenther "Unable to read from %s",
1116fc5cb1eaSguenther strcmp(file, "-") ? file : "stdin");
111776b0a314Sespie tar_usage();
111876b0a314Sespie }
1119fc5cb1eaSguenther if (strcmp(file, "-") != 0)
1120fc5cb1eaSguenther fclose(fp);
112129e8fb76Smillert } else if (strcmp(*argv, "-C") == 0) {
112229e8fb76Smillert if (*++argv == NULL)
112329e8fb76Smillert break;
112429e8fb76Smillert if (ftree_add(*argv++, 1) < 0)
112529e8fb76Smillert tar_usage();
1126a7a4d07aSotto havechd++;
112729e8fb76Smillert } else if (ftree_add(*argv++, 0) < 0)
11283c2af966Sdownsj tar_usage();
11293c2af966Sdownsj }
1130df930be7Sderaadt /*
1131df930be7Sderaadt * no read errors allowed on updates/append operation!
1132df930be7Sderaadt */
1133df930be7Sderaadt maxflt = 0;
1134df930be7Sderaadt break;
1135df930be7Sderaadt }
1136df930be7Sderaadt }
1137df930be7Sderaadt
1138c01bd743Sespie static int mkpath(char *);
1139cd90c754Sderaadt
1140c01bd743Sespie static int
mkpath(char * path)1141366a2d32Stb mkpath(char *path)
1142849a3f9cStholo {
1143849a3f9cStholo struct stat sb;
1144be87792eSmillert char *slash;
1145849a3f9cStholo int done = 0;
1146849a3f9cStholo
1147849a3f9cStholo slash = path;
1148849a3f9cStholo
1149849a3f9cStholo while (!done) {
1150849a3f9cStholo slash += strspn(slash, "/");
1151849a3f9cStholo slash += strcspn(slash, "/");
1152849a3f9cStholo
1153849a3f9cStholo done = (*slash == '\0');
1154849a3f9cStholo *slash = '\0';
1155849a3f9cStholo
1156849a3f9cStholo if (stat(path, &sb)) {
1157849a3f9cStholo if (errno != ENOENT || mkdir(path, 0777)) {
1158849a3f9cStholo paxwarn(1, "%s", path);
1159849a3f9cStholo return (-1);
1160849a3f9cStholo }
1161849a3f9cStholo } else if (!S_ISDIR(sb.st_mode)) {
1162849a3f9cStholo syswarn(1, ENOTDIR, "%s", path);
1163849a3f9cStholo return (-1);
1164849a3f9cStholo }
1165849a3f9cStholo
1166849a3f9cStholo if (!done)
1167849a3f9cStholo *slash = '/';
1168849a3f9cStholo }
1169849a3f9cStholo
1170849a3f9cStholo return (0);
1171849a3f9cStholo }
1172f3e2c552Sderaadt
1173f3e2c552Sderaadt #ifndef NOCPIO
1174df930be7Sderaadt /*
1175df930be7Sderaadt * cpio_options()
1176df930be7Sderaadt * look at the user specified flags. set globals as required and check if
1177df930be7Sderaadt * the user specified a legal set of flags. If not, complain and exit
1178df930be7Sderaadt */
1179df930be7Sderaadt
1180df930be7Sderaadt static void
cpio_options(int argc,char ** argv)1181be87792eSmillert cpio_options(int argc, char **argv)
1182df930be7Sderaadt {
1183a47b6461Sderaadt const char *errstr;
118406edebb3Sguenther int c, list_only = 0;
1185e1fb501dShalex unsigned i;
1186537ae142Sespie char *str;
118719e7eef2Stholo FILE *fp;
118819e7eef2Stholo
118919e7eef2Stholo kflag = 1;
119019e7eef2Stholo pids = 1;
119119e7eef2Stholo pmode = 1;
1192849a3f9cStholo pmtime = 0;
119319e7eef2Stholo arcname = NULL;
119419e7eef2Stholo dflag = 1;
119519e7eef2Stholo act = -1;
1196849a3f9cStholo nodirs = 1;
1197a914b46dSpvalchev while ((c=getopt(argc,argv,"abcdfijklmoprstuvzABC:E:F:H:I:LO:SZ6")) != -1)
119819e7eef2Stholo switch (c) {
119919e7eef2Stholo case 'a':
120019e7eef2Stholo /*
120119e7eef2Stholo * preserve access time on files read
120219e7eef2Stholo */
120319e7eef2Stholo tflag = 1;
120419e7eef2Stholo break;
120519e7eef2Stholo case 'b':
120619e7eef2Stholo /*
120719e7eef2Stholo * swap bytes and half-words when reading data
120819e7eef2Stholo */
120919e7eef2Stholo break;
121019e7eef2Stholo case 'c':
121119e7eef2Stholo /*
121219e7eef2Stholo * ASCII cpio header
121319e7eef2Stholo */
121419e7eef2Stholo frmt = &(fsub[F_ACPIO]);
121519e7eef2Stholo break;
121619e7eef2Stholo case 'd':
121719e7eef2Stholo /*
121819e7eef2Stholo * create directories as needed
121919e7eef2Stholo */
1220849a3f9cStholo nodirs = 0;
122119e7eef2Stholo break;
122219e7eef2Stholo case 'f':
122319e7eef2Stholo /*
122419e7eef2Stholo * invert meaning of pattern list
122519e7eef2Stholo */
122619e7eef2Stholo cflag = 1;
122719e7eef2Stholo break;
122819e7eef2Stholo case 'i':
122919e7eef2Stholo /*
123019e7eef2Stholo * restore an archive
123119e7eef2Stholo */
123219e7eef2Stholo act = EXTRACT;
123319e7eef2Stholo break;
1234a914b46dSpvalchev case 'j':
1235a914b46dSpvalchev /*
1236a914b46dSpvalchev * use bzip2. Non standard option.
1237a914b46dSpvalchev */
1238a914b46dSpvalchev gzip_program = BZIP2_CMD;
1239a914b46dSpvalchev break;
124019e7eef2Stholo case 'k':
124119e7eef2Stholo break;
124219e7eef2Stholo case 'l':
124319e7eef2Stholo /*
124419e7eef2Stholo * use links instead of copies when possible
124519e7eef2Stholo */
124619e7eef2Stholo lflag = 1;
124719e7eef2Stholo break;
124819e7eef2Stholo case 'm':
124919e7eef2Stholo /*
125019e7eef2Stholo * preserve modification time
125119e7eef2Stholo */
125219e7eef2Stholo pmtime = 1;
125319e7eef2Stholo break;
125419e7eef2Stholo case 'o':
125519e7eef2Stholo /*
125619e7eef2Stholo * create an archive
125719e7eef2Stholo */
125819e7eef2Stholo act = ARCHIVE;
125955d472e4Snaddy if (frmt == NULL)
126019e7eef2Stholo frmt = &(fsub[F_CPIO]);
126119e7eef2Stholo break;
126219e7eef2Stholo case 'p':
126319e7eef2Stholo /*
126419e7eef2Stholo * copy-pass mode
126519e7eef2Stholo */
126619e7eef2Stholo act = COPY;
126719e7eef2Stholo break;
126819e7eef2Stholo case 'r':
126919e7eef2Stholo /*
127019e7eef2Stholo * interactively rename files
127119e7eef2Stholo */
127219e7eef2Stholo iflag = 1;
127319e7eef2Stholo break;
127419e7eef2Stholo case 's':
127519e7eef2Stholo /*
127619e7eef2Stholo * swap bytes after reading data
127719e7eef2Stholo */
127819e7eef2Stholo break;
127919e7eef2Stholo case 't':
128019e7eef2Stholo /*
128119e7eef2Stholo * list contents of archive
128219e7eef2Stholo */
128306edebb3Sguenther list_only = 1;
128419e7eef2Stholo break;
128519e7eef2Stholo case 'u':
128619e7eef2Stholo /*
128719e7eef2Stholo * replace newer files
128819e7eef2Stholo */
128919e7eef2Stholo kflag = 0;
129019e7eef2Stholo break;
129119e7eef2Stholo case 'v':
129219e7eef2Stholo /*
129319e7eef2Stholo * verbose operation mode
129419e7eef2Stholo */
129519e7eef2Stholo vflag = 1;
129619e7eef2Stholo break;
129719e7eef2Stholo case 'z':
129819e7eef2Stholo /*
129919e7eef2Stholo * use gzip. Non standard option.
130019e7eef2Stholo */
130119e7eef2Stholo gzip_program = GZIP_CMD;
130219e7eef2Stholo break;
130319e7eef2Stholo case 'A':
130419e7eef2Stholo /*
130519e7eef2Stholo * append mode
130619e7eef2Stholo */
130719e7eef2Stholo act = APPND;
130819e7eef2Stholo break;
130919e7eef2Stholo case 'B':
131019e7eef2Stholo /*
131119e7eef2Stholo * Use 5120 byte block size
131219e7eef2Stholo */
131319e7eef2Stholo wrblksz = 5120;
131419e7eef2Stholo break;
131519e7eef2Stholo case 'C':
131619e7eef2Stholo /*
131719e7eef2Stholo * set block size in bytes
131819e7eef2Stholo */
1319a47b6461Sderaadt wrblksz = strtonum(optarg, 0, INT_MAX, &errstr);
1320a47b6461Sderaadt if (errstr) {
1321a47b6461Sderaadt paxwarn(1, "Invalid block size %s: %s",
1322a47b6461Sderaadt optarg, errstr);
1323a47b6461Sderaadt pax_usage();
1324a47b6461Sderaadt }
132519e7eef2Stholo break;
132619e7eef2Stholo case 'E':
132719e7eef2Stholo /*
132819e7eef2Stholo * file with patterns to extract or list
132919e7eef2Stholo */
133019e7eef2Stholo if ((fp = fopen(optarg, "r")) == NULL) {
1331fc5cb1eaSguenther syswarn(1, errno, "Unable to open %s",
1332fc5cb1eaSguenther optarg);
133319e7eef2Stholo cpio_usage();
1334df930be7Sderaadt }
1335f9bbbf45Sfgsch while ((str = get_line(fp)) != NULL) {
133619e7eef2Stholo pat_add(str, NULL);
133719e7eef2Stholo }
1338fc5cb1eaSguenther if (ferror(fp)) {
1339fc5cb1eaSguenther syswarn(1, errno,
1340fc5cb1eaSguenther "Unable to read from %s", optarg);
1341537ae142Sespie cpio_usage();
1342537ae142Sespie }
1343fc5cb1eaSguenther fclose(fp);
134419e7eef2Stholo break;
134519e7eef2Stholo case 'F':
134619e7eef2Stholo case 'I':
134719e7eef2Stholo case 'O':
134819e7eef2Stholo /*
134919e7eef2Stholo * filename where the archive is stored
135019e7eef2Stholo */
135119e7eef2Stholo if ((optarg[0] == '-') && (optarg[1]== '\0')) {
135219e7eef2Stholo /*
135319e7eef2Stholo * treat a - as stdin
135419e7eef2Stholo */
135519e7eef2Stholo arcname = NULL;
135619e7eef2Stholo break;
135719e7eef2Stholo }
135819e7eef2Stholo arcname = optarg;
135919e7eef2Stholo break;
136019e7eef2Stholo case 'H':
136119e7eef2Stholo /*
136219e7eef2Stholo * specify an archive format on write
136319e7eef2Stholo */
1364e1fb501dShalex for (i = 0; i < sizeof(fsub)/sizeof(FSUB); ++i)
1365e1fb501dShalex if (fsub[i].name != NULL &&
1366e1fb501dShalex strcmp(fsub[i].name, optarg) == 0)
136719e7eef2Stholo break;
1368e43eba20Sguenther if (i < sizeof(fsub)/sizeof(FSUB)) {
1369e43eba20Sguenther frmt = &fsub[i];
1370e43eba20Sguenther break;
1371e43eba20Sguenther }
137219e7eef2Stholo paxwarn(1, "Unknown -H format: %s", optarg);
137319e7eef2Stholo (void)fputs("cpio: Known -H formats are:", stderr);
137419e7eef2Stholo for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i)
1375e43eba20Sguenther if (fsub[i].name != NULL)
1376e43eba20Sguenther (void)fprintf(stderr, " %s",
1377e43eba20Sguenther fsub[i].name);
137819e7eef2Stholo (void)fputs("\n\n", stderr);
137919e7eef2Stholo cpio_usage();
138019e7eef2Stholo break;
138119e7eef2Stholo case 'L':
138219e7eef2Stholo /*
138319e7eef2Stholo * follow symbolic links
138419e7eef2Stholo */
138519e7eef2Stholo Lflag = 1;
138619e7eef2Stholo break;
138719e7eef2Stholo case 'S':
138819e7eef2Stholo /*
138919e7eef2Stholo * swap halfwords after reading data
139019e7eef2Stholo */
139119e7eef2Stholo break;
139219e7eef2Stholo case 'Z':
139319e7eef2Stholo /*
139419e7eef2Stholo * use compress. Non standard option.
139519e7eef2Stholo */
139619e7eef2Stholo gzip_program = COMPRESS_CMD;
139719e7eef2Stholo break;
139819e7eef2Stholo case '6':
139919e7eef2Stholo /*
140019e7eef2Stholo * process Version 6 cpio format
140119e7eef2Stholo */
140219e7eef2Stholo frmt = &(fsub[F_OCPIO]);
140319e7eef2Stholo break;
140419e7eef2Stholo default:
140519e7eef2Stholo cpio_usage();
140619e7eef2Stholo break;
140719e7eef2Stholo }
140819e7eef2Stholo argc -= optind;
140919e7eef2Stholo argv += optind;
141019e7eef2Stholo
141119e7eef2Stholo /*
141219e7eef2Stholo * process the args as they are interpreted by the operation mode
141319e7eef2Stholo */
141419e7eef2Stholo switch (act) {
141519e7eef2Stholo case EXTRACT:
141606edebb3Sguenther if (list_only) {
141706edebb3Sguenther act = LIST;
141806edebb3Sguenther
141906edebb3Sguenther /*
142006edebb3Sguenther * cpio is like pax: list to stderr
142106edebb3Sguenther * unless in list mode
142206edebb3Sguenther */
142306edebb3Sguenther listf = stdout;
142406edebb3Sguenther }
14254bbb0cd1Skstailey while (*argv != NULL)
142619e7eef2Stholo if (pat_add(*argv++, NULL) < 0)
142719e7eef2Stholo cpio_usage();
142819e7eef2Stholo break;
142919e7eef2Stholo case COPY:
14304bbb0cd1Skstailey if (*argv == NULL) {
143119e7eef2Stholo paxwarn(0, "Destination directory was not supplied");
143219e7eef2Stholo cpio_usage();
143319e7eef2Stholo }
1434849a3f9cStholo dirptr = *argv;
1435849a3f9cStholo if (mkpath(dirptr) < 0)
1436849a3f9cStholo cpio_usage();
143719e7eef2Stholo --argc;
1438849a3f9cStholo ++argv;
143919e7eef2Stholo /* FALL THROUGH */
144019e7eef2Stholo case ARCHIVE:
144119e7eef2Stholo case APPND:
14424bbb0cd1Skstailey if (*argv != NULL)
144319e7eef2Stholo cpio_usage();
144419e7eef2Stholo /*
144519e7eef2Stholo * no read errors allowed on updates/append operation!
144619e7eef2Stholo */
144719e7eef2Stholo maxflt = 0;
1448f9bbbf45Sfgsch while ((str = get_line(stdin)) != NULL) {
14491fb6e2dfSjaredy ftree_add(str, 0);
1450fc709564Saaron }
1451fc5cb1eaSguenther if (ferror(stdin)) {
1452fc5cb1eaSguenther syswarn(1, errno, "Unable to read from %s",
1453fc5cb1eaSguenther "stdin");
1454537ae142Sespie cpio_usage();
145519e7eef2Stholo }
145619e7eef2Stholo break;
145719e7eef2Stholo default:
145819e7eef2Stholo cpio_usage();
145919e7eef2Stholo break;
146019e7eef2Stholo }
146119e7eef2Stholo }
1462f3e2c552Sderaadt #endif /* !NOCPIO */
1463df930be7Sderaadt
1464df930be7Sderaadt /*
1465df930be7Sderaadt * printflg()
1466df930be7Sderaadt * print out those invalid flag sets found to the user
1467df930be7Sderaadt */
1468df930be7Sderaadt
1469df930be7Sderaadt static void
printflg(unsigned int flg)1470df930be7Sderaadt printflg(unsigned int flg)
1471df930be7Sderaadt {
1472df930be7Sderaadt int nxt;
1473df930be7Sderaadt int pos = 0;
1474df930be7Sderaadt
1475df930be7Sderaadt (void)fprintf(stderr,"%s: Invalid combination of options:", argv0);
147642cf9836Stholo while ((nxt = ffs(flg)) != 0) {
1477f37d86feSguenther flg >>= nxt;
1478df930be7Sderaadt pos += nxt;
1479df930be7Sderaadt (void)fprintf(stderr, " -%c", flgch[pos-1]);
1480df930be7Sderaadt }
1481df930be7Sderaadt (void)putc('\n', stderr);
1482df930be7Sderaadt }
1483df930be7Sderaadt
1484df930be7Sderaadt /*
1485df930be7Sderaadt * opt_next()
1486df930be7Sderaadt * called by format specific options routines to get each format specific
1487df930be7Sderaadt * flag and value specified with -o
1488df930be7Sderaadt * Return:
1489df930be7Sderaadt * pointer to next OPLIST entry or NULL (end of list).
1490df930be7Sderaadt */
1491df930be7Sderaadt
1492df930be7Sderaadt OPLIST *
opt_next(void)1493df930be7Sderaadt opt_next(void)
1494df930be7Sderaadt {
1495df930be7Sderaadt OPLIST *opt;
1496df930be7Sderaadt
1497df930be7Sderaadt if ((opt = ophead) != NULL)
1498df930be7Sderaadt ophead = ophead->fow;
1499df930be7Sderaadt return(opt);
1500df930be7Sderaadt }
1501df930be7Sderaadt
1502df930be7Sderaadt /*
1503df930be7Sderaadt * bad_opt()
1504df930be7Sderaadt * generic routine used to complain about a format specific options
1505df930be7Sderaadt * when the format does not support options.
1506df930be7Sderaadt */
1507df930be7Sderaadt
1508c01bd743Sespie static int
bad_opt(void)1509df930be7Sderaadt bad_opt(void)
1510df930be7Sderaadt {
1511be87792eSmillert OPLIST *opt;
1512df930be7Sderaadt
1513df930be7Sderaadt if (ophead == NULL)
1514df930be7Sderaadt return(0);
1515df930be7Sderaadt /*
1516df930be7Sderaadt * print all we were given
1517df930be7Sderaadt */
151842cf9836Stholo paxwarn(1,"These format options are not supported");
1519df930be7Sderaadt while ((opt = opt_next()) != NULL)
1520df930be7Sderaadt (void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value);
1521df930be7Sderaadt pax_usage();
1522df930be7Sderaadt return(0);
1523df930be7Sderaadt }
1524df930be7Sderaadt
1525df930be7Sderaadt /*
1526df930be7Sderaadt * opt_add()
1527df930be7Sderaadt * breaks the value supplied to -o into a option name and value. options
1528df930be7Sderaadt * are given to -o in the form -o name-value,name=value
15294eb0b000Smillert * multiple -o may be specified.
1530df930be7Sderaadt * Return:
1531df930be7Sderaadt * 0 if format in name=value format, -1 if -o is passed junk
1532df930be7Sderaadt */
1533df930be7Sderaadt
1534c01bd743Sespie static int
opt_add(const char * str)15357097cf92Smillert opt_add(const char *str)
1536df930be7Sderaadt {
1537be87792eSmillert OPLIST *opt;
1538be87792eSmillert char *frpt;
1539be87792eSmillert char *pt;
1540be87792eSmillert char *endpt;
15417097cf92Smillert char *dstr;
1542df930be7Sderaadt
1543df930be7Sderaadt if ((str == NULL) || (*str == '\0')) {
154442cf9836Stholo paxwarn(0, "Invalid option name");
1545df930be7Sderaadt return(-1);
1546df930be7Sderaadt }
15477097cf92Smillert if ((dstr = strdup(str)) == NULL) {
1548450fd277Smillert paxwarn(0, "Unable to allocate space for option list");
1549450fd277Smillert return(-1);
1550450fd277Smillert }
15517097cf92Smillert frpt = endpt = dstr;
1552df930be7Sderaadt
1553df930be7Sderaadt /*
1554df930be7Sderaadt * break into name and values pieces and stuff each one into a
1555df930be7Sderaadt * OPLIST structure. When we know the format, the format specific
1556df930be7Sderaadt * option function will go through this list
1557df930be7Sderaadt */
1558df930be7Sderaadt while ((frpt != NULL) && (*frpt != '\0')) {
1559df930be7Sderaadt if ((endpt = strchr(frpt, ',')) != NULL)
1560df930be7Sderaadt *endpt = '\0';
1561df930be7Sderaadt if ((pt = strchr(frpt, '=')) == NULL) {
156242cf9836Stholo paxwarn(0, "Invalid options format");
15637097cf92Smillert free(dstr);
1564df930be7Sderaadt return(-1);
1565df930be7Sderaadt }
1566f38a3474Sguenther if ((opt = malloc(sizeof(OPLIST))) == NULL) {
156742cf9836Stholo paxwarn(0, "Unable to allocate space for option list");
15687097cf92Smillert free(dstr);
1569df930be7Sderaadt return(-1);
1570df930be7Sderaadt }
1571f4bfdd1aSderaadt dstr = NULL; /* parts of string going onto the OPLIST */
1572df930be7Sderaadt *pt++ = '\0';
1573df930be7Sderaadt opt->name = frpt;
1574df930be7Sderaadt opt->value = pt;
1575df930be7Sderaadt opt->fow = NULL;
1576df930be7Sderaadt if (endpt != NULL)
1577df930be7Sderaadt frpt = endpt + 1;
1578df930be7Sderaadt else
1579df930be7Sderaadt frpt = NULL;
1580df930be7Sderaadt if (ophead == NULL) {
1581df930be7Sderaadt optail = ophead = opt;
1582df930be7Sderaadt continue;
1583df930be7Sderaadt }
1584df930be7Sderaadt optail->fow = opt;
1585df930be7Sderaadt optail = opt;
1586df930be7Sderaadt }
1587f4bfdd1aSderaadt free(dstr);
1588df930be7Sderaadt return(0);
1589df930be7Sderaadt }
1590df930be7Sderaadt
1591df930be7Sderaadt /*
1592df930be7Sderaadt * str_offt()
1593df930be7Sderaadt * Convert an expression of the following forms to an off_t > 0.
1594df930be7Sderaadt * 1) A positive decimal number.
1595df930be7Sderaadt * 2) A positive decimal number followed by a b (mult by 512).
1596df930be7Sderaadt * 3) A positive decimal number followed by a k (mult by 1024).
1597df930be7Sderaadt * 4) A positive decimal number followed by a m (mult by 512).
1598df930be7Sderaadt * 5) A positive decimal number followed by a w (mult by sizeof int)
1599df930be7Sderaadt * 6) Two or more positive decimal numbers (with/without k,b or w).
1600ff61e0a4Sprovos * separated by x (also * for backwards compatibility), specifying
1601df930be7Sderaadt * the product of the indicated values.
1602df930be7Sderaadt * Return:
1603df930be7Sderaadt * 0 for an error, a positive value o.w.
1604df930be7Sderaadt */
1605df930be7Sderaadt
1606df930be7Sderaadt static off_t
str_offt(char * val)1607df930be7Sderaadt str_offt(char *val)
1608df930be7Sderaadt {
1609df930be7Sderaadt char *expr;
1610df930be7Sderaadt off_t num, t;
1611df930be7Sderaadt
161228071059Sguenther num = strtoll(val, &expr, 0);
161328071059Sguenther if ((num == LLONG_MAX) || (num <= 0) || (expr == val))
1614df930be7Sderaadt return(0);
1615df930be7Sderaadt
1616df930be7Sderaadt switch (*expr) {
1617df930be7Sderaadt case 'b':
1618df930be7Sderaadt t = num;
1619df930be7Sderaadt num *= 512;
1620df930be7Sderaadt if (t > num)
1621df930be7Sderaadt return(0);
1622df930be7Sderaadt ++expr;
1623df930be7Sderaadt break;
1624df930be7Sderaadt case 'k':
1625df930be7Sderaadt t = num;
1626df930be7Sderaadt num *= 1024;
1627df930be7Sderaadt if (t > num)
1628df930be7Sderaadt return(0);
1629df930be7Sderaadt ++expr;
1630df930be7Sderaadt break;
1631df930be7Sderaadt case 'm':
1632df930be7Sderaadt t = num;
1633df930be7Sderaadt num *= 1048576;
1634df930be7Sderaadt if (t > num)
1635df930be7Sderaadt return(0);
1636df930be7Sderaadt ++expr;
1637df930be7Sderaadt break;
1638df930be7Sderaadt case 'w':
1639df930be7Sderaadt t = num;
1640df930be7Sderaadt num *= sizeof(int);
1641df930be7Sderaadt if (t > num)
1642df930be7Sderaadt return(0);
1643df930be7Sderaadt ++expr;
1644df930be7Sderaadt break;
1645df930be7Sderaadt }
1646df930be7Sderaadt
1647df930be7Sderaadt switch (*expr) {
1648df930be7Sderaadt case '\0':
1649df930be7Sderaadt break;
1650df930be7Sderaadt case '*':
1651df930be7Sderaadt case 'x':
1652df930be7Sderaadt t = num;
1653df930be7Sderaadt num *= str_offt(expr + 1);
1654df930be7Sderaadt if (t > num)
1655df930be7Sderaadt return(0);
1656df930be7Sderaadt break;
1657df930be7Sderaadt default:
1658df930be7Sderaadt return(0);
1659df930be7Sderaadt }
1660df930be7Sderaadt return(num);
1661df930be7Sderaadt }
1662df930be7Sderaadt
1663537ae142Sespie char *
get_line(FILE * f)1664f9bbbf45Sfgsch get_line(FILE *f)
1665537ae142Sespie {
1666fc5cb1eaSguenther char *str = NULL;
1667fc5cb1eaSguenther size_t size = 0;
1668fc5cb1eaSguenther ssize_t len;
1669537ae142Sespie
1670fc5cb1eaSguenther do {
1671fc5cb1eaSguenther len = getline(&str, &size, f);
1672fc5cb1eaSguenther if (len == -1) {
1673fc5cb1eaSguenther free(str);
1674fc5cb1eaSguenther return NULL;
1675537ae142Sespie }
1676fc5cb1eaSguenther if (str[len - 1] == '\n')
1677fc5cb1eaSguenther str[len - 1] = '\0';
1678fc5cb1eaSguenther } while (str[0] == '\0');
1679fc5cb1eaSguenther return str;
1680537ae142Sespie }
1681537ae142Sespie
1682df930be7Sderaadt /*
1683df930be7Sderaadt * no_op()
1684df930be7Sderaadt * for those option functions where the archive format has nothing to do.
1685df930be7Sderaadt * Return:
1686df930be7Sderaadt * 0
1687df930be7Sderaadt */
1688df930be7Sderaadt
1689df930be7Sderaadt static int
no_op(void)1690df930be7Sderaadt no_op(void)
1691df930be7Sderaadt {
1692df930be7Sderaadt return(0);
1693df930be7Sderaadt }
1694df930be7Sderaadt
1695df930be7Sderaadt /*
1696df930be7Sderaadt * pax_usage()
1697df930be7Sderaadt * print the usage summary to the user
1698df930be7Sderaadt */
1699df930be7Sderaadt
1700df930be7Sderaadt void
pax_usage(void)1701df930be7Sderaadt pax_usage(void)
1702df930be7Sderaadt {
17036bf8d0c9Sjaredy (void)fputs(
1704a914b46dSpvalchev "usage: pax [-0cdjnOvz] [-E limit] [-f archive] [-G group] [-s replstr]\n"
17053d5126eaSsobrado " [-T range] [-U user] [pattern ...]\n"
1706a914b46dSpvalchev " pax -r [-0cDdijknOuvYZz] [-E limit] [-f archive] [-G group] [-o options]\n"
1707abe48ab4Ssobrado " [-p string] [-s replstr] [-T range] [-U user] [pattern ...]\n"
1708a914b46dSpvalchev " pax -w [-0adHijLOPtuvXz] [-B bytes] [-b blocksize] [-f archive]\n"
1709abe48ab4Ssobrado " [-G group] [-o options] [-s replstr] [-T range] [-U user]\n"
1710abe48ab4Ssobrado " [-x format] [file ...]\n"
1711bb4196c7Sjmc " pax -rw [-0DdHikLlnOPtuvXYZ] [-G group] [-p string] [-s replstr]\n"
17123d5126eaSsobrado " [-T range] [-U user] [file ...] directory\n",
17136bf8d0c9Sjaredy stderr);
1714df930be7Sderaadt exit(1);
1715df930be7Sderaadt }
1716df930be7Sderaadt
1717df930be7Sderaadt /*
1718df930be7Sderaadt * tar_usage()
1719df930be7Sderaadt * print the usage summary to the user
1720df930be7Sderaadt */
1721df930be7Sderaadt
1722df930be7Sderaadt void
tar_usage(void)1723df930be7Sderaadt tar_usage(void)
1724df930be7Sderaadt {
172554fea831Sjaredy (void)fputs(
1726f30fa552Sjca "usage: tar {crtux}[014578beFfHhjLmNOoPpqsvwXZz]\n"
1727f30fa552Sjca " [blocking-factor | format | archive | replstr]\n"
1728f30fa552Sjca " [-C directory] [-I file] [file ...]\n"
17295e460854Stedu " tar {-crtux} [-014578eHhjLmNOoPpqvwXZz] [-b blocking-factor]\n"
1730f30fa552Sjca " [-C directory] [-F format] [-f archive] [-I file]\n"
1731f30fa552Sjca " [-s replstr] [file ...]\n",
1732d2b23181Sderaadt stderr);
1733df930be7Sderaadt exit(1);
1734df930be7Sderaadt }
1735df930be7Sderaadt
1736f3e2c552Sderaadt #ifndef NOCPIO
1737df930be7Sderaadt /*
1738df930be7Sderaadt * cpio_usage()
1739df930be7Sderaadt * print the usage summary to the user
1740df930be7Sderaadt */
1741df930be7Sderaadt
1742df930be7Sderaadt void
cpio_usage(void)1743df930be7Sderaadt cpio_usage(void)
1744df930be7Sderaadt {
1745abe48ab4Ssobrado (void)fputs(
1746a914b46dSpvalchev "usage: cpio -o [-AaBcjLvZz] [-C bytes] [-F archive] [-H format]\n"
1747abe48ab4Ssobrado " [-O archive] < name-list [> archive]\n"
1748a914b46dSpvalchev " cpio -i [-6BbcdfjmrSstuvZz] [-C bytes] [-E file] [-F archive] [-H format]\n"
1749abe48ab4Ssobrado " [-I archive] [pattern ...] [< archive]\n"
1750abe48ab4Ssobrado " cpio -p [-adLlmuv] destination-directory < name-list\n",
1751abe48ab4Ssobrado stderr);
1752df930be7Sderaadt exit(1);
1753df930be7Sderaadt }
1754f3e2c552Sderaadt #endif /* !NOCPIO */
1755a48f739dSguenther
1756a48f739dSguenther #ifndef SMALL
1757a48f739dSguenther static int
compress_id(char * blk,int size)1758a48f739dSguenther compress_id(char *blk, int size)
1759a48f739dSguenther {
1760a48f739dSguenther if (size >= 2 && blk[0] == '\037' && blk[1] == '\235') {
1761a48f739dSguenther paxwarn(0, "input compressed with %s; use the -%c option"
1762a48f739dSguenther " to decompress it", "compress", 'Z');
1763a48f739dSguenther exit(1);
1764a48f739dSguenther }
1765a48f739dSguenther return (-1);
1766a48f739dSguenther }
1767a48f739dSguenther
1768a48f739dSguenther static int
gzip_id(char * blk,int size)1769a48f739dSguenther gzip_id(char *blk, int size)
1770a48f739dSguenther {
1771a48f739dSguenther if (size >= 2 && blk[0] == '\037' && blk[1] == '\213') {
1772a48f739dSguenther paxwarn(0, "input compressed with %s; use the -%c option"
1773a48f739dSguenther " to decompress it", "gzip", 'z');
1774a48f739dSguenther exit(1);
1775a48f739dSguenther }
1776a48f739dSguenther return (-1);
1777a48f739dSguenther }
1778a48f739dSguenther
1779a48f739dSguenther static int
bzip2_id(char * blk,int size)1780a48f739dSguenther bzip2_id(char *blk, int size)
1781a48f739dSguenther {
1782a48f739dSguenther if (size >= 3 && blk[0] == 'B' && blk[1] == 'Z' && blk[2] == 'h') {
1783a48f739dSguenther paxwarn(0, "input compressed with %s; use the -%c option"
1784a48f739dSguenther " to decompress it", "bzip2", 'j');
1785a48f739dSguenther exit(1);
1786a48f739dSguenther }
1787a48f739dSguenther return (-1);
1788a48f739dSguenther }
1789a48f739dSguenther
1790a48f739dSguenther static int
xz_id(char * blk,int size)1791a48f739dSguenther xz_id(char *blk, int size)
1792a48f739dSguenther {
1793a48f739dSguenther if (size >= 6 && memcmp(blk, "\xFD\x37\x7A\x58\x5A", 6) == 0) {
1794a48f739dSguenther paxwarn(0, "input compressed with xz");
1795a48f739dSguenther exit(1);
1796a48f739dSguenther }
1797a48f739dSguenther return (-1);
1798a48f739dSguenther }
1799a48f739dSguenther #endif /* !SMALL */
1800