1 /* @(#)star.c 1.412 21/08/20 Copyright 1985, 88-90, 92-96, 98, 99, 2000-2021 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)star.c 1.412 21/08/20 Copyright 1985, 88-90, 92-96, 98, 99, 2000-2021 J. Schilling";
6 #endif
7 /*
8 * Copyright (c) 1985, 88-90, 92-96, 98, 99, 2000-2021 J. Schilling
9 */
10 /*
11 * The contents of this file are subject to the terms of the
12 * Common Development and Distribution License, Version 1.0 only
13 * (the "License"). You may not use this file except in compliance
14 * with the License.
15 *
16 * See the file CDDL.Schily.txt in this distribution for details.
17 * A copy of the CDDL is also available via the Internet at
18 * http://www.opensource.org/licenses/cddl1.txt
19 *
20 * When distributing Covered Code, include this CDDL HEADER in each
21 * file and include the License file CDDL.Schily.txt from this distribution.
22 */
23
24 #define STAR_MAIN
25
26 #include <schily/stdio.h>
27 #include <schily/stdlib.h>
28 #include <schily/unistd.h>
29 #include <schily/signal.h>
30 #include <schily/string.h>
31 #include "star.h"
32 #include "props.h"
33 #include "diff.h"
34 #include <schily/wait.h>
35 #include <schily/standard.h>
36 #define __XDEV__ /* Needed to activate _dev_init() */
37 #include <schily/device.h>
38 #include <schily/fcntl.h> /* Needed for O_XATTR */
39 #include <schily/stat.h> /* Needed for umask(2) */
40 #include <schily/getargs.h>
41 #define GT_COMERR /* #define comerr gtcomerr */
42 #define GT_ERROR /* #define error gterror */
43 #include <schily/schily.h>
44 #include <schily/idcache.h>
45 #include "fifo.h" /* Needed for #undef FIFO */
46 #include "dumpdate.h"
47 #ifdef USE_FIND
48 #include <schily/walk.h>
49 #include <schily/find.h>
50 #endif
51
52 #include <schily/nlsdefs.h>
53
54 #include "starsubs.h"
55 #include "dirtime.h"
56 #include "checkerr.h"
57
58 EXPORT int main __PR((int ac, char **av));
59 LOCAL void star_create __PR((int ac, char *const *av));
60 LOCAL void checkdumptype __PR((GINFO *gp));
61 LOCAL void init_ddate __PR((char *name));
62 EXPORT void copy_create __PR((int ac, char *const *av));
63 LOCAL int getfilecount __PR((int ac, char *const *av, const char *fmt));
64 LOCAL void getdir __PR((int *acp, char *const **avp,
65 const char **dirp));
66 LOCAL void openlist __PR((void));
67 LOCAL void check_stdin __PR((char *name));
68 LOCAL void susage __PR((int ret));
69 LOCAL void usage __PR((int ret));
70 LOCAL void xusage __PR((int ret));
71 LOCAL void dusage __PR((int ret));
72 LOCAL void husage __PR((int ret));
73 LOCAL void gargs __PR((int ac, char *const *av));
74 LOCAL void star_mkvers __PR((void));
75 LOCAL void star_helpvers __PR((char *name, BOOL help, BOOL xhelp, BOOL prvers));
76 LOCAL void star_checkopts __PR((BOOL oldtar, BOOL dodesc, BOOL usetape,
77 int archive, BOOL no_fifo,
78 const char *paxopts,
79 Llong llbs));
80 EXPORT void star_verifyopts __PR((void));
81 LOCAL void star_nfiles __PR((int files, int minfiles));
82 LOCAL int getpaxH __PR((char *arg, long *valp, int *pac, char *const **pav));
83 LOCAL int getpaxL __PR((char *arg, long *valp, int *pac, char *const **pav));
84 LOCAL int getpaxP __PR((char *arg, long *valp, int *pac, char *const **pav));
85 LOCAL int getfind __PR((char *arg, long *valp, int *pac, char *const **pav));
86 LOCAL int getpaxpriv __PR((char *arg, long *valp));
87 LOCAL int getlldefault __PR((char *arg, Llong *valp, int mult));
88 EXPORT int getbnum __PR((char *arg, Llong *valp));
89 EXPORT int getknum __PR((char *arg, Llong *valp));
90 EXPORT int getknum __PR((char *arg, Llong *valp));
91 LOCAL int getenum __PR((char *arg, long *valp));
92 LOCAL int addtarfile __PR((const char *tarfile));
93 LOCAL int add_diffopt __PR((char *optstr, long *flagp));
94 LOCAL int gethdr __PR((char *optstr, long *typep));
95 LOCAL int getexclude __PR((char *arg, long *valp, int *pac, char *const **pav));
96 #ifdef USED
97 LOCAL int addfile __PR((char *optstr, long *dummy));
98 #endif
99 EXPORT void set_signal __PR((int sig, RETSIGTYPE (*handler)(int)));
100 LOCAL void exsig __PR((int sig));
101 LOCAL void sighup __PR((int sig));
102 LOCAL void sigintr __PR((int sig));
103 LOCAL void sigquit __PR((int sig));
104 LOCAL void getstamp __PR((void));
105 LOCAL const char *has_cli __PR((int ac, char *const *av));
106 LOCAL int get_ptype __PR((const char *p));
107 LOCAL void set_ptype __PR((int *pac, char *const **pav));
108 LOCAL void docompat __PR((int *pac, char *const **pav));
109 EXPORT BOOL ttyerr __PR((FILE *f));
110
111 #if defined(SIGDEFER) || defined(SVR4)
112 #define signal sigset
113 #endif
114
115 #define QIC_24_TSIZE 122880 /* 61440 kBytes */
116 #define QIC_120_TSIZE 256000 /* 128000 kBytes */
117 #define QIC_150_TSIZE 307200 /* 153600 kBytes */
118 #define QIC_250_TSIZE 512000 /* 256000 kBytes (XXX not verified) */
119 #define QIC_525_TSIZE 1025000 /* 512500 kBytes */
120 #define TSIZE(s) ((s)*TBLOCK)
121
122 char *vers; /* the full version string */
123
124 struct star_stats xstats; /* for printing statistics */
125
126 extern BOOL havepat; /* Pattern matching in use */
127
128 #define NTARFILE 100 /* Max # of archive files */
129
130 FILE *tarf; /* The current archive */
131 FILE *listf; /* File for list= option */
132 FILE *tty; /* Open /dev/tty for questions */
133 FILE *vpr; /* File for verbose printing */
134 BOOL did_stdin = FALSE; /* Did use stdin for any option */
135 const char *tarfiles[NTARFILE]; /* Cycle list of all archives */
136 int ntarfiles; /* Number of entries in list */
137 int tarfindex; /* Current index in list */
138 char *newvol_script; /* -new-volume-script name */
139 BOOL multivol = FALSE; /* -multivol specified */
140 BOOL force_noremote = FALSE; /* -force-local specified */
141 char *rmt; /* -rmt specify remote server */
142 char *rsh; /* -rsh specify rsh command */
143 char *listfile; /* File name for list= */
144 BOOL pkglist = FALSE; /* pkglist= specified */
145 char *stampfile; /* Time stamp file for -newer */
146 BOOL errflag; /* -e for abort on error */
147 const char *wdir; /* current working dir name */
148 const char *currdir; /* current -C dir argument */
149 const char *dir_flags = NULL; /* One/more -C options present */
150 BOOL bsdchdir = FALSE; /* -C only valid for next arg */
151 char *volhdr; /* VOLHDR= argument */
152 char *fs_name; /* fs-name= for snapshot fs */
153 char *dd_name; /* dumpdate= for snapshots */
154 dev_t tape_dev; /* st_dev for current archive */
155 ino_t tape_ino; /* st_ino for current archive */
156 BOOL tape_isreg = FALSE; /* Tape is a regular file */
157 #ifdef FIFO
158 BOOL use_fifo = TRUE; /* Whether to use a FIFO or not */
159 #else
160 BOOL use_fifo = FALSE; /* Whether to use a FIFO or not */
161 #endif
162 BOOL shmflag = FALSE; /* Whether to use shmem f. FIFO */
163 long fs; /* FIFO size */
164 long bs; /* TAPE block size (bytes) */
165 int nblocks = 20; /* TAPE blocks (512 byte units) */
166 long iskip; /* Inital skip bf. reading arch */
167 Llong mtskip; /* First block offset to read */
168 BOOL not_tape = FALSE; /* -sun-n not a Tape */
169 uid_t dir_uid = _BAD_UID; /* -dir-owner */
170 gid_t dir_gid = _BAD_GID; /* -dir-group */
171 uid_t my_uid; /* Current euid */
172 dev_t curfs = NODEV; /* Current st_dev for -M option */
173 struct timespec ddate; /* The current dump date */
174 time_t sixmonth; /* 6 months before limit (ls) */
175 time_t now; /* now limit (ls) */
176 /*
177 * Change default header format into XUSTAR in 2004 (see below in gargs())
178 */
179 long hdrtype = H_XSTAR; /* default header format */
180 long chdrtype = H_UNDEF; /* command line hdrtype */
181 int cmptype = C_NONE; /* compression type */
182 int iftype = I_TAR; /* command line interface type */
183 int ptype = P_STAR; /* program interface type */
184 const char *pname = NULL; /* program name with cli= */
185 BOOL paxls = FALSE; /* create PAX type listing */
186 int version = 0; /* Version from POSIX TAR hdr */
187 int swapflg = -1; /* Whether to swap input */
188 BOOL debug = FALSE; /* -debug has been specified */
189 int xdebug = 0; /* eXtended debug level */
190 int dumplevel = -1; /* level for incremental dumps */
191 int oldlevel = 0; /* dumpleve this dump refers to */
192 BOOL dump_partial = FALSE; /* Dump is not a full dump */
193 BOOL dump_cumulative = FALSE; /* -cumulative has b. specified */
194 char *dumpdates = "/etc/tardumps"; /* Database for increment. dump */
195 BOOL wtardumps = FALSE; /* Should update above file */
196 BOOL print_artype = FALSE;
197 BOOL showtime = FALSE; /* -time has been specified */
198 BOOL no_stats = FALSE; /* -no-statistics specified */
199 BOOL cpio_stats = FALSE; /* -cpio-statistics specified */
200 BOOL do_fifostats = FALSE; /* -fifostats specified */
201 BOOL numeric = FALSE; /* -numeric user ids */
202 int verbose = 0; /* -v has been specified */
203 BOOL silent = FALSE; /* -silent no informal msg */
204 BOOL prblockno = FALSE; /* -block-number for all files */
205 BOOL no_xheader = FALSE; /* -no-xheader ignore P.2001 */
206 BOOL no_fsync = -1; /* -no-fsync on extract */
207 BOOL readnull = FALSE; /* -read0 on with list= */
208 BOOL tpath = FALSE; /* -tpath print path only */
209 BOOL cflag = FALSE; /* -c has been specified */
210 BOOL uflag = FALSE; /* -u has been specified */
211 BOOL rflag = FALSE; /* -r has been specified */
212 BOOL xflag = FALSE; /* -x has been specified */
213 BOOL tflag = FALSE; /* -t has been specified */
214 BOOL copyflag = FALSE; /* -copy has been specified */
215 BOOL binflag = FALSE; /* -o binary has been specified */
216 BOOL nflag = FALSE; /* -n dummy extract mode */
217 BOOL diff_flag = FALSE; /* -diff has been specified */
218 BOOL Zflag = FALSE; /* -Z has been specified */
219 BOOL zflag = FALSE; /* -z has been specified */
220 BOOL bzflag = FALSE; /* -bz has been specified */
221 BOOL lzoflag = FALSE; /* -lzo has been specified */
222 BOOL p7zflag = FALSE; /* -7z has been specified */
223 BOOL xzflag = FALSE; /* -xz has been specified */
224 BOOL lzipflag = FALSE; /* -lzip has been specified */
225 BOOL zstdflag = FALSE; /* -zstd has been specified */
226 BOOL lzmaflag = FALSE; /* -lzma has been specified */
227 BOOL freezeflag = FALSE; /* -freeze has been specified */
228 char *compress_prg = NULL; /* -compress-program specified */
229 BOOL multblk = FALSE; /* -B has been specified */
230 BOOL one_file = FALSE; /* -one-file has been specified */
231 BOOL ignoreerr = FALSE; /* -i has been specified */
232 BOOL nodir = FALSE; /* -d do not store dirs */
233 BOOL noxdir = FALSE; /* -d do not create dirs */
234 BOOL noatime = FALSE; /* -p a pax do not restore atime */
235 BOOL nomtime = FALSE; /* -m do not restore times */
236 BOOL nochown = FALSE; /* -o do not restore owner */
237 BOOL acctime = FALSE; /* -atime has been specified */
238 BOOL pflag = FALSE; /* -p restore permissions */
239 BOOL nopflag = FALSE; /* -no-p don't restore perms */
240 BOOL dirmode = FALSE; /* -dirmode wr. dirs past files */
241 BOOL nolinkerr = FALSE; /* pr. link # err depends on -l */
242 BOOL follow = FALSE; /* -h follow symbolic links */
243 BOOL paxfollow = FALSE; /* PAX -L follow symbolic links */
244 BOOL paxHflag = FALSE; /* PAX -H follow symbolic links */
245 BOOL nodesc = FALSE; /* -D do not descenc dirs */
246 BOOL nomount = FALSE; /* -M do not cross mount points */
247 BOOL interactive = FALSE; /* -w has been specified */
248 BOOL paxinteract = FALSE; /* PAX -i has been specified */
249 BOOL signedcksum = FALSE; /* -signed-checksum */
250 BOOL partial = FALSE; /* -P write partial last record */
251 BOOL nospec = FALSE; /* -S no special files */
252 int Fflag = 0; /* -F,-FF,... no SCCS/RCS/... */
253 BOOL uncond = FALSE; /* -U unconditional extract */
254 BOOL uncond_rename = FALSE; /* -uncond-rename - ask always */
255 BOOL xdir = FALSE; /* -xdir uncond. dir extract */
256 BOOL xdot = FALSE; /* -xdot uncond '.' dir extract */
257 BOOL keep_old = FALSE; /* -k do not overwrite files */
258 BOOL refresh_old = FALSE; /* -refresh existing only */
259 BOOL abs_path = FALSE; /* -/ absolute path allowed */
260 BOOL allow_dotdot = FALSE; /* -.. '..' in path allowed */
261 BOOL secure_links = -1; /* -secure-links (no .. & /) */
262 BOOL no_dirslash = FALSE; /* -no-dirslash option */
263 BOOL notpat = FALSE; /* -not invert pattern matcher */
264 BOOL match_tree = FALSE; /* -match-tree match dir -> tree */
265 BOOL notarg = FALSE; /* PAX -c invert match */
266 BOOL paxmatch = FALSE; /* Do PAX like matching */
267 BOOL paxnflag = FALSE; /* PAX -n one match only */
268 BOOL force_hole = FALSE; /* -force-hole on extract */
269 BOOL sparse = FALSE; /* -sparse has been specified */
270 BOOL to_stdout = FALSE; /* -to-stdout extraction */
271 BOOL wready = FALSE; /* -wready wait for ready tape */
272 BOOL force_remove = FALSE; /* -force-remove on extraction */
273 BOOL ask_remove = FALSE; /* -ask-remove on extraction */
274 BOOL remove_first = FALSE; /* -remove-first on extraction */
275 BOOL remove_recursive = FALSE; /* -remove-recursive on extract */
276 BOOL keep_nonempty_dirs = FALSE; /* -keep-nonempty-dirs on extract */
277 BOOL do_install = FALSE; /* -install on extract */
278 BOOL nullout = FALSE; /* -onull - simulation write */
279 BOOL prinodes = FALSE; /* -prinodes print ino # w. -tv */
280
281 Ullong maxsize = 0; /* max file size for create */
282 struct timespec Newer = {0, 0}; /* Time stamp to compare with */
283 Ullong tsize = 0; /* Max tape size in tar blocks */
284 long diffopts = 0L; /* diffopts= bit mask */
285 BOOL nowarn = FALSE; /* -nowarn has been specified */
286 BOOL Ctime = FALSE; /* -ctime has been specified */
287 BOOL nodump = FALSE; /* -nodump has been specified */
288
289 BOOL listnew = FALSE; /* -newest list newest only */
290 BOOL listnewf = FALSE; /* -newest-file list n. plain f */
291 BOOL hpdev = FALSE; /* -hpdev non POSIX dev # */
292 BOOL modebits = FALSE; /* -modebits more than 12 bits */
293 BOOL copylinks = FALSE; /* -copylinks rather than link */
294 BOOL copyhardlinks = FALSE; /* -copyhardlinks rather than link */
295 BOOL copysymlinks = FALSE; /* -copysymlinks rather than link */
296 BOOL copydlinks = FALSE; /* copy content of linked dirs */
297 BOOL hardlinks = FALSE; /* -hardlinks ext. sym as hard */
298 BOOL symlinks = FALSE; /* -symlinks ext. hard as syml */
299 BOOL linkdata = FALSE; /* -link-data data in hardlinks */
300 BOOL doacl = FALSE; /* -acl handle ACLs */
301 BOOL doxattr = FALSE; /* -xattr handle extended fattr */
302 BOOL dolxattr = FALSE; /* -xattr-linux extended fattr */
303 BOOL dofflags = FALSE; /* -xfflags handle extended ffl */
304 BOOL link_dirs = FALSE; /* -link-dirs hard linked dirs */
305 BOOL dodump = FALSE; /* -dump mode with all ino prop */
306 BOOL dorestore = FALSE; /* -restore in incremental mode */
307 BOOL dopartial = FALSE; /* -partial in incremental mode */
308 BOOL forcerestore = FALSE; /* -force-restore in incremental mode */
309 BOOL dometa = FALSE; /* -meta ino metadata only */
310 BOOL dumpmeta = FALSE; /* -dumpmeta metadata for ctime */
311 BOOL xmeta = FALSE; /* -xmeta extract meta files */
312 BOOL lowmem = FALSE; /* -lowmem use less memory */
313 #ifdef USE_FIND
314 BOOL dofind = FALSE; /* -find option found */
315 int find_ac = 0; /* ac past -find option */
316 char *const *find_av = NULL; /* av past -find option */
317 int find_pac = 0; /* ac for first find primary */
318 char *const *find_pav = NULL; /* av for first find primary */
319 findn_t *find_node; /* syntaxtree from find_parse() */
320 void *plusp; /* residual for -exec ...{} + */
321 int find_patlen; /* len for -find pattern state */
322 char *codeset = "ISO8859-1";
323 #ifdef USE_SELINUX
324 BOOL selinux_enabled;
325 #endif
326
327
328 LOCAL int walkflags = WALK_CHDIR | WALK_PHYS | WALK_NOEXIT |
329 WALK_STRIPLDOT;
330 LOCAL int maxdepth = -1;
331 LOCAL int mindepth = -1;
332 EXPORT struct WALK walkstate;
333 #endif
334
335 BOOL tcompat = FALSE; /* Tar compatibility (av[0] is tar/ustar) */
336 BOOL fcompat = FALSE; /* Archive file compatibility was requested */
337
338 int intr = 0; /* Did catch a ^C */
339
340 BOOL do_subst;
341
342 /*
343 * _grinfo is only used to read the information.
344 */
345 GINFO _ginfo; /* Global (volhdr) information */
346 GINFO _grinfo; /* Global read information */
347 GINFO *gip = &_ginfo; /* Global information pointer */
348 GINFO *grip = &_grinfo; /* Global read info pointer */
349
350 struct ga_props gaprops;
351
352 #ifdef STAR_FAT
353 #include "suntar.c"
354 #include "gnutar.c"
355 #include "cpio.c"
356 #include "pax.c"
357 #endif
358
359 #ifndef NO_STAR_MAIN
360 #define PTYPE_DEFAULT P_STAR
361 /*
362 * Achtung: Optionen wie f= sind problematisch denn dadurch dass -ffilename geht,
363 * werden wird bei Falschschreibung von -fifo evt. eine Datei angelegt wird.
364 */
365 /* BEGIN CSTYLED */
366 char _opts[] = "C*,find~,help,xhelp,version,debug,xdebug#,xd#,bsdchdir,pax-ls,level#,tardumps*,wtardumps,time,no_statistics,no-statistics,cpio-statistics,fifostats,numeric,v+,block-number,tpath,c,u,r,x,t,copy,xcopy,n,diff,diffopts&,H&,artype&,print-artype,fs-name*,force_hole,force-hole,sparse,to_stdout,to-stdout,wready,force_remove,force-remove,ask_remove,ask-remove,remove_first,remove-first,remove_recursive,remove-recursive,keep-nonempty-dirs,install,nullout,onull,fifo,no_fifo,no-fifo,shm,fs&,VOLHDR*,list*,pkglist*,multivol,new-volume-script*,force-local,restore,partial,force-restore,freeze,file&,f&,T,Z,z,bz,j,lzo,7z,xz,lzip,zstd,lzma,compress-program*,rmt*,rsh*,bs&,blocks&,b&,B,pattern&,pat&,one-file,iskip&,mtskip&,i,d,m,o,nochown,pax-o*,pax-p&,a,atime,p,no-p,dirmode,l,h,L,pax-L~,pax-H~,pax-P~,D,dodesc,M,xdev,w,pax-i,I,X&,exclude-from&,O,signed_checksum,signed-checksum,P,S,F+,U,uncond-rename,xdir,xdot,k,keep_old_files,keep-old-files,refresh_old_files,refresh-old-files,refresh,/,..,secure-links,no-secure-links%0,no-dirslash,not,V,match-tree,pax-match,pax-n,pax-c,notarg,maxsize&,newer*,ctime,nodump,tsize&,qic24,qic120,qic150,qic250,qic525,nowarn,newest_file,newest-file,newest,hpdev,modebits,copylinks,copyhardlinks,copysymlinks,copydlinks,hardlinks,symlinks,link-data,acl,xattr,xattr-linux,xfflags,link-dirs,dumpdate*,dump,dump\\+%2,cumulative,dump-cumulative,meta,dumpmeta,xmeta,silent,lowmem,no-xheader,no-fsync%1,do-fsync%0,read0,errctl&,e,data-change-warn,prinodes,dir-owner*,dir-group*,umask*,s&,pax-s&,?";
367 /* END CSTYLED */
368 char *opts = _opts;
369 #else
370 extern char *opts;
371 #endif /* NO_STAR_MAIN */
372
373 EXPORT int
main(ac,av)374 main(ac, av)
375 int ac;
376 char **av;
377 {
378 int cac = ac;
379 char *const *cav = av;
380 int oac;
381 char *const *oav;
382 int excode = 0;
383 char *tgt_dir = NULL;
384
385 save_args(ac, av);
386
387 #ifdef USE_NLS
388 if (setlocale(LC_ALL, "") != NULL) {
389 #ifdef CODESET
390 codeset = nl_langinfo(CODESET);
391 #endif
392 }
393
394 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
395 #define TEXT_DOMAIN "star" /* Use this only if it weren't */
396 #endif
397 { char *dir;
398 dir = searchfileinpath("share/locale", F_OK,
399 SIP_ANY_FILE|SIP_NO_PATH, NULL);
400 if (dir)
401 (void) bindtextdomain(TEXT_DOMAIN, dir);
402 else
403 #if defined(PROTOTYPES) && defined(INS_BASE)
404 (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
405 #else
406 (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
407 #endif
408 (void) textdomain(TEXT_DOMAIN);
409 }
410
411 #endif /* USE_NLS */
412
413 my_uid = geteuid();
414 my_uid = getuid();
415
416 docompat(&cac, &cav);
417
418 gargs(cac, cav);
419 if (pname) { /* cli=xxx seen as argv[1] */
420 --cac, cav++;
421 }
422 --cac, cav++;
423 oac = cac;
424 oav = cav;
425
426 #ifdef SIGHUP
427 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
428 set_signal(SIGHUP, sighup);
429 #endif
430 #ifdef SIGINT
431 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
432 set_signal(SIGINT, sigintr);
433 #endif
434 #ifdef SIGQUIT
435 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
436 set_signal(SIGQUIT, sigquit);
437 #endif
438 #ifdef SIGINFO
439 /*
440 * Be polite to *BSD users.
441 * They copied our idea and implemented intermediate status
442 * printing in 'dd' in 1990.
443 */
444 if (signal(SIGINFO, SIG_IGN) != SIG_IGN)
445 set_signal(SIGINFO, sigquit);
446 #endif
447
448 file_raise((FILE *)NULL, FALSE);
449
450 initbuf(nblocks); /* Calls initfifo() if needed */
451
452 (void) openremote(); /* This needs super user privilleges */
453
454 if (geteuid() != getuid()) { /* AIX does not like to do this */
455 /* If we are not root */
456 #ifdef HAVE_SETREUID
457 if (setreuid(-1, getuid()) < 0)
458 #else
459 #ifdef HAVE_SETEUID
460 if (seteuid(getuid()) < 0)
461 #else
462 if (setuid(getuid()) < 0)
463 #endif
464 #endif
465 comerr("Panic cannot set back effective uid.\n");
466 }
467 my_uid = geteuid();
468 /*
469 * WARNING: We now are no more able to open a new remote connection
470 * unless we have been called by root.
471 * It you like to do a remote multi-tape backup to different hosts
472 * and do not call star from root, you are lost.
473 */
474
475 #ifdef USE_SELINUX
476 selinux_enabled = is_selinux_enabled() > 0;
477 #endif
478
479 opentape();
480
481 if (stampfile)
482 getstamp();
483
484 star_mkvers(); /* Create version string */
485 setprops(chdrtype); /* Set up properties for archive format */
486 /*
487 * If the archive format contains extended headers, we
488 * need to set up iconv().
489 */
490 if (cflag && props.pr_flags & PR_XHDR)
491 utf8_init(S_CREATE); /* Init. iconv() setup for xheader */
492
493 if (!(rflag || uflag) || chdrtype != H_UNDEF)
494 star_verifyopts(); /* Chk if options are valid for chdrtype */
495
496 if (dumplevel >= 0)
497 initdumpdates(dumpdates, wtardumps);
498 dev_init(debug); /* Init device macro handling */
499 xbinit(); /* Initialize buffer for extended headers */
500
501 if (dir_flags && (!tflag || copyflag))
502 wdir = dogetwdir(TRUE); /* Exit on failure */
503 else if (xflag)
504 wdir = dogetwdir(FALSE); /* Return NULL on failure */
505
506 getnstimeofday(&ddate);
507 now = ddate.tv_sec + 60;
508 sixmonth = ddate.tv_sec - 6L*30L*24L*60L*60L;
509 #ifdef USE_FIND
510 find_timeinit(ddate.tv_sec);
511 walkinitstate(&walkstate);
512 #endif
513 if (dd_name)
514 init_ddate(dd_name);
515
516 ginit(); /* Initialize global (volhdr) info */
517
518 if (copyflag) {
519 int lac = cac;
520 char *const *lav = cav;
521
522 if (tflag) {
523 /*
524 * Flag no args at 'extract' side in -c -list mode.
525 */
526 cav = &oav[oac];
527 cac = 0;
528 } else {
529 /*
530 * Find last file type argument.
531 */
532 for (; ; --cac, cav++) {
533 if (getlfiles(&cac, &cav, &gaprops, opts) == 0)
534 break;
535 lac = cac;
536 lav = cav;
537 }
538 tgt_dir = lav[0];
539 cav = &lav[1];
540 cac = lac-1;
541 if (cac > 0) {
542 errmsgno(EX_BAD,
543 "Badly placed option after target directory.\n");
544 susage(EX_BAD);
545 }
546 }
547 }
548
549 /*
550 * These callbacks are only called in case we leave star via comexit().
551 * We do this only in case of a severe error.
552 * These functions are called in the inverse set up oder, so checkerrs()
553 * called last.
554 */
555 on_comerr((void(*)__PR((int, void *)))checkerrs, (void *)0);
556 on_comerr((void(*)__PR((int, void *)))prstats, (void *)0);
557 if (xflag)
558 on_comerr((void(*)__PR((int, void *)))flushdirtimes, (void *)0);
559 #ifdef FIFO
560 if (use_fifo) {
561 runfifo(oac, oav); /* Run FIFO, fork() is called here */
562 on_comerr(fifo_onexit, /* For foreground FIFO process only */
563 (void *)0);
564 }
565 #endif
566
567 if (copyflag) {
568 do_subst = FALSE; /* Substitution only at create side */
569 havepat = FALSE; /* Patterns only at create side */
570 listfile = NULL; /* Listfile only at create side */
571 swapflg = 0; /* Don't try to find out the hdrtype */
572 dir_flags = tgt_dir; /* Target directory only at extract */
573 #ifdef USE_FIND
574 dofind = FALSE; /* -find expr only at create side */
575 #endif
576 }
577
578 if (xflag || tflag || diff_flag) {
579 /*
580 * cflag will never be TRUE in this case
581 */
582 if (listfile) {
583 openlist();
584 hash_build(listf);
585 if ((currdir = dir_flags) != NULL)
586 dochdir(currdir, TRUE);
587 } else {
588 #ifdef USE_FIND
589 if (!dofind) {
590 #endif
591 for (; ; --cac, cav++) {
592 if (dir_flags)
593 getdir(&cac, &cav, &currdir);
594 if (getlfiles(&cac, &cav, &gaprops, opts) == 0)
595 break;
596 addarg(cav[0]);
597 }
598 #ifdef USE_FIND
599 }
600 #endif
601 closepattern();
602 }
603 if (tflag) {
604 list();
605 } else {
606 /*
607 * xflag || diff_flag
608 * First change dir to the one or last -C arg
609 * in case there is no pattern in list.
610 */
611 if ((currdir = dir_flags) != NULL)
612 dochdir(currdir, TRUE);
613 if (xflag)
614 extract(volhdr);
615 else
616 diff();
617 }
618 }
619 closepattern();
620 if (uflag || rflag) {
621 /*
622 * cflag will also be TRUE in this case
623 */
624 skipall();
625 syncbuf();
626 backtape();
627 }
628 if (cflag) {
629 /*
630 * xflag, tflag, diff_flag will never be TRUE in this case
631 */
632 star_create(cac, cav);
633 }
634
635 #ifdef USE_FIND
636 find_plusflush(plusp, &walkstate);
637 #endif
638 fflush(vpr); /* Avoid output mix with checklinks() from 2>&1 | tee */
639 if (!nolinkerr)
640 checklinks();
641 if (!use_fifo) {
642 extern m_stats *stats;
643
644 closetape();
645 runnewvolscript(stats->volno+1, tarfindex+1);
646 }
647 #ifdef FIFO
648 if (use_fifo)
649 fifo_exit(0);
650 #endif
651
652 #ifdef HAVE_FORK
653 while (wait(0) >= 0) {
654 ;
655 /* LINTED */
656 }
657 #endif
658 if (!no_stats)
659 prpatstats();
660 prstats();
661 if (checkerrs()) {
662 if (!nowarn && !no_stats) {
663 errmsgno(EX_BAD,
664 "Processed all possible files, despite earlier errors.\n");
665 }
666 excode = -2;
667 }
668 if (intr) {
669 /*
670 * This happens when we are in create mode and the interrupt is
671 * delayed in order to prevent inconsistent archives.
672 */
673 if (excode == 0)
674 excode = -4;
675 }
676 if (!isatty(fdown(stderr))) {
677 char *p;
678
679 /*
680 * Try to avoid that the verbose or diagnostic messages are
681 * sometimes lost if called on Linux via "ssh". Unfortunately
682 * this does not always help. If you like to make sure that
683 * nothing gets lost, call: ssh host "star .... ; sleep 10"
684 */
685 fflush(vpr);
686 fflush(stderr);
687 #ifdef HAVE_FSYNC
688 if (!no_fsync) {
689 fsync(fdown(vpr));
690 fsync(fdown(stderr));
691 }
692 #endif
693 /*
694 * Use the sleep only in case that the environment is set, but
695 * keep the fflush() as stderr may be buffered.
696 */
697 if ((p = getenv("STAR_WORKAROUNDS")) != NULL &&
698 strstr(p, "ssh-tcpip") != NULL)
699 usleep(100000);
700 }
701 #ifdef FIFO
702 /*
703 * Fetch errno from FIFO if available.
704 */
705 if (fifo_errno())
706 excode = fifo_errno();
707 #endif
708 if (dumplevel >= 0 && wtardumps) {
709 if (excode != 0 || intr) {
710 errmsgno(EX_BAD, "'%s' not written due to problems during backup.\n",
711 dumpdates);
712 } else {
713 int dflags = 0;
714
715 if (gip->dumptype != DT_FULL)
716 dflags |= DD_PARTIAL;
717 if (dump_cumulative)
718 dflags |= DD_CUMULATIVE;
719
720 writedumpdates(dumpdates, gip->filesys, dumplevel, dflags, &ddate);
721 }
722 }
723 #ifdef DBG_MALLOC
724 aprintlist(stdout, 1);
725 #endif
726
727 exit(excode);
728 /* NOTREACHED */
729 return (excode); /* keep lint happy */
730 }
731
732 LOCAL void
star_create(ac,av)733 star_create(ac, av)
734 int ac;
735 char *const *av;
736 {
737 /*
738 * xflag, tflag, diff_flag will never be TRUE in this case
739 */
740 put_release(); /* Pax 'g' vendor unique */
741 put_archtype(); /* Pax 'g' vendor unique */
742 if (dumplevel < 0) /* In dump mode we first collect the data */
743 put_volhdr(volhdr, TRUE);
744 #ifdef USE_FIND
745 if (dumplevel >= 0 && (listfile || dofind))
746 comerrno(EX_BAD,
747 "Cannot do incremental dumps with list= or -find.\n");
748 #else
749 if (dumplevel >= 0 && listfile)
750 comerrno(EX_BAD, "Cannot do incremental dumps with list=.\n");
751 #endif
752 #ifdef USE_FIND
753 if (dofind) {
754 if (listfile)
755 walkopen(&walkstate);
756
757 if (find_patlen > 0) {
758 walkstate.patstate = ___malloc(sizeof (int) * find_patlen,
759 "space for pattern state");
760 }
761
762 walkstate.walkflags = walkflags;
763 walkstate.maxdepth = maxdepth;
764 walkstate.mindepth = mindepth;
765 walkstate.lname = NULL;
766 walkstate.tree = find_node;
767 walkstate.err = 0;
768 walkstate.pflags = 0;
769
770 if (listfile)
771 openlist();
772
773 if ((currdir = dir_flags) != NULL)
774 dochdir(currdir, TRUE);
775
776 if (listfile) {
777 if (find_pav > find_av)
778 comerrno(EX_BAD, "Too many args for list= option.\n");
779 createlist(&walkstate);
780 } else {
781 nodesc = TRUE;
782 for (av = find_av; av != find_pav; av++) {
783 treewalk(*av, walkfunc, &walkstate);
784 }
785 }
786 } else
787 #endif
788 if (listfile) {
789 openlist();
790 if ((currdir = dir_flags) != NULL)
791 dochdir(currdir, TRUE);
792 /*
793 * We do not allow file type args together with list=
794 * Note that Sun tar allows a mix.
795 */
796 if (getlfiles(&ac, &av, &gaprops, opts) > 0)
797 comerrno(EX_BAD, "Too many args for list= option.\n");
798 createlist(NULL);
799 } else {
800 const char *cdir = NULL;
801
802 for (; ; --ac, av++) {
803 if (dir_flags)
804 getdir(&ac, &av, &currdir);
805 if (currdir && cdir != currdir) {
806 if (!(dochdir(wdir, FALSE) &&
807 dochdir(currdir, FALSE)))
808 break;
809 cdir = currdir;
810 }
811
812 if (getlfiles(&ac, &av, &gaprops, opts) == 0)
813 break;
814 if (dumplevel >= 0) {
815 dumpd_t *dp;
816 int dflags = 0;
817
818 /*
819 * The next message is only for debugging
820 * purposes to find problems related to option
821 * parsing.
822 */
823 if (ac > 1)
824 errmsgno(EX_BAD, "INFO: ac %c av[0] '%s'\n", ac, av[0]);
825
826 /*
827 * We cannot have more than one file type
828 * argument in dump mode if we like to grant
829 * the consistency of dumps. In theory, it would
830 * be possible to allow it, but then we will not
831 * be able to deal with renames from outside the
832 * scope to inside the scope.
833 */
834 if (ac > 1)
835 comerrno(EX_BAD,
836 "Only one file type arg allowed in dump mode.\n");
837 if (cdir == NULL) {
838 comerrno(EX_BAD,
839 "Need '-C dir' in dump mode.\n");
840 /* NOTREACHED */
841 }
842 if (cdir[0] != '/')
843 comerrno(EX_BAD,
844 "Need absolute path with '-C dir' in dump mode.\n");
845 if (!streql(av[0], "."))
846 comerrno(EX_BAD,
847 "File type arg must be '.' in dump mode.\n");
848
849 gip->filesys = (char *)cdir;
850 gip->gflags |= GF_FILESYS;
851 if (fs_name) {
852 gip->filesys = fs_name;
853 gip->cwd = (char *)cdir;
854 gip->gflags |= GF_CWD;
855 }
856 /*
857 * Set dump type to full/partial.
858 */
859 checkdumptype(gip);
860 if (gip->dumptype != DT_FULL)
861 dflags |= DD_PARTIAL;
862 if (dump_cumulative)
863 dflags |= DD_CUMULATIVE;
864 dp = checkdumpdates(gip->filesys, dumplevel, dflags);
865 if (dp == NULL && dumplevel > 0 && gip->dumptype != DT_FULL)
866 dp = checkdumpdates(gip->filesys, dumplevel, 0);
867 if (dp == NULL && dumplevel > 0) {
868 errmsgno(EX_BAD,
869 "No level 0 dump entry found in '%s'.\n",
870 dumpdates);
871 comerrno(EX_BAD, "Perform a level 0 dump first.\n");
872 }
873 if (dp) {
874 oldlevel = dp->dd_level;
875 Newer = dp->dd_date;
876 gip->reflevel = dp->dd_level;
877 gip->refdate = dp->dd_date;
878 gip->gflags |= (GF_REFLEVEL|GF_REFDATE);
879 }
880
881 adddumpdates(gip->filesys, dumplevel, dflags,
882 &ddate, TRUE);
883
884 error("Type of this level %d%s dump: %s\n",
885 dumplevel,
886 (dflags & DD_PARTIAL) ? "P":" ",
887 dt_name(gip->dumptype));
888 error("Date of this level %d%s dump: %s\n",
889 dumplevel,
890 (dflags & DD_PARTIAL) ? "P":" ",
891 dumpdate(&ddate));
892 error("Date of last level %d%s dump: %s\n",
893 oldlevel,
894 (dp && (dp->dd_flags & DD_PARTIAL)) ?
895 "P":" ",
896 dumpdate(&Newer));
897
898 put_volhdr(volhdr, TRUE);
899 }
900 if (intr)
901 break;
902 curfs = NODEV;
903 /*
904 * To avoid empty incremental dumps, make sure that
905 * av[0] is always in the archive in with dumplevel >= 0
906 */
907 create(av[0], paxHflag, dumplevel >= 0);
908 if (bsdchdir && wdir && !dochdir(wdir, FALSE))
909 break;
910 }
911 }
912 flushlinks();
913 weof();
914 buf_drain();
915 }
916
917 LOCAL void
checkdumptype(gp)918 checkdumptype(gp)
919 GINFO *gp;
920 {
921 FINFO dinfo;
922 FINFO ddinfo;
923 BOOL full = FALSE;
924
925 if (!_getinfo(".", &dinfo))
926 return;
927 if (!_getinfo("..", &ddinfo))
928 return;
929
930 if (dinfo.f_ino == ddinfo.f_ino && dinfo.f_dev == ddinfo.f_dev)
931 full = TRUE;
932
933 if (dinfo.f_dev != ddinfo.f_dev)
934 full = TRUE;
935 if (full && !dump_partial && !havepat) {
936 gp->gflags |= GF_DUMPTYPE;
937 gp->dumptype = DT_FULL;
938 } else {
939 gp->gflags |= GF_DUMPTYPE;
940 gp->dumptype = DT_PARTIAL;
941 }
942 }
943
944 LOCAL void
init_ddate(name)945 init_ddate(name)
946 char *name;
947 {
948 FINFO ddinfo;
949
950 if (!_getinfo(name, &ddinfo))
951 comerr("Cannot stat '%s'.\n", name);
952
953 ddate.tv_sec = ddinfo.f_mtime;
954 ddate.tv_nsec = ddinfo.f_mnsec;
955 }
956
957 EXPORT void
copy_create(ac,av)958 copy_create(ac, av)
959 int ac;
960 char *const *av;
961 {
962 int oac = ac;
963 char *const *oav = av;
964 int lac = ac;
965 #ifdef __needed__
966 char *const *lav = av;
967 #endif
968
969 verbose = 0; /* Verbose not at create side */
970 interactive = FALSE; /* Interactive not at create side */
971
972 if (!tflag) {
973 /*
974 * Cut off beginning at last file type arg.
975 */
976 for (; ; --ac, av++) {
977 if (getlfiles(&ac, &av, &gaprops, opts) == 0)
978 break;
979 lac = ac;
980 #ifdef __needed__
981 lav = av;
982 #endif
983 }
984 ac = oac-lac;
985 av = oav;
986 }
987
988 star_create(ac, av);
989 /*
990 * XXX Fehlerzusammenfassung fuer die -c reate Seite?
991 */
992 }
993
994 LOCAL int
getfilecount(ac,av,fmt)995 getfilecount(ac, av, fmt)
996 int ac;
997 char *const *av;
998 const char *fmt;
999 {
1000 int files = 0;
1001
1002 for (; ; --ac, av++) {
1003 if (getlfiles(&ac, &av, &gaprops, fmt) == 0)
1004 break;
1005 files++;
1006 }
1007 return (files);
1008 }
1009
1010 LOCAL void
getdir(acp,avp,dirp)1011 getdir(acp, avp, dirp)
1012 int *acp;
1013 char *const **avp;
1014 const char **dirp;
1015 {
1016 int len = strlen(opts);
1017 char *dir = NULL;
1018
1019 if (iftype == I_CPIO || iftype == I_PAX)
1020 return;
1021 /*
1022 * Skip all other flags.
1023 * Note that we need to patch away "...,?" at the end of the
1024 * option string so this will not interfere with a -C dir
1025 * option in the command line.
1026 */
1027 if (opts[len-1] == '?' && opts[len-2] == ',')
1028 opts[len-2] = '\0';
1029 getlfiles(acp, avp, &gaprops, &opts[3]);
1030
1031 if (debug) /* temporary */
1032 errmsgno(EX_BAD, "Flag/File: '%s'.\n", (*avp)[0]);
1033
1034 again:
1035 /*
1036 * Get next '-C dir' option
1037 */
1038 if (getlargs(acp, avp, &gaprops, "C*", &dir) < 0) {
1039 int cac = *acp;
1040 /*
1041 * Skip all other flags that are known to star.
1042 */
1043 if (getlfiles(acp, avp, &gaprops, &opts[3]) < 0) {
1044 /*
1045 * If we did find other legal flags, try again.
1046 */
1047 if (cac > *acp)
1048 goto again;
1049
1050 errmsgno(EX_BAD, "Badly placed Option: %s.\n",
1051 (*avp)[0]);
1052 if ((*avp)[1] != NULL)
1053 errmsgno(EX_BAD, "Next arg is '%s'.\n",
1054 (*avp)[1]);
1055 susage(EX_BAD);
1056 }
1057 }
1058 if (opts[len-2] == '\0')
1059 opts[len-2] = ',';
1060 if (dir)
1061 *dirp = dir;
1062 if (debug) /* temporary */
1063 errmsgno(EX_BAD, "Dirp: '%s' Dir: %s.\n", *dirp, dir);
1064 }
1065
1066 LOCAL void
openlist()1067 openlist()
1068 {
1069 if (streql(listfile, "-")) {
1070 check_stdin("list=");
1071 listf = stdin;
1072 listfile = "stdin";
1073 } else if ((listf = lfilemopen(listfile, "r", S_IRWALL)) == (FILE *)NULL)
1074 comerr("Cannot open '%s'.\n", listfile);
1075 }
1076
1077 LOCAL void
check_stdin(name)1078 check_stdin(name)
1079 char *name;
1080 {
1081 if (did_stdin) {
1082 comerrno(EX_BAD,
1083 "Did already use stdin, cannot use stdin for '%s' option.\n",
1084 name);
1085 }
1086 did_stdin = TRUE;
1087 }
1088
1089 #ifndef NO_STAR_MAIN
1090 /*
1091 * Short usage
1092 */
1093 LOCAL void
susage(ret)1094 susage(ret)
1095 int ret;
1096 {
1097 #ifdef STAR_FAT
1098 switch (ptype) {
1099
1100 case P_SUNTAR:
1101 suntar_susage(ret); exit(ret);
1102 /* NOTREACHED */
1103 case P_GNUTAR:
1104 gnutar_susage(ret); exit(ret);
1105 /* NOTREACHED */
1106 case P_PAX:
1107 pax_susage(ret); exit(ret);
1108 /* NOTREACHED */
1109 case P_CPIO:
1110 cpio_susage(ret); exit(ret);
1111 /* NOTREACHED */
1112 }
1113 #endif
1114 #ifdef USE_FIND
1115 error("Usage:\t%s cmd [options] [-find] file1 ... filen [find expression]\n", get_progname());
1116 #else
1117 error("Usage:\t%s cmd [options] file1 ... filen\n", get_progname());
1118 #endif
1119 error("\t%s cli=name ...\n", get_progname());
1120 error("\nUse\t%s -help\n", get_progname());
1121 error("and\t%s -xhelp\n", get_progname());
1122 error("to get a list of valid cmds and options.\n");
1123 error("\nUse\t%s H=help\n", get_progname());
1124 error("to get a list of valid archive header formats.\n");
1125 error("\nUse\t%s diffopts=help\n", get_progname());
1126 error("to get a list of valid diff options.\n");
1127 exit(ret);
1128 /* NOTREACHED */
1129 }
1130
1131 LOCAL void
usage(ret)1132 usage(ret)
1133 int ret;
1134 {
1135 #ifdef STAR_FAT
1136 switch (ptype) {
1137
1138 case P_SUNTAR:
1139 suntar_usage(ret); exit(ret);
1140 /* NOTREACHED */
1141 case P_GNUTAR:
1142 gnutar_usage(ret); exit(ret);
1143 /* NOTREACHED */
1144 case P_PAX:
1145 pax_usage(ret); exit(ret);
1146 /* NOTREACHED */
1147 case P_CPIO:
1148 cpio_usage(ret); exit(ret);
1149 /* NOTREACHED */
1150 }
1151 #endif
1152 #ifdef USE_FIND
1153 error("Usage:\t%s cmd [options] [-find] file1 ... filen [find expression]\n", get_progname());
1154 #else
1155 error("Usage:\t%s cmd [options] file1 ... filen\n", get_progname());
1156 #endif
1157 error("\t%s cli=name ...\n", get_progname());
1158 error("Cmd:\n");
1159 error("\t-c/-u/-r\tcreate/update/replace archive with named files to tape\n");
1160 error("\t-x/-t/-n\textract/list/trace named files from tape\n");
1161 error("\t-copy\t\tcopy named files to destination directory\n");
1162 error("\t-diff\t\tdiff archive against file system (see -xhelp)\n");
1163 error("Options:\n");
1164 error("\t-help\t\tprint this help\n");
1165 error("\t-xhelp\t\tprint extended help\n");
1166 error("\t-version\tprint version information and exit\n");
1167 error("\t-xcopy\t\talias for -copy -sparse -acl\n");
1168 error("\tblocks=#,b=#\tset blocking factor to #x512 Bytes (default 20)\n");
1169 error("\tfile=nm,f=nm\tuse 'nm' as tape instead of stdin/stdout\n");
1170 error("\t-T\t\tuse $TAPE as tape instead of stdin/stdout\n");
1171 error("\t-[0-7]\t\tSelect an alternative tape drive\n");
1172 #ifdef FIFO
1173 error("\t-fifo/-no-fifo\tuse/don't use a fifo to optimize data flow from/to tape\n");
1174 #if defined(USE_MMAP) && defined(USE_USGSHM)
1175 error("\t-shm\t\tuse SysV shared memory for fifo\n");
1176 #endif
1177 #endif
1178 error("\t-v\t\tincrement verbose level\n");
1179 error("\t-block-number\tprint the block numbers where the TAR headers start\n");
1180 error("\t-tpath\t\tuse with -t, -cv or -diff to list path names only\n");
1181 error("\tH=header\tgenerate 'header' type archive (see H=help)\n");
1182 error("\tartype=header\tgenerate 'header' type archive (see artype=help)\n");
1183 error("\t-print-artype\tcheck and print archive and compression type on one line and exit.\n");
1184 error("\tC=dir\t\tperform a chdir to 'dir' before storing/extracting next file\n");
1185 error("\t-bsdchdir\tdo BSD style C= (only related to the next file type arg)\n");
1186 #ifdef USE_FIND
1187 error("\t-find\t\tOption separator: Use find command line to the right.\n");
1188 #endif
1189 error("\t-Z\t\tpipe input/output through compress, does not work on tapes\n");
1190 error("\t-z\t\tpipe input/output through gzip, does not work on tapes\n");
1191 error("\t-j,-bz\t\tpipe input/output through bzip2, does not work on tapes\n");
1192 error("\t-lzo\t\tpipe input/output through lzop, does not work on tapes\n");
1193 error("\t-7z\t\tpipe input/output through p7zip, does not work on tapes\n");
1194 error("\t-xz\t\tpipe input/output through xz, does not work on tapes\n");
1195 error("\t-lzip\t\tpipe input/output through lzip, does not work on tapes\n");
1196 error("\t-zstd\t\tpipe input/output through zstd, does not work on tapes\n");
1197 error("\t-lzma\t\tpipe input/output through lzma, does not work on tapes\n");
1198 error("\t-freeze\t\tpipe input/output through freeze, does not work on tapes\n");
1199 error("\tcompress-program=name\tpipe input/output through program 'name', does not work on tapes\n");
1200 error("\t-B\t\tperform multiple reads (needed on pipes)\n");
1201 error("\t-i\t\tignore checksum errors\n");
1202 error("\t-d\t\tdo not store/create directories\n");
1203 error("\t-m\t\tdo not restore access and modification time\n");
1204 error("\t-o,-nochown\tdo not restore owner and group\n");
1205 error("\t-pax-o string\tPAX options (none specified with SUSv2 / UNIX-98)\n");
1206 error("\t-pax-p string\tuse PAX like privileges set up\n");
1207 error("\t-a,-atime\treset access time after storing file\n");
1208 error("\t-p\t\trestore file permissions\n");
1209 error("\t-no-p\t\tdo not restore file permissions\n");
1210 error("\t-l\t\tdo not print a message if not all links are dumped\n");
1211 error("\t-h,-L\t\tfollow symbolic links as if they were files\n");
1212 error("\t-pax-L\t\tfollow symbolic links as if they were files (PAX style)\n");
1213 error("\t-pax-H\t\tfollow symbolic links from cmdline as if they were files (PAX style)\n");
1214 error("\t-D\t\tdo not descend directories\n");
1215 error("\t-M,-xdev\tdo not descend mounting points\n");
1216 error("\t-w\t\tdo interactive creation/extraction/renaming\n");
1217 error("\t-pax-i\t\tdo interactive creation/extraction/renaming (PAX style)\n");
1218 error("\t-O\t\tbe compatible to old tar (except for checksum bug)\n");
1219 error("\t-P\t\tlast record may be partial (useful on cartridge tapes)\n");
1220 error("\t-S\t\tdo not store/create special files\n");
1221 error("\t-F,-FF,-FFF,...\tdo not store/create SCCS/RCS, core and object files\n");
1222 error("\t-U\t\trestore files unconditionally\n");
1223 error("\t-uncond-rename\twith interactive restore unconditionally ask for name\n");
1224 exit(ret);
1225 /* NOTREACHED */
1226 }
1227
1228 LOCAL void
xusage(ret)1229 xusage(ret)
1230 int ret;
1231 {
1232 #ifdef STAR_FAT
1233 switch (ptype) {
1234
1235 case P_SUNTAR:
1236 suntar_xusage(ret); exit(ret);
1237 /* NOTREACHED */
1238 case P_GNUTAR:
1239 gnutar_xusage(ret); exit(ret);
1240 /* NOTREACHED */
1241 case P_PAX:
1242 pax_xusage(ret); exit(ret);
1243 /* NOTREACHED */
1244 case P_CPIO:
1245 cpio_xusage(ret); exit(ret);
1246 /* NOTREACHED */
1247 }
1248 #endif
1249 #ifdef USE_FIND
1250 error("Usage:\t%s cmd [options] [-find] file1 ... filen [find expression]\n", get_progname());
1251 #else
1252 error("Usage:\t%s cmd [options] file1 ... filen\n", get_progname());
1253 #endif
1254 error("\t%s cli=name ...\n", get_progname());
1255 error("Extended options:\n");
1256 error("\tdiffopts=optlst\tcomma separated list of diffopts (see diffopts=help)\n");
1257 error("\t-debug\t\tprint additional debug messages\n");
1258 error("\txdebug=#,xd=#\tset extended debug level\n");
1259 error("\t-pax-ls\t\tprint a PAX type file listing\n");
1260 error("\t-silent\t\tno not print informational messages\n");
1261 error("\t-lowmem\t\ttry to use less memory for operation\n");
1262 error("\t-not,-V\t\tuse those files which do not match pat= pattern\n");
1263 error("\t-pax-match\tuse PAX like pattern matching\n");
1264 error("\t-pax-n\t\tonly one match per pattern allowed\n");
1265 error("\t-notarg,-pax-c\tuse those files which do not match file type pattern\n");
1266 error("\tVOLHDR=name\tuse name to generate a volume header\n");
1267 error("\t-xdir\t\textract dir even if the current is never\n");
1268 error("\t-xdot\t\textract first '.' or './' dir even if the current is never\n");
1269 error("\t-dirmode\twrite directories after the files they contain\n");
1270 error("\t-link-dirs\tlook for hard linked directories in create mode\n");
1271 error("\t-dump\t\tarchive more ino metadata (needed for incremental dumps)\n");
1272 error("\t-dump+\t\tlike -dump but with more global meta data\n");
1273 error("\t-restore\trestore incremental dumps\n");
1274 error("\t-partial\tpermit to restore partial incremental dumps\n");
1275 error("\t-force-restore\tforce to restore partial incremental dumps\n");
1276 error("\t-no-xheader\tdo not read or write extended headers regardless of format\n");
1277 error("\t-meta\t\tuse inode metadata only (omit file content)\n");
1278 error("\t-xmeta\t\textract meta files\n");
1279 error("\t-dumpmeta\tuse inode metadata in dump mode if only ctime is newer\n");
1280 error("\t-keep-old-files,-k\tkeep existing files\n");
1281 error("\t-refresh-old-files\trefresh existing files, don't create new files\n");
1282 error("\t-refresh\trefresh existing files, don't create new files\n");
1283 error("\t-/\t\tdon't strip leading '/'s from file names\n");
1284 error("\t-..\t\tdon't skip filenames that contain '..' in non-interactive extract\n");
1285 error("\t-secure-links\tdon't extract links that start with '/' or contain '..' (default)\n");
1286 error("\t-no-secure-links\textract links that start with '/' or contain '..'\n");
1287 error("\t-no-dirslash\tdon't append a slash to directory names\n");
1288 error("\tlist=name\tread filenames from named file\n");
1289 error("\t-X name\t\texclude filenames from named file\n");
1290 error("\t-exclude-from name\texclude filenames from named file\n");
1291 error("\tpkglist=name\tread filenames from named file (unstable interface for sps)\n");
1292 error("\t-read0\t\tread null terminated filenames with list=\n");
1293 error("\t-data-change-warn\ttreat data/size changes in create more as warning only\n");
1294 error("\t-e\t\tabort on all error conditions undefined by errctl=\n");
1295 error("\terrctl=name\tread error contrl definitions from named file\n");
1296 error("\t-dodesc\t\tdo descend directories found in a list= file\n");
1297 error("\tpattern=p,pat=p\tset matching pattern\n");
1298 error("\t-one-file\texit after extracting one file from a matching pattern\n");
1299 error("\tiskip=#\t\tskip # of bytes in first archive record\n");
1300 error("\tmtskip=#\tskip # of 512 byte blocks from start of archive\n");
1301 error("\t-match-tree\tdo not scan the content of non matching dirs in create mode\n");
1302 error("\ts=replstr\tApply change(1) like pattern substitution -s /old/new/gp on filenames\n");
1303 error("\tpax-s=replstr\tApply ed(1) like pattern substitution -pax-s /old/new/gp on filenames\n");
1304 error("\tlevel=dumplevel\tset current incremental dump level\n");
1305 error("\t-cumulative\tmake a cumulative incremental dump (relative to same level)\n");
1306 error("\ttardumps=name\tset file name for tar dump dates, default is %s\n", dumpdates);
1307 error("\t-wtardumps\tupdate file for tar dump dates if in dump mode\n");
1308 error("\tdumpdate=name\tuse timestamp from name instead of current time for %s\n", dumpdates);
1309 error("\tfs-name=name\tuse name instead of mount point for %s\n", dumpdates);
1310 error("\tmaxsize=#\tdo not store file if bigger than # (default mult is kB)\n");
1311 error("\tnewer=name\tstore only files which are newer than 'name'\n");
1312 error("\t-multivol\tread/write/list a multi volume archive\n");
1313 error("\tnew-volume-script=script\tcall 'script' at end of each volume\n");
1314 error("\t-ctime\t\tuse ctime for newer= option\n");
1315 error("\t-nodump\t\tdo not dump files that have the nodump flag set\n");
1316 error("\t-acl\t\thandle access control lists\n");
1317 error("\t-xattr\t\thandle extended file attributes\n");
1318 error("\t-xattr-linux\t\thandle extended file attributes (Linux variant)\n");
1319 error("\t-xfflags\thandle extended file flags\n");
1320 error("\t-prinodes\tif archive contains inode number, print them in list mode\n");
1321 error("\tbs=#\t\tset (output) block size to #\n");
1322 #ifdef FIFO
1323 error("\tfs=#\t\tset fifo size to #\n");
1324 #endif
1325 error("\ttsize=#\t\tset tape volume size to # (default multiplier is 512)\n");
1326 error("\t-qic24\t\tset tape volume size to %d kBytes\n",
1327 TSIZE(QIC_24_TSIZE)/1024);
1328 error("\t-qic120\t\tset tape volume size to %d kBytes\n",
1329 TSIZE(QIC_120_TSIZE)/1024);
1330 error("\t-qic150\t\tset tape volume size to %d kBytes\n",
1331 TSIZE(QIC_150_TSIZE)/1024);
1332 error("\t-qic250\t\tset tape volume size to %d kBytes\n",
1333 TSIZE(QIC_250_TSIZE)/1024);
1334 error("\t-qic525\t\tset tape volume size to %d kBytes\n",
1335 TSIZE(QIC_525_TSIZE)/1024);
1336 error("\t-no-fsync\tdo not call fsync() for each extracted file (may be dangerous)\n");
1337 error("\t-nowarn\t\tdo not print warning messages\n");
1338 error("\t-time\t\tprint timing info\n");
1339 error("\t-no-statistics\tdo not print statistics\n");
1340 error("\t-cpio-statistics\tprint cpio style statistics\n");
1341 #ifdef FIFO
1342 error("\t-fifostats\tprint fifo statistics\n");
1343 #endif
1344 error("\t-numeric\tdon't use user/group name from tape\n");
1345 error("\t-newest\t\tfind newest file on tape\n");
1346 error("\t-newest-file\tfind newest regular file on tape\n");
1347 error("\t-hpdev\t\tuse HP's non POSIX compliant method to store dev numbers\n");
1348 error("\t-modebits\tinclude all 16 bits from stat.st_mode, this violates POSIX-1003.1\n");
1349 error("\t-copylinks\tCopy hard and symlinks rather than linking\n");
1350 error("\t-copyhardlinks\tCopy hardlink source files rather than linking\n");
1351 error("\t-copysymlinks\tCopy symlink source files rather than linking\n");
1352 error("\t-copydlinks\tCopy the content of linked dirs\n");
1353 error("\t-hardlinks\tExtract symlinks as hardlinks\n");
1354 error("\t-link-data\tInclude data for hard linked files\n");
1355 error("\t-symlinks\tExtract hardlinks as symlinks\n");
1356 error("\t-signed-checksum\tuse signed chars to calculate checksum\n");
1357 error("\trmt=path\tSpecify remote path to remote tape server program\n");
1358 error("\trsh=path\tSpecify path to remote login program\n");
1359 error("\t-sparse\t\thandle file with holes effectively on store/create\n");
1360 error("\t-force-hole\ttry to extract all files with holes\n");
1361 error("\t-to-stdout\textract files to stdout\n");
1362 error("\t-wready\t\twait for tape drive to become ready\n");
1363 error("\t-force-remove\tforce to remove non writable files on extraction\n");
1364 error("\t-ask-remove\task to remove non writable files on extraction\n");
1365 error("\t-remove-first\tremove files before extraction\n");
1366 error("\t-remove-recursive\tremove files recursive\n");
1367 error("\t-keep-nonempty-dirs\tdo not complain about non-empty dirs\n");
1368 error("\t-install\tcarefully replace old files with -x, similar to install(1)\n");
1369 error("\tdir-owner=user\tIntermediate created directories will be owned by 'user'.\n");
1370 error("\tdir-group=user\tIntermediate created directories will be owned by 'group'.\n");
1371 error("\tumask=mask\tSet star's umask to 'mask'.\n");
1372 error("\t-onull,-nullout\tsimulate creating an achive to compute the size\n");
1373 exit(ret);
1374 /* NOTREACHED */
1375 }
1376 #endif /* NO_STAR_MAIN */
1377
1378 LOCAL void
dusage(ret)1379 dusage(ret)
1380 int ret;
1381 {
1382 error("Diff options:\n");
1383 error("\tnot\t\tif this option is present, exclude listed options\n");
1384 error("\t!\t\tif this option is present, exclude listed options\n");
1385 error("\tall\t\tcompare everything\n");
1386 error("\tperm\t\tcompare file permissions\n");
1387 error("\tmode\t\tcompare file permissions\n");
1388 error("\tsymperm\t\tcompare symlink permissions\n");
1389 error("\ttype\t\tcompare file type\n");
1390 error("\tnlink\t\tcompare all linkcounts (star dump mode only)\n");
1391 error("\tdnlink\t\tcompare directory linkcounts (star dump mode only)\n");
1392 error("\tuid\t\tcompare owner of file\n");
1393 error("\tgid\t\tcompare group of file\n");
1394 error("\tuname\t\tcompare name of owner of file\n");
1395 error("\tgname\t\tcompare name of group of file\n");
1396 error("\tid\t\tcompare owner, group, ownername and groupname of file\n");
1397 error("\tsize\t\tcompare file size\n");
1398 error("\tdata\t\tcompare content of file\n");
1399 error("\tcont\t\tcompare content of file\n");
1400 error("\trdev\t\tcompare rdev of device node\n");
1401 error("\thardlink\tcompare target of hardlink\n");
1402 error("\tsymlink\t\tcompare target of symlink\n");
1403 error("\tsympath\t\tcompare target pathname of symlink\n");
1404 error("\tsparse\t\tcompare if both files are sparse or not\n");
1405 error("\tatime\t\tcompare access time of file (only star)\n");
1406 error("\tmtime\t\tcompare modification time of file\n");
1407 error("\tctime\t\tcompare creation time of file (only star)\n");
1408 error("\ttimes\t\tcompare all times of file\n");
1409 error("\tlmtime\t\tcompare modification time of symlinks\n");
1410 error("\txtimes\t\tcompare all times and lmtime\n");
1411 error("\tnsecs\t\tcompare nanoseconds in times\n");
1412 error("\tdir\t\tcompare directory content (star dump mode only)\n");
1413 #ifdef USE_ACL
1414 error("\tacl\t\tcompare access control lists (specify -acl also)\n");
1415 #endif
1416 #ifdef USE_XATTR
1417 error("\txattr\t\tcompare extended attributes (specify -xattr also)\n");
1418 #endif
1419 #ifdef USE_FFLAGS
1420 error("\tfflags\t\tcompare extended file flags (specify -xfflags also)\n");
1421 #endif
1422 error("\n");
1423 error("Default is to compare everything except atime.\n");
1424 exit(ret);
1425 /* NOTREACHED */
1426 }
1427
1428 LOCAL void
husage(ret)1429 husage(ret)
1430 int ret;
1431 {
1432 error("Header types (default marked with '*'):\n");
1433 hdr_usage();
1434 exit(ret);
1435 /* NOTREACHED */
1436 }
1437
1438 #ifndef NO_STAR_MAIN
1439 LOCAL void
gargs(ac,av)1440 gargs(ac, av)
1441 int ac;
1442 char *const *av;
1443 {
1444 int files = 0;
1445 int minfiles = 1;
1446 BOOL help = FALSE;
1447 BOOL xhelp = FALSE;
1448 BOOL prvers = FALSE;
1449 BOOL xcopy = FALSE;
1450 BOOL oldtar = FALSE;
1451 BOOL no_fifo = FALSE;
1452 BOOL usetape = FALSE;
1453 BOOL dodesc = FALSE;
1454 BOOL qic24 = FALSE;
1455 BOOL qic120 = FALSE;
1456 BOOL qic150 = FALSE;
1457 BOOL qic250 = FALSE;
1458 BOOL qic525 = FALSE;
1459 BOOL dchangeflag = FALSE;
1460 char *pkglistfile = NULL;
1461 char *diruid = NULL;
1462 char *dirgid = NULL;
1463 char *u_mask = NULL;
1464 char *paxopts = NULL;
1465 const char *p;
1466 Llong llbs = 0;
1467 signed char archive = -1; /* On IRIX, we have unsigned chars by default */
1468 BOOL Ointeractive = FALSE;
1469
1470 /* BEGIN CSTYLED */
1471 /*char _opts[] = "C*,find~,help,xhelp,version,debug,xdebug#,xd#,bsdchdir,pax-ls,level#,tardumps*,wtardumps,time,no_statistics,no-statistics,cpio-statistics,fifostats,numeric,v+,block-number,tpath,c,u,r,x,t,copy,xcopy,n,diff,diffopts&,H&,artype&,print-artype,fs-name*,force_hole,force-hole,sparse,to_stdout,to-stdout,wready,force_remove,force-remove,ask_remove,ask-remove,remove_first,remove-first,remove_recursive,remove-recursive,keep-nonempty-dirs,install,nullout,onull,fifo,no_fifo,no-fifo,shm,fs&,VOLHDR*,list*,pkglist*,multivol,new-volume-script*,force-local,restore,partial,force-restore,freeze,file&,f&,T,Z,z,bz,j,lzo,7z,xz,lzip,zstd,lzma,compress-program*,rmt*,rsh*,bs&,blocks&,b&,B,pattern&,pat&,one-file,iskip&,mtskip&,i,d,m,o,nochown,pax-o*,pax-p&,a,atime,p,no-p,dirmode,l,h,L,pax-L~,pax-H~,pax-P~,D,dodesc,M,xdev,w,pax-i,I,X&,exclude-from&,O,signed_checksum,signed-checksum,P,S,F+,U,uncond-rename,xdir,xdot,k,keep_old_files,keep-old-files,refresh_old_files,refresh-old-files,refresh,/,..,secure-links,no-secure-links%0,no-dirslash,not,V,match-tree,pax-match,pax-n,pax-c,notarg,maxsize&,newer*,ctime,nodump,tsize&,qic24,qic120,qic150,qic250,qic525,nowarn,newest_file,newest-file,newest,hpdev,modebits,copylinks,copyhardlinks,copysymlinks,copydlinks,hardlinks,symlinks,link-data,acl,xattr,xattr-linux,xfflags,link-dirs,dumpdate*,dump,dump\\+%2,cumulative,dump-cumulative,meta,dumpmeta,xmeta,silent,lowmem,no-xheader,no-fsync%1,do-fsync%0,read0,errctl&,e,data-change-warn,prinodes,dir-owner*,dir-group*,umask*,s&,pax-s&,?";*/
1472 /* END CSTYLED */
1473
1474 getarginit(&gaprops, GAF_DEFAULT); /* Set default behavior */
1475 #ifdef STAR_FAT
1476 switch (ptype) {
1477
1478 case P_SUNTAR:
1479 suntar_gargs(ac, av);
1480 return;
1481 case P_GNUTAR:
1482 gnutar_gargs(ac, av);
1483 return;
1484 case P_PAX:
1485 pax_gargs(ac, av);
1486 return;
1487 case P_CPIO:
1488 cpio_gargs(ac, av);
1489 return;
1490 }
1491 #endif
1492
1493 p = filename(av[0]);
1494 if (streql(p, "ustar")) {
1495 /*
1496 * If we are called as "ustar" we are as POSIX-1003.1-1988
1497 * compliant as possible. There are no enhancements at all.
1498 */
1499 hdrtype = H_USTAR;
1500 } else if (streql(p, "tar")) {
1501 /*
1502 * If we are called as "tar" we are mostly POSIX compliant
1503 * and use POSIX-1003.1-2001 extensions. The differences of the
1504 * base format compared to POSIX-1003.1-1988 can only be
1505 * regocnised by star. Even the checsum bug of the "pax"
1506 * reference implementation is not hit by the fingerprint
1507 * used to allow star to discriminate XUSTAR from USTAR.
1508 */
1509 hdrtype = H_XUSTAR;
1510 }
1511 /*
1512 * Current default archive format in all other cases is XSTAR (see
1513 * above). This will not change until 2004 (then the new XUSTAR format
1514 * is recognised by star for at least 5 years and we may asume that
1515 * all star installations will properly handle it.
1516 * XSTAR is USTAR with extensions similar to GNU tar.
1517 */
1518
1519 iftype = I_TAR; /* command line interface */
1520 ptype = P_STAR; /* program interface type */
1521
1522 if (pname) { /* cli=xxx seen as argv[1] */
1523 --ac, av++;
1524 }
1525 --ac, ++av;
1526 files = getfilecount(ac, av, opts);
1527 if (getlallargs(&ac, &av, &gaprops, opts,
1528 &dir_flags,
1529 getfind, NULL,
1530 &help, &xhelp, &prvers, &debug, &xdebug, &xdebug,
1531 &bsdchdir, &paxls,
1532 &dumplevel, &dumpdates, &wtardumps,
1533 &showtime, &no_stats, &no_stats, &cpio_stats,
1534 &do_fifostats,
1535 &numeric, &verbose, &prblockno, &tpath,
1536 #ifndef __old__lint
1537 &cflag,
1538 &uflag,
1539 &rflag,
1540 &xflag,
1541 &tflag,
1542 ©flag, &xcopy,
1543 &nflag,
1544 &diff_flag, add_diffopt, &diffopts,
1545 gethdr, &chdrtype, gethdr, &chdrtype,
1546 &print_artype,
1547 &fs_name,
1548 &force_hole, &force_hole, &sparse, &to_stdout, &to_stdout, &wready,
1549 &force_remove, &force_remove, &ask_remove, &ask_remove,
1550 &remove_first, &remove_first, &remove_recursive, &remove_recursive,
1551 &keep_nonempty_dirs, &do_install,
1552 &nullout, &nullout,
1553 &use_fifo, &no_fifo, &no_fifo, &shmflag,
1554 getenum, &fs,
1555 &volhdr,
1556 &listfile, &pkglistfile,
1557 &multivol, &newvol_script,
1558 &force_noremote,
1559 &dorestore, &dopartial, &forcerestore,
1560 &freezeflag,
1561 /*
1562 * All options starting with -f need to appear
1563 * before this line.
1564 */
1565 addtarfile, NULL,
1566 addtarfile, NULL,
1567 &usetape,
1568 &Zflag, &zflag, &bzflag, &bzflag, &lzoflag,
1569 &p7zflag, &xzflag, &lzipflag, &zstdflag, &lzmaflag,
1570 &compress_prg,
1571 &rmt, &rsh,
1572 getenum, &bs,
1573 getbnum, &llbs,
1574 getbnum, &llbs,
1575 &multblk,
1576 addpattern, NULL,
1577 addpattern, NULL,
1578 &one_file,
1579 getenum, &iskip,
1580 getllnum, &mtskip,
1581 &ignoreerr,
1582 &nodir,
1583 &nomtime, &nochown, &nochown,
1584 &paxopts,
1585 getpaxpriv, NULL,
1586 &acctime, &acctime,
1587 &pflag, &nopflag, &dirmode,
1588 &nolinkerr,
1589 &follow, &follow,
1590 #ifdef USE_FIND
1591 getpaxL, &walkflags,
1592 getpaxH, &walkflags,
1593 getpaxP, &walkflags,
1594 #else
1595 getpaxL, NULL,
1596 getpaxH, NULL,
1597 getpaxP, NULL,
1598 #endif
1599 &nodesc,
1600 &dodesc,
1601 &nomount, &nomount,
1602 &interactive, &paxinteract,
1603 &Ointeractive,
1604 getexclude, NULL,
1605 getexclude, NULL,
1606 &oldtar, &signedcksum, &signedcksum,
1607 &partial,
1608 &nospec, &Fflag,
1609 &uncond, &uncond_rename,
1610 &xdir, &xdot,
1611 &keep_old, &keep_old, &keep_old,
1612 &refresh_old, &refresh_old, &refresh_old,
1613 &abs_path, &allow_dotdot,
1614 &secure_links, &secure_links,
1615 &no_dirslash,
1616 ¬pat, ¬pat, &match_tree,
1617 &paxmatch, &paxnflag, ¬arg, ¬arg,
1618 getknum, &maxsize,
1619 &stampfile,
1620 &Ctime,
1621 &nodump,
1622 getbnum, &tsize,
1623 &qic24,
1624 &qic120,
1625 &qic150,
1626 &qic250,
1627 &qic525,
1628 &nowarn,
1629 #endif /* __old__lint */
1630 &listnewf, &listnewf,
1631 &listnew,
1632 &hpdev, &modebits,
1633 ©links, ©hardlinks, ©symlinks,
1634 ©dlinks,
1635 &hardlinks, &symlinks, &linkdata,
1636 &doacl, &doxattr, &dolxattr, &dofflags,
1637 &link_dirs,
1638 &dd_name,
1639 &dodump, &dodump,
1640 &dump_cumulative, &dump_cumulative,
1641 &dometa, &dumpmeta, &xmeta,
1642 &silent, &lowmem, &no_xheader,
1643 &no_fsync, &no_fsync,
1644 &readnull,
1645 errconfig, NULL,
1646 &errflag, &dchangeflag,
1647 &prinodes,
1648 &diruid, &dirgid, &u_mask,
1649 parsesubst, &do_subst,
1650 paxpsubst, &do_subst,
1651 &archive) < 0) {
1652 errmsgno(EX_BAD, "Bad Option: %s.\n", av[0]);
1653 susage(EX_BAD);
1654 }
1655
1656 if (archive != -1 && !(archive >= '0' && archive <= '7')) {
1657 errmsgno(EX_BAD, "Bad Option: -%c.\n", archive);
1658 susage(EX_BAD);
1659 }
1660 star_helpvers("star", help, xhelp, prvers);
1661
1662 if (Ointeractive) {
1663 comerrno(EX_BAD, "Option -I is obsolete and will get a different meaning in next release, use -w instead.\n");
1664 }
1665 if (xcopy) {
1666 copyflag = TRUE;
1667 sparse = TRUE;
1668 doacl = TRUE;
1669 xdot = TRUE;
1670 }
1671 if (tsize == 0) {
1672 if (qic24) tsize = QIC_24_TSIZE;
1673 if (qic120) tsize = QIC_120_TSIZE;
1674 if (qic150) tsize = QIC_150_TSIZE;
1675 if (qic250) tsize = QIC_250_TSIZE;
1676 if (qic525) tsize = QIC_525_TSIZE;
1677 }
1678 if (pkglistfile != NULL) {
1679 listfile = pkglistfile;
1680 pkglist = TRUE;
1681 }
1682 if (u_mask) {
1683 long l;
1684
1685 if (*astolb(u_mask, &l, 8))
1686 comerrno(EX_BAD, "Bad umask '%s'.\n", u_mask);
1687 umask((mode_t)l);
1688 }
1689 if (diruid) {
1690 Llong ll;
1691 uid_t uid;
1692
1693 if (!ic_uidname(diruid, strlen(diruid), &uid)) {
1694 if (*astollb(diruid, &ll, 10))
1695 comerrno(EX_BAD, "Bad uid '%s'.\n", diruid);
1696 dir_uid = ll;
1697 } else {
1698 dir_uid = uid;
1699 }
1700 }
1701 if (dirgid) {
1702 Llong ll;
1703 gid_t gid;
1704
1705 if (!ic_gidname(dirgid, strlen(dirgid), &gid)) {
1706 if (*astollb(dirgid, &ll, 10))
1707 comerrno(EX_BAD, "Bad gid '%s'.\n", diruid);
1708 dir_gid = ll;
1709 } else {
1710 dir_gid = gid;
1711 }
1712 }
1713
1714 if (dchangeflag)
1715 errconfig("WARN|GROW|SHRINK *");
1716
1717 star_checkopts(oldtar, dodesc, usetape, archive, no_fifo,
1718 paxopts, llbs);
1719 #ifdef USE_FIND
1720 if (dofind && find_ac > 0) {
1721 int cac = find_ac;
1722 char *const * cav = find_av;
1723 finda_t fa;
1724
1725 if (copyflag)
1726 cac--;
1727 find_firstprim(&cac, &cav);
1728 find_pac = cac;
1729 find_pav = cav;
1730 files = find_ac - cac;
1731 if (!copyflag && !cflag && files > 0)
1732 comerrno(EX_BAD, "Path arguments not yet supported in extract mode.\n");
1733
1734 if (cac > 0) {
1735 BOOL did_stdout = FALSE;
1736 int i;
1737
1738 now = time(0);
1739 now = now +60;
1740 find_argsinit(&fa);
1741 fa.walkflags = walkflags;
1742 fa.Argc = cac;
1743 fa.Argv = (char **)cav;
1744 find_node = find_parse(&fa);
1745 if (fa.primtype == FIND_ERRARG)
1746 comexit(fa.error);
1747 if (fa.primtype != FIND_ENDARGS)
1748 comerrno(EX_BAD, "Incomplete expression.\n");
1749 plusp = fa.plusp;
1750 find_patlen = fa.patlen;
1751 walkflags = fa.walkflags;
1752 maxdepth = fa.maxdepth;
1753 mindepth = fa.mindepth;
1754
1755 for (i = 0; i < ntarfiles; i++) {
1756 if (tarfiles[i][0] == '-' && tarfiles[i][1] == '\0')
1757 did_stdout = TRUE;
1758 }
1759 if (ntarfiles == 1 && nullout)
1760 did_stdout = FALSE;
1761
1762 if (find_node && (did_stdin || did_stdout)) {
1763 if (find_pname(find_node, "-exec") ||
1764 find_pname(find_node, "-execdir") ||
1765 find_pname(find_node, "-exec+") ||
1766 find_pname(find_node, "-execdir+") ||
1767 find_pname(find_node, "-ok") ||
1768 find_pname(find_node, "-okdir"))
1769 comerrno(EX_BAD,
1770 "Cannot -exec with f=-.\n");
1771 if (cflag && did_stdout &&
1772 (find_pname(find_node, "-print") ||
1773 find_pname(find_node, "-print0") ||
1774 find_pname(find_node, "-printnnl") ||
1775 find_pname(find_node, "-ls")))
1776 comerrno(EX_BAD,
1777 "Cannot -print/-ls with f=-.\n");
1778 }
1779 }
1780 }
1781 #endif
1782 star_nfiles(files, minfiles);
1783 }
1784 #endif /* NO_STAR_MAIN */
1785
1786 LOCAL void
star_mkvers()1787 star_mkvers()
1788 {
1789 char buf[512];
1790 extern char strvers[];
1791 extern char dvers[];
1792
1793 if (vers != NULL)
1794 return;
1795
1796 js_snprintf(buf, sizeof (buf),
1797 "%s %s (%s-%s-%s) %s", "star", strvers,
1798 HOST_CPU, HOST_VENDOR, HOST_OS,
1799 dvers);
1800
1801 vers = ___savestr(buf);
1802 }
1803
1804 LOCAL void
star_helpvers(name,help,xhelp,prvers)1805 star_helpvers(name, help, xhelp, prvers)
1806 char *name;
1807 BOOL help;
1808 BOOL xhelp;
1809 BOOL prvers;
1810 {
1811 if (help)
1812 usage(0);
1813 if (xhelp)
1814 xusage(0);
1815 star_mkvers();
1816 if (prvers) {
1817 printf("%s: %s\n\n", name, vers);
1818 gtprintf("Options:");
1819 #ifdef USE_ACL
1820 opt_acl();
1821 #endif
1822 #ifdef USE_FIND
1823 printf(" find");
1824 #endif
1825 #ifdef USE_FFLAGS
1826 opt_fflags();
1827 #endif
1828 #ifdef USE_REMOTE
1829 opt_remote();
1830 #endif
1831 #ifdef USE_XATTR
1832 opt_xattr();
1833 #endif
1834 #ifdef USE_SELINUX
1835 opt_selinux();
1836 #endif
1837 gtprintf("\n\n");
1838 gtprintf("Copyright (C) 1985, 88-90, 92-96, 98, 99, 2000-2021 %s\n", _("J�rg Schilling"));
1839 gtprintf("This is free software; see the source for copying conditions. There is NO\n");
1840 gtprintf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
1841 exit(0);
1842 }
1843 }
1844
1845 LOCAL void
star_checkopts(oldtar,dodesc,usetape,archive,no_fifo,paxopts,llbs)1846 star_checkopts(oldtar, dodesc, usetape, archive, no_fifo, paxopts, llbs)
1847 BOOL oldtar; /* -O oldtar option */
1848 BOOL dodesc; /* -dodesc descend dirs from listfile */
1849 BOOL usetape; /* -T usetape option */
1850 int archive; /* -0 .. -9 archive option */
1851 BOOL no_fifo; /* -no-fifo option */
1852 const char * paxopts; /* -pax-o / -o option */
1853 Llong llbs; /* blocks= option */
1854 {
1855 int n;
1856
1857 if (print_artype) {
1858 tflag = TRUE;
1859 no_fifo = TRUE;
1860 }
1861 if ((n = xflag + cflag + uflag + rflag + tflag + copyflag + nflag + diff_flag) > 1) {
1862 if ((n == 2) && copyflag && (tflag || diff_flag)) {
1863 /*
1864 * This is OK: star -copy -t or star -copy -diff
1865 */
1866 /* EMPTY */
1867 } else if ((n == 2) && cflag && (tflag || diff_flag)) {
1868 copyflag = TRUE;
1869 cflag = FALSE;
1870 } else {
1871 errmsgno(EX_BAD,
1872 "Too many commands, only one of -x -c -u -r -t -copy -n or -diff is allowed.\n");
1873 susage(EX_BAD);
1874 }
1875 }
1876 if (!(xflag | cflag | uflag | rflag | tflag | copyflag | nflag | diff_flag)) {
1877 errmsgno(EX_BAD, "Missing command, must specify -x -c -u -r -t -copy -n or -diff.\n");
1878 susage(EX_BAD);
1879 }
1880 if (uflag || rflag) {
1881 cflag = TRUE;
1882 no_fifo = TRUE; /* Until we are able to reverse the FIFO */
1883 dump_partial = TRUE;
1884 }
1885 if (nullout && !cflag) {
1886 errmsgno(EX_BAD, "-nullout only makes sense in create mode.\n");
1887 susage(EX_BAD);
1888 }
1889 if (no_fifo || nullout)
1890 use_fifo = FALSE;
1891 #ifndef FIFO
1892 if (use_fifo) {
1893 errmsgno(EX_BAD, "Fifo not configured in.\n");
1894 susage(EX_BAD);
1895 }
1896 #endif
1897
1898 if (ptype == P_SUNTAR)
1899 nolinkerr ^= tcompat;
1900
1901 noxdir = nodir;
1902 if (xdir) /* Extract all dirs uncond */
1903 xdot = FALSE;
1904
1905 if (copylinks) {
1906 copyhardlinks = TRUE;
1907 copysymlinks = TRUE;
1908 }
1909 if (copyflag) {
1910 hdrtype = chdrtype = H_EXUSTAR;
1911 dodump = TRUE;
1912 partial = TRUE; /* Important as we fiddle with FIFO obs */
1913 binflag = TRUE;
1914 nodir = FALSE;
1915 multivol = FALSE;
1916 linkdata = FALSE;
1917 if (secure_links < 0)
1918 secure_links = FALSE;
1919
1920 if (!tflag && !diff_flag)
1921 xflag = TRUE;
1922
1923 if (!use_fifo) {
1924 errmsgno(EX_BAD, "Need fifo for -copy mode.\n");
1925 susage(EX_BAD);
1926 }
1927 }
1928 if (cflag && linkdata && sparse)
1929 linkdata = FALSE; /* XXX Cannot yet do sparse datalinks */
1930
1931 if (dumplevel >= 0) {
1932 /*
1933 * This is an articicial limitation, our code supports an
1934 * unlimited number of dump levels.
1935 */
1936 if (dumplevel > 99)
1937 comerrno(EX_BAD, "Illegal dump level, use 0..99\n");
1938 dodump = TRUE;
1939 if (!nomount)
1940 comerrno(EX_BAD, "A dump needs the -M/-xdev option.\n");
1941 }
1942 if (dodump) {
1943 chdrtype = H_EXUSTAR;
1944 if (lowmem)
1945 comerrno(EX_BAD, "Dump mode does not work with -lowmem.\n");
1946 }
1947 if (dump_cumulative) {
1948 if (dumplevel < 0)
1949 comerrno(EX_BAD, "With -cumulative, level= is needed.\n");
1950 }
1951 if (maxsize > 0 || Fflag > 0 || nospec || nodump)
1952 dump_partial = TRUE;
1953
1954 if (dopartial)
1955 dorestore = TRUE;
1956 if (forcerestore)
1957 dorestore = TRUE;
1958 if (dorestore) {
1959 xdir = TRUE;
1960 if (secure_links < 0)
1961 secure_links = FALSE;
1962 if (!uncond)
1963 comerrno(EX_BAD, "A restore needs the -U option.\n");
1964 if (do_install)
1965 comerrno(EX_BAD, "-install not allowed in restore mode.\n");
1966 }
1967 if (oldtar)
1968 chdrtype = H_OTAR;
1969 if (chdrtype != H_UNDEF) {
1970 if (H_TYPE(chdrtype) == H_OTAR)
1971 oldtar = TRUE; /* XXX hack */
1972 }
1973 /*
1974 * We do not set chdrtype here in case it is H_UNDEF and -r or -u have
1975 * been specified.
1976 */
1977 if (cflag && (!(rflag || uflag) || chdrtype != H_UNDEF)) {
1978 if (chdrtype != H_UNDEF)
1979 hdrtype = chdrtype;
1980 chdrtype = hdrtype; /* wegen setprops(chdrtype) in main() */
1981
1982 /*
1983 * hdrtype und chdrtype
1984 * bei uflag, rflag sowie xflag, tflag, nflag, diff_flag
1985 * in get_tcb vergleichen !
1986 */
1987 }
1988 if (no_dirslash && chdrtype == H_OTAR) {
1989 errmsgno(EX_BAD, "-no-dirslash cannot be used with the old tar format\n");
1990 susage(EX_BAD);
1991 }
1992 if (diff_flag) {
1993 if (diffopts == 0)
1994 diffopts = D_DEFLT;
1995 if ((diffopts & D_ATIME) == 0)
1996 diffopts &= ~D_ANTIME;
1997 if ((diffopts & D_MTIME) == 0)
1998 diffopts &= ~D_MNTIME;
1999 if ((diffopts & D_CTIME) == 0)
2000 diffopts &= ~D_CNTIME;
2001 } else if (diffopts != 0) {
2002 errmsgno(EX_BAD, "diffopts= only makes sense with -diff\n");
2003 susage(EX_BAD);
2004 }
2005 if (fs == 0L) {
2006 char *ep = getenv("STAR_FIFOSIZE");
2007
2008 if (ep) {
2009 if (getnum(ep, &fs) != 1) {
2010 comerrno(EX_BAD,
2011 "Bad fifo size environment '%s'.\n",
2012 ep);
2013 }
2014 }
2015 }
2016 if (llbs != 0 && bs != 0) {
2017 errmsgno(EX_BAD, "Only one of blocks= b= bs=.\n");
2018 susage(EX_BAD);
2019 }
2020 if (llbs != 0) {
2021 bs = (long)llbs;
2022 if (bs != llbs) {
2023 errmsgno(EX_BAD, "Blocksize used with blocks= or b= too large.\n");
2024 susage(EX_BAD);
2025 }
2026 }
2027 if (bs % TBLOCK) {
2028 errmsgno(EX_BAD, "Invalid block size %ld.\n", bs);
2029 susage(EX_BAD);
2030 }
2031 if (bs)
2032 nblocks = bs / TBLOCK;
2033 if ((nblocks <= 0) ||
2034 ((rflag || uflag) && nblocks < 2)) {
2035 errmsgno(EX_BAD, "Invalid block size %d blocks.\n", nblocks);
2036 susage(EX_BAD);
2037 }
2038 bs = nblocks * TBLOCK;
2039 if (debug) {
2040 errmsgno(EX_BAD, "Block size %d blocks (%ld bytes).\n", nblocks, bs);
2041 }
2042 if (mtskip)
2043 iskip = 0;
2044 if (iskip && iskip >= bs) {
2045 errmsgno(EX_BAD, "Invalid skip size %ld bytes.\n", iskip);
2046 susage(EX_BAD);
2047 }
2048 if (tsize > 0) {
2049 if (tsize % TBLOCK) {
2050 errmsgno(EX_BAD, "Invalid tape size %llu.\n", tsize);
2051 susage(EX_BAD);
2052 }
2053 tsize /= TBLOCK;
2054 }
2055
2056 if (pkglist) {
2057 dodesc = FALSE;
2058 readnull = FALSE;
2059 if (!cflag)
2060 comerrno(EX_BAD, "pkglist= option only works in create mode.\n");
2061 }
2062 if (listfile != NULL)
2063 dump_partial = TRUE;
2064
2065 if (listfile != NULL && !dodesc)
2066 nodesc = TRUE;
2067 if (oldtar)
2068 nospec = TRUE;
2069 if (!tarfiles[0]) {
2070 if (usetape) {
2071 tarfiles[0] = getenv("TAPE");
2072 }
2073 if ((usetape || archive > 0) &&
2074 !tarfiles[0]) {
2075 static char arname[] = "archive0=";
2076 Ullong otsize = tsize;
2077 char *dfltfile = NULL;
2078
2079 #ifdef DFLT_FILE
2080 #define DFILE DFLT_FILE
2081 #else
2082 #define DFILE NULL
2083 #endif
2084 /*
2085 * If we got a digit option, check for an 'archive#='
2086 * entry in /etc/default/[s!]tar. If there was no -f
2087 * or digit option, look for 'archive0='.
2088 */
2089 if (archive < '0' || archive > '9')
2090 archive = '0';
2091 arname[7] = (char)archive;
2092 if (ptype == P_SUNTAR)
2093 dfltfile = DFILE;
2094 if (!star_darchive(arname, dfltfile)) {
2095 errmsgno(EX_BAD,
2096 "Archive entry %c not found in %s. %s",
2097 archive,
2098 get_stardefaults(DFILE),
2099 "Using stdin/stdout as archive.\n");
2100 tarfiles[0] = NULL;
2101 tsize = otsize;
2102 }
2103 }
2104 if (!tarfiles[0])
2105 tarfiles[0] = "-";
2106 ntarfiles++;
2107 }
2108 if (!cflag && !copyflag) {
2109 for (n = 0; n < ntarfiles; n++) {
2110 if (tarfiles[n][0] == '-' && tarfiles[n][1] == '\0')
2111 check_stdin("-f");
2112 }
2113 }
2114 if (tsize % nblocks) {
2115 /*
2116 * Silently round down to a multiple of the tape block size.
2117 */
2118 tsize /= nblocks;
2119 tsize *= nblocks;
2120 }
2121 /*
2122 * XXX This must be rethought with files split by multi volume and
2123 * XXX with with volume headers and continuation headers.
2124 */
2125 if (tsize > 0 && tsize < 3) {
2126 errmsgno(EX_BAD, "Tape size must be at least 3 blocks.\n");
2127 susage(EX_BAD);
2128 }
2129 /*
2130 * XXX This is a place that should be checked every time, when
2131 * XXX possible interactivity is modified.
2132 */
2133 if (interactive || ask_remove ||
2134 ((multivol || tsize > 0) && !newvol_script)) {
2135 #ifdef JOS
2136 tty = stderr;
2137 #else
2138 #ifdef HAVE__DEV_TTY
2139 if ((tty = lfilemopen("/dev/tty", "r", S_IRWALL)) == (FILE *)NULL)
2140 comerr("Cannot open '/dev/tty'.\n");
2141 #else
2142 tty = stderr;
2143 #endif
2144 #endif
2145 }
2146 if (nflag) {
2147 xflag = TRUE;
2148 interactive = TRUE;
2149 if (verbose == 0 && !tpath)
2150 verbose = 1;
2151 }
2152 if (to_stdout) {
2153 force_hole = FALSE;
2154 }
2155 if (keep_old && refresh_old) {
2156 errmsgno(EX_BAD, "Cannot use -keep-old-files and -refresh-old-files together.\n");
2157 susage(EX_BAD);
2158 }
2159 if ((copylinks + hardlinks + symlinks) > 1) {
2160 errmsgno(EX_BAD, "Only one of -copylinks -hardlinks -symlinks.\n");
2161 susage(EX_BAD);
2162 }
2163
2164 if (my_uid == 0 && !nopflag)
2165 pflag = TRUE;
2166
2167 /*
2168 * -acl includes -p
2169 */
2170 if (doacl)
2171 pflag = TRUE;
2172
2173 if (doxattr) {
2174 #ifndef O_XATTR
2175 errmsgno(EX_BAD,
2176 "This platform does not support NFSv4 extended attribute files.\n");
2177 comerrno(EX_BAD,
2178 "-xattr is reserved for NFSv4 extended attributes, for Linux use -xattr-linux\n");
2179 #else
2180 /*
2181 * XXX: see getpaxpriv() "pax -pe": doxattr commented out.
2182 */
2183 comerrno(EX_BAD,
2184 "NFSv4 extended attribute files are not yet supported.\n");
2185 #endif
2186 }
2187
2188 if (paxopts) {
2189 if (!ppaxopts(paxopts)) {
2190 errmsgno(EX_BAD, "Unsupported option '%s' for %s.\n",
2191 paxopts,
2192 iftype == I_PAX ? "-o" : "-pax-o");
2193 susage(EX_BAD);
2194 }
2195 }
2196
2197 star_defaults(&fs, &no_fsync, &secure_links, NULL);
2198 if (no_fsync < 0)
2199 no_fsync = FALSE;
2200 if (secure_links < 0)
2201 secure_links = TRUE;
2202 }
2203
2204 EXPORT void
star_verifyopts()2205 star_verifyopts()
2206 {
2207 if (cflag && (props.pr_flags & PR_LINK_DATA) == 0)
2208 linkdata = FALSE;
2209 if (cflag && multivol && (props.pr_flags & PR_MULTIVOL) == 0) {
2210 errmsgno(EX_BAD,
2211 "Multi volume archives are not supported with %s format.\n",
2212 hdr_name(chdrtype));
2213 susage(EX_BAD);
2214 }
2215 if (cflag && doacl) {
2216 /*
2217 * Check properties for archive format.
2218 */
2219 if ((props.pr_xhmask & (XF_ACL_ACCESS|XF_ACL_DEFAULT|XF_ACL_ACE)) == 0) {
2220 errmsgno(EX_BAD,
2221 "Archive format '%s' does not support -acl.\n",
2222 hdr_name(chdrtype));
2223 susage(EX_BAD);
2224 }
2225 }
2226 }
2227
2228 LOCAL void
star_nfiles(files,minfiles)2229 star_nfiles(files, minfiles)
2230 int files;
2231 int minfiles;
2232 {
2233 if (cflag || copyflag) {
2234 if (copyflag && !tflag)
2235 minfiles++;
2236 if (listfile)
2237 minfiles--;
2238 if (files < minfiles) {
2239 errmsgno(EX_BAD, "Too few arguments; will not create an empty archive.\n");
2240 susage(EX_BAD);
2241 }
2242 }
2243 }
2244
2245 /* ARGSUSED */
2246 LOCAL int
getpaxH(arg,valp,pac,pav)2247 getpaxH(arg, valp, pac, pav)
2248 char *arg;
2249 long *valp;
2250 int *pac;
2251 char *const **pav;
2252 {
2253 #ifdef GETARG_DEBUG
2254 error("paxH\n");
2255 #endif
2256 paxfollow = FALSE;
2257 paxHflag = TRUE;
2258 #ifdef USE_FIND
2259 *(int *)valp |= WALK_ARGFOLLOW;
2260 #endif
2261 return (1);
2262 }
2263
2264 /* ARGSUSED */
2265 LOCAL int
getpaxL(arg,valp,pac,pav)2266 getpaxL(arg, valp, pac, pav)
2267 char *arg;
2268 long *valp;
2269 int *pac;
2270 char *const **pav;
2271 {
2272 #ifdef GETARG_DEBUG
2273 error("paxL\n");
2274 #endif
2275 paxfollow = TRUE;
2276 paxHflag = FALSE;
2277 #ifdef USE_FIND
2278 *(int *)valp |= WALK_ALLFOLLOW;
2279 #endif
2280 return (1);
2281 }
2282
2283 /* ARGSUSED */
2284 LOCAL int
getpaxP(arg,valp,pac,pav)2285 getpaxP(arg, valp, pac, pav)
2286 char *arg;
2287 long *valp;
2288 int *pac;
2289 char *const **pav;
2290 {
2291 #ifdef GETARG_DEBUG
2292 error("paxP\n");
2293 #endif
2294 paxfollow = FALSE;
2295 paxHflag = FALSE;
2296 #ifdef USE_FIND
2297 *(int *)valp &= ~(WALK_ARGFOLLOW | WALK_ALLFOLLOW);
2298 #endif
2299 return (1);
2300 }
2301
2302 /* ARGSUSED */
2303 LOCAL int
getfind(arg,valp,pac,pav)2304 getfind(arg, valp, pac, pav)
2305 char *arg;
2306 long *valp; /* Not used until we introduce a ptr to opt struct */
2307 int *pac;
2308 char *const **pav;
2309 {
2310 #ifdef USE_FIND
2311 dofind = TRUE;
2312 find_ac = *pac;
2313 find_av = *pav;
2314 find_ac--, find_av++;
2315 return (NOARGS);
2316 #else
2317 return (BADFLAG);
2318 #endif
2319 }
2320
2321 /* ARGSUSED */
2322 LOCAL int
getpaxpriv(arg,valp)2323 getpaxpriv(arg, valp)
2324 char *arg;
2325 long *valp; /* Not used until we introduce a ptr to opt struct */
2326 {
2327 register char *p = arg;
2328 register char c;
2329
2330 while ((c = *p++) != '\0') {
2331 switch (c) {
2332
2333 case 'a': /* do not preserve access time */
2334 noatime = TRUE;
2335 break;
2336
2337 case 'e': /* preserve everything */
2338 pflag = TRUE;
2339 doacl = TRUE;
2340 #if 0
2341 /*
2342 * XXX: see doxattr check above.
2343 * XXX: We disable this to pass a solaris-ON compilation
2344 * XXX: "NFSv4 extended attribute files are not yet..."
2345 */
2346 doxattr = TRUE;
2347 #endif
2348 dolxattr = TRUE;
2349 dofflags = TRUE;
2350 noatime = FALSE;
2351 nomtime = FALSE;
2352 nochown = FALSE;
2353 break;
2354
2355 case 'm': /* do not preserve modification time */
2356 nomtime = TRUE;
2357 break;
2358
2359 case 'o': /* preserve userid/grupid & SUID/SGID */
2360 nochown = FALSE;
2361 break;
2362
2363 case 'p': /* preserve file mode bits (permissions) */
2364 pflag = TRUE;
2365 break;
2366
2367 default:
2368 errmsgno(EX_BAD,
2369 "Bad character '%c' in option '-p %s'.\n",
2370 c, arg);
2371 return (-1);
2372 }
2373 }
2374 return (1);
2375 }
2376
2377 LOCAL int
getlldefault(arg,valp,mult)2378 getlldefault(arg, valp, mult)
2379 char *arg;
2380 Llong *valp;
2381 int mult;
2382 {
2383 int ret = 1;
2384 int len = strlen(arg);
2385
2386 if (len > 0) {
2387 len = (Uchar)arg[len-1];
2388 if (!isdigit(len))
2389 mult = 1;
2390 }
2391 ret = getllnum(arg, valp);
2392 if (ret == 1)
2393 *valp *= mult;
2394 else
2395 errmsgno(EX_BAD, "Badly formed number '%s'.\n", arg);
2396 return (ret);
2397 }
2398
2399 EXPORT int
getbnum(arg,valp)2400 getbnum(arg, valp)
2401 char *arg;
2402 Llong *valp;
2403 {
2404 return (getlldefault(arg, valp, 512));
2405 }
2406
2407 EXPORT int
getknum(arg,valp)2408 getknum(arg, valp)
2409 char *arg;
2410 Llong *valp;
2411 {
2412 return (getlldefault(arg, valp, 1024));
2413 }
2414
2415 LOCAL int
getenum(arg,valp)2416 getenum(arg, valp)
2417 char *arg;
2418 long *valp;
2419 {
2420 int ret = getnum(arg, valp);
2421
2422 if (ret != 1)
2423 errmsgno(EX_BAD, "Badly formed number '%s'.\n", arg);
2424 return (ret);
2425 }
2426
2427 LOCAL int
addtarfile(tarfile)2428 addtarfile(tarfile)
2429 const char *tarfile;
2430 {
2431 #ifdef ADDARG_DEBUG
2432 if (debug)
2433 error("Add tar file '%s'.\n", tarfile);
2434 #endif
2435
2436 if (ntarfiles >= NTARFILE)
2437 comerrno(EX_BAD, "Too many tar files (max is %d).\n", NTARFILE);
2438
2439 if (ntarfiles > 0 && (streql(tarfile, "-") || streql(tarfiles[0], "-")))
2440 comerrno(EX_BAD, "Cannot handle multi volume archives from/to stdin/stdout.\n");
2441
2442 tarfiles[ntarfiles] = tarfile;
2443 ntarfiles++;
2444 return (TRUE);
2445 }
2446
2447 LOCAL int
add_diffopt(optstr,flagp)2448 add_diffopt(optstr, flagp)
2449 char *optstr;
2450 long *flagp;
2451 {
2452 char *ep;
2453 char *np;
2454 int optlen;
2455 long optflags = 0;
2456 BOOL not = FALSE;
2457
2458 while (*optstr) {
2459 if ((ep = strchr(optstr, ',')) != NULL) {
2460 Intptr_t pdiff = ep - optstr;
2461
2462 optlen = (int)pdiff;
2463 if (optlen != pdiff) /* lint paranoia */
2464 return (-1);
2465 np = &ep[1];
2466 } else {
2467 optlen = strlen(optstr);
2468 np = &optstr[optlen];
2469 }
2470 if (optstr[0] == '!') {
2471 optstr++;
2472 optlen--;
2473 not = TRUE;
2474 }
2475 if (strncmp(optstr, "not", optlen) == 0 ||
2476 strncmp(optstr, "!", optlen) == 0) {
2477 not = TRUE;
2478 } else if (strncmp(optstr, "all", optlen) == 0) {
2479 optflags |= D_ALL;
2480 } else if (strncmp(optstr, "perm", optlen) == 0) {
2481 optflags |= D_PERM;
2482 } else if (strncmp(optstr, "mode", optlen) == 0) {
2483 optflags |= D_PERM;
2484 } else if (strncmp(optstr, "symperm", optlen) == 0) {
2485 optflags |= D_SYMPERM;
2486 } else if (strncmp(optstr, "type", optlen) == 0) {
2487 optflags |= D_TYPE;
2488 } else if (strncmp(optstr, "nlink", optlen) == 0) {
2489 optflags |= D_NLINK|D_DNLINK;
2490 } else if (strncmp(optstr, "dnlink", optlen) == 0) {
2491 optflags |= D_DNLINK;
2492 } else if (strncmp(optstr, "uid", optlen) == 0) {
2493 optflags |= D_UID;
2494 } else if (strncmp(optstr, "gid", optlen) == 0) {
2495 optflags |= D_GID;
2496 } else if (strncmp(optstr, "uname", optlen) == 0) {
2497 optflags |= D_UNAME;
2498 } else if (strncmp(optstr, "gname", optlen) == 0) {
2499 optflags |= D_GNAME;
2500 } else if (strncmp(optstr, "id", optlen) == 0) {
2501 optflags |= D_ID;
2502 } else if (strncmp(optstr, "size", optlen) == 0) {
2503 optflags |= D_SIZE;
2504 } else if (strncmp(optstr, "data", optlen) == 0) {
2505 optflags |= D_DATA;
2506 } else if (strncmp(optstr, "cont", optlen) == 0) {
2507 optflags |= D_DATA;
2508 } else if (strncmp(optstr, "rdev", optlen) == 0) {
2509 optflags |= D_RDEV;
2510 } else if (strncmp(optstr, "hardlink", optlen) == 0) {
2511 optflags |= D_HLINK;
2512 } else if (strncmp(optstr, "symlink", optlen) == 0) {
2513 optflags |= D_SLINK;
2514 } else if (strncmp(optstr, "sympath", optlen) == 0) {
2515 optflags |= D_SLPATH;
2516 } else if (strncmp(optstr, "sparse", optlen) == 0) {
2517 optflags |= D_SPARS;
2518 } else if (strncmp(optstr, "atime", optlen) == 0) {
2519 optflags |= D_ATIME;
2520 } else if (strncmp(optstr, "mtime", optlen) == 0) {
2521 optflags |= D_MTIME;
2522 } else if (strncmp(optstr, "ctime", optlen) == 0) {
2523 optflags |= D_CTIME;
2524 } else if (strncmp(optstr, "lmtime", optlen) == 0) {
2525 optflags |= D_LMTIME;
2526 } else if (strncmp(optstr, "times", optlen) == 0) {
2527 optflags |= D_TIMES;
2528 } else if (strncmp(optstr, "xtimes", optlen) == 0) {
2529 optflags |= D_XTIMES;
2530 } else if (strncmp(optstr, "nsecs", optlen) == 0) {
2531 optflags |= D_ANTIME|D_MNTIME|D_CNTIME;
2532 } else if (strncmp(optstr, "dir", optlen) == 0) {
2533 optflags |= D_DIR;
2534 #ifdef USE_ACL
2535 } else if (strncmp(optstr, "acl", optlen) == 0) {
2536 optflags |= D_ACL;
2537 #endif
2538 #ifdef USE_XATTR
2539 } else if (strncmp(optstr, "xattr", optlen) == 0) {
2540 optflags |= D_XATTR;
2541 #endif
2542 #ifdef USE_FFLAGS
2543 } else if (strncmp(optstr, "fflags", optlen) == 0) {
2544 optflags |= D_FFLAGS;
2545 #endif
2546 } else if (strncmp(optstr, "help", optlen) == 0) {
2547 dusage(0);
2548 } else {
2549 error("Illegal diffopt.\n");
2550 dusage(EX_BAD);
2551 return (-1);
2552 }
2553 optstr = np;
2554 }
2555 if (not)
2556 optflags = ~optflags;
2557
2558 if ((optflags & D_MTIME) == 0)
2559 optflags &= ~D_LMTIME;
2560
2561 if ((optflags & D_SLINK) == 0)
2562 optflags &= ~D_SLPATH;
2563
2564 *flagp = optflags;
2565
2566 return (TRUE);
2567 }
2568
2569 LOCAL int
gethdr(optstr,typep)2570 gethdr(optstr, typep)
2571 char *optstr;
2572 long *typep;
2573 {
2574 BOOL swapped = FALSE;
2575 long type = H_UNDEF;
2576
2577 if (*optstr == 'S') {
2578 swapped = TRUE;
2579 optstr++;
2580 }
2581 if (streql(optstr, "help")) {
2582 husage(0);
2583 } else if ((type = hdr_type(optstr)) < 0) {
2584 error("Illegal header type '%s'.\n", optstr);
2585 husage(EX_BAD);
2586 return (-1);
2587 }
2588 if (swapped)
2589 *typep = H_SWAPPED(type);
2590 else
2591 *typep = type;
2592 return (TRUE);
2593 }
2594
2595 /* ARGSUSED */
2596 LOCAL int
getexclude(arg,valp,pac,pav)2597 getexclude(arg, valp, pac, pav)
2598 char *arg;
2599 long *valp;
2600 int *pac;
2601 char *const **pav;
2602 {
2603 FILE *xf;
2604
2605 if (streql(arg, "-")) {
2606 check_stdin("-X");
2607 xf = stdin;
2608 } else if ((xf = lfilemopen(arg, "r", S_IRWALL)) == (FILE *)NULL)
2609 comerr("Cannot open '%s'.\n", arg);
2610 hash_xbuild(xf);
2611 fclose(xf);
2612 return (1);
2613 }
2614
2615 #ifdef USED
2616 /*
2617 * Add archive file.
2618 * May currently not be activated:
2619 * If the option string ends with ",&", the -C option will not work
2620 * anymore.
2621 */
2622 LOCAL int
addfile(optstr,dummy)2623 addfile(optstr, dummy)
2624 char *optstr;
2625 long *dummy;
2626 {
2627 char *p;
2628
2629 #ifdef ADDARG_DEBUG
2630 error("got_it: %s\n", optstr);
2631 #endif
2632
2633 if (!strchr("01234567", optstr[0]))
2634 return (NOTAFILE); /* Tell getargs that this may be a flag */
2635
2636 for (p = &optstr[1]; *p; p++) {
2637 if (*p != 'l' && *p != 'm' && *p != 'h')
2638 return (BADFLAG);
2639 }
2640 #ifdef ADDARG_DEBUG
2641 error("is_tape: %s\n", optstr);
2642 #endif
2643
2644 comerrno(EX_BAD, "Options [0-7][lmh] currently not supported.\n");
2645 /*
2646 * The tape device should be determined from the defaults file
2647 * in the near future.
2648 * Search for /etc/opt/schily/star, /etc/default/star, /etc/default/tar
2649 */
2650
2651 return (1); /* Success */
2652 }
2653 #endif
2654
2655 EXPORT void
set_signal(sig,handler)2656 set_signal(sig, handler)
2657 int sig;
2658 RETSIGTYPE (*handler) __PR((int));
2659 {
2660 #if defined(HAVE_SIGPROCMASK) && defined(SA_RESTART)
2661 struct sigaction sa;
2662
2663 sigemptyset(&sa.sa_mask);
2664 sa.sa_handler = handler;
2665 sa.sa_flags = SA_RESTART;
2666 (void) sigaction(sig, &sa, (struct sigaction *)0);
2667 #else
2668 #ifdef HAVE_SIGSETMASK
2669 struct sigvec sv;
2670
2671 sv.sv_mask = 0;
2672 sv.sv_handler = handler;
2673 sv.sv_flags = 0;
2674 (void) sigvec(sig, &sv, (struct sigvec *)0);
2675 #else
2676 (void) signal(sig, handler);
2677 #endif
2678 #endif
2679 }
2680
2681 LOCAL void
exsig(sig)2682 exsig(sig)
2683 int sig;
2684 {
2685 (void) signal(sig, SIG_DFL);
2686 kill(getpid(), sig);
2687 }
2688
2689 /* ARGSUSED */
2690 LOCAL void
sighup(sig)2691 sighup(sig)
2692 int sig;
2693 {
2694 #ifdef SIGHUP
2695 set_signal(SIGHUP, sighup);
2696 #endif
2697 prstats();
2698 intr++;
2699 if (!cflag)
2700 exsig(sig);
2701 }
2702
2703 /* ARGSUSED */
2704 LOCAL void
sigintr(sig)2705 sigintr(sig)
2706 int sig;
2707 {
2708 #ifdef SIGINT
2709 set_signal(SIGINT, sigintr);
2710 #endif
2711 prstats();
2712 intr++;
2713 if (!cflag)
2714 exsig(sig);
2715 }
2716
2717 /* ARGSUSED */
2718 LOCAL void
sigquit(sig)2719 sigquit(sig)
2720 int sig;
2721 {
2722 /*
2723 * sig may be either SIGQUIT or SIGINFO (*BSD only).
2724 */
2725 set_signal(sig, sigquit);
2726 prstats();
2727 }
2728
2729 LOCAL void
getstamp()2730 getstamp()
2731 {
2732 FINFO finfo;
2733 BOOL ofollow = follow;
2734
2735 follow = TRUE;
2736 if (!_getinfo(stampfile, &finfo))
2737 comerr("Cannot stat '%s'.\n", stampfile);
2738 follow = ofollow;
2739
2740 Newer.tv_sec = finfo.f_mtime;
2741 Newer.tv_nsec = finfo.f_mnsec;
2742 }
2743
2744 LOCAL const char *
has_cli(ac,av)2745 has_cli(ac, av)
2746 int ac;
2747 char *const *av;
2748 {
2749 if (ac > 1) {
2750 const char *p = av[1];
2751
2752 if (p[0] == 'c' && p[1] == 'l' && p[2] == 'i' && p[3] == '=')
2753 return (&p[4]);
2754 }
2755 return (NULL);
2756 }
2757
2758 LOCAL struct clis {
2759 char *name;
2760 int type;
2761 } clis[] = {
2762 { "star", P_STAR },
2763 { "suntar", P_SUNTAR },
2764 { "tar", P_SUNTAR },
2765 { "gnutar", P_GNUTAR },
2766 { "gtar", P_GNUTAR },
2767 { "pax", P_PAX },
2768 { "cpio", P_CPIO },
2769 { NULL, C_NONE },
2770 };
2771
2772 LOCAL int
get_ptype(p)2773 get_ptype(p)
2774 const char *p;
2775 {
2776 struct clis *clp = clis;
2777
2778 while (clp->name) {
2779 if (streql(clp->name, p))
2780 return (clp->type);
2781 clp++;
2782 }
2783
2784 return (C_NONE);
2785 }
2786
2787 LOCAL void
set_ptype(pac,pav)2788 set_ptype(pac, pav)
2789 int *pac;
2790 char *const **pav;
2791 {
2792 int ac = *pac;
2793 char *const *av = *pav;
2794 const char *p;
2795
2796 if ((p = has_cli(ac, av)) != NULL) {
2797 ptype = get_ptype(p);
2798 if (ptype == C_NONE) {
2799 struct clis *clp = clis;
2800
2801 errmsgno(EX_BAD, "Illegal cli name '%s'.\n", p);
2802 errmsgno(EX_BAD, "Use one of:");
2803 while (clp->name) {
2804 error(" %s", (clp++)->name);
2805 }
2806 error(".\n\n");
2807 susage(EX_BAD);
2808 }
2809 set_progname((pname = p));
2810 return;
2811 }
2812
2813 p = filename(av[0]);
2814
2815 /*
2816 * If you like different behavior, you need to insert exceptional
2817 * code before the switch statement.
2818 *
2819 * These are the names we support:
2820 *
2821 * cpio gnutar pax star suntar ustar
2822 */
2823 switch (p[0]) {
2824
2825 case 'c': /* 'c'pio */
2826 ptype = P_CPIO;
2827 return;
2828
2829 case 'g': /* 'g'*tar */
2830 ptype = P_GNUTAR;
2831 return;
2832
2833 case 'p': /* 'p'ax */
2834 ptype = P_PAX;
2835 return;
2836
2837 case 't': /* 't'ar */
2838 /*
2839 * If we put something different here (e.g. P_STAR), we may
2840 * set the default behavior to be the behavor of 'star'.
2841 */
2842 ptype = P_SUNTAR;
2843 return;
2844 case 's':
2845 if (streql(p, "suntar")) {
2846 ptype = P_SUNTAR;
2847 return;
2848 }
2849 if (streql(p, "scpio")) {
2850 ptype = P_CPIO;
2851 return;
2852 }
2853 if (streql(p, "spax")) {
2854 ptype = P_PAX;
2855 return;
2856 }
2857 /* FALLTHRU */
2858
2859 case 'u': /* 'u'star */
2860 ptype = P_STAR;
2861 return;
2862 default:
2863 ptype = PTYPE_DEFAULT;
2864 return;
2865 }
2866 }
2867
2868 /* BEGIN CSTYLED */
2869 /*
2870 * Convert old tar type syntax into the new UNIX option syntax.
2871 * Allow only a limited subset of the single character options to avoid
2872 * collisions between interpretation of options in different
2873 * tar implementations. The old syntax has a risk to damage files
2874 * which is avoided with the 'fcompat' flag (see opentape()).
2875 *
2876 * The UNIX-98 documentation lists the following tar options:
2877 * Function Key: crtux
2878 * c Create
2879 * r Append
2880 * t List
2881 * u Update
2882 * x Extract
2883 * Additional Key: vwfblmo
2884 * v Verbose
2885 * w Wait for confirmation
2886 * f Archive file
2887 * b Blocking factor
2888 * l Report missing links
2889 * m Do not restore mtime from archive
2890 * o Do not restore owner/group from archive
2891 *
2892 * Incompatibilities with UNIX-98 tar:
2893 * l works the oposite way round as with star, but
2894 * if TAR_COMPAT is defined, star will behave
2895 * as documented in UNIX-98 if av[0] is either
2896 * "tar" or "ustar".
2897 *
2898 * Additional functions from historic UNIX tar versions:
2899 * 0..7 magtape_0 .. magtape_7
2900 *
2901 * Additional functions from historic BSD tar versions:
2902 * p Extract dir permissions too
2903 * h Follow symbolic links
2904 * i ignore directory checksum errors
2905 * B do multiple reads to reblock pipes
2906 * F Ommit unwanted files (e.g. core)
2907 *
2908 * Additional functions from historic Star versions:
2909 * T Use $TAPE environment as archive
2910 * L Follow symbolic links
2911 * d do not archive/extract directories
2912 * k keep old files
2913 * n do not extract but tell what to do
2914 *
2915 * Additional functions from historic SVr4 tar versions:
2916 * e Exit on unexpected errors
2917 * X Arg is File with unwanted filenames
2918 *
2919 * Additional functions from historic GNU tar versions:
2920 * z do inline compression
2921 *
2922 * Missing in star (from SVr4/Solaris tar):
2923 * E Extended headers
2924 * P Supress '/' at beginning of filenames
2925 * q quit after extracting first file
2926 * Incompatibilities with SVr4/Solaris tar:
2927 * I Arg is File with filenames to be included
2928 * The -I option is not handled as option.
2929 * P SVr4/solaris: Supress '/', star: last partial
2930 * k set tape size for multi volume archives
2931 * n non tape device (do seeks)
2932 *
2933 * Incompatibilities with GNU tar:
2934 * There are many. GNU programs in many cases make smooth
2935 * coexistence hard.
2936 *
2937 * Problems:
2938 * The 'e' and 'X' option are currently not implemented.
2939 * There is a collision between the BSD -I (include) and
2940 * star's -I (interactive) which may be solved by using -w instead.
2941 */
2942 /* END CSTYLED */
2943 LOCAL void
docompat(pac,pav)2944 docompat(pac, pav)
2945 int *pac;
2946 char *const **pav;
2947 {
2948 int ac = *pac;
2949 char *const *av = *pav;
2950 int nac;
2951 char **nav;
2952 char nopt[3];
2953 char *_copt = "crtuxbfXBFTLdehijklmnopvwz01234567";
2954 char *copt = _copt;
2955 const char *p;
2956 char c;
2957 char *const *oa;
2958 char **na;
2959 int coff = 1;
2960
2961 set_ptype(pac, pav);
2962 switch (ptype) {
2963
2964 case P_SUNTAR:
2965 iftype = I_TAR;
2966 #ifdef SUN_TAR
2967 copt = sun_copt;
2968 #endif
2969 break;
2970 case P_GNUTAR:
2971 iftype = I_TAR;
2972 #ifdef GNU_TAR
2973 copt = gnu_copt;
2974 #endif
2975 break;
2976 case P_PAX:
2977 iftype = I_PAX;
2978 break;
2979 case P_CPIO:
2980 iftype = I_CPIO;
2981 break;
2982 case P_STAR:
2983 default:
2984 iftype = I_TAR;
2985 copt = _copt;
2986 }
2987
2988 /*
2989 * We must check this first to be able to set 'tcompat'.
2990 */
2991 p = filename(av[0]);
2992 if (streql(p, "tar") || streql(p, "ustar") ||
2993 streql(p, "suntar") || streql(p, "gnutar") || streql(p, "gtar"))
2994 tcompat = TRUE;
2995
2996 if (pname) /* cli=xxx seen as argv[1] */
2997 coff++;
2998
2999 if (ac <= coff)
3000 return;
3001 if (iftype != I_TAR)
3002 return;
3003
3004
3005 /*
3006 * If we come here, this is for a tar type CLI.
3007 */
3008 if (ptype != P_SUNTAR && ptype != P_GNUTAR) {
3009 /*
3010 * For "suntar" & "gnutar" the first option string may start
3011 * with '-', and still may need a conversion, else only convert
3012 * to new syntax if the first arg is a non '-' arg.
3013 */
3014 if (av[1][0] == '-') /* Do not convert new syntax */
3015 return;
3016 }
3017 if (av[coff][0] == '-' && av[coff][1] == '-') /* Do not convert new syntax */
3018 return;
3019
3020 if (strchr(av[coff], '=') != NULL) /* Do not try to convert bs= */
3021 return;
3022
3023 nac = ac + strlen(av[coff]);
3024 nav = ___malloc(nac-- * sizeof (char *), /* keep space for NULL ptr */
3025 "compat argv");
3026 oa = av; /* remember old arg pointer */
3027 na = nav; /* set up new arg pointer */
3028 *na++ = *oa++; /* copy over av[0] */
3029 if (coff > 1) /* If we have a cli= argument */
3030 *na++ = *oa++; /* copy over av[1] (cli=...) */
3031 oa++; /* Skip over av[coff] */
3032
3033 nopt[0] = '-';
3034 nopt[2] = '\0';
3035
3036 for (p = av[coff]; (c = *p) != '\0'; p++) {
3037 if (c == '-') {
3038 nac--;
3039 continue;
3040 }
3041 if (strchr(copt, c) == NULL) {
3042 if (ptype == P_SUNTAR || ptype == P_GNUTAR)
3043 errmsgno(EX_BAD, "Illegal option '%c'.\n", c);
3044 else
3045 errmsgno(EX_BAD, "Illegal option '%c' for compat mode.\n", c);
3046
3047 susage(EX_BAD);
3048 }
3049 nopt[1] = c;
3050 *na++ = ___savestr(nopt);
3051
3052 if (c == 'f' || c == 'b' || (ptype == P_SUNTAR && c == 'k') || c == 'X') {
3053 if ((av + ac) <= oa) {
3054 comerrno(EX_BAD,
3055 "Missing arg for '%s' option.\n",
3056 nopt);
3057 }
3058 *na++ = *oa++;
3059 /*
3060 * The old syntax has a high risk of corrupting
3061 * files if the user disorders the args.
3062 */
3063 if (c == 'f')
3064 fcompat = TRUE;
3065 }
3066 }
3067
3068 /*
3069 * Now copy over the rest...
3070 */
3071 while ((av + ac) > oa)
3072 *na++ = *oa++;
3073 *na = NULL;
3074
3075 *pac = nac;
3076 *pav = nav;
3077
3078 #ifdef COMPAT_DEBUG
3079 { int i;
3080 printf("agrc: %d\n", nac);
3081 for (i = 0; i < nac; i++)
3082 printf("%i: '%s'\n", i, nav[i]);
3083 }
3084 #endif
3085 }
3086
3087 EXPORT BOOL
ttyerr(f)3088 ttyerr(f)
3089 FILE *f;
3090 {
3091 /*
3092 * We may get EIO in case that we received an ignored SIGTTIN.
3093 */
3094 if (ferror(f)) {
3095 errmsgno(EX_BAD, "No access to tty.\n");
3096 return (TRUE);
3097 }
3098 if (feof(f)) {
3099 errmsgno(EX_BAD, "EOF on tty.\n");
3100 return (TRUE);
3101 }
3102 return (FALSE);
3103 }
3104