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 				&copyflag, &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 				&notpat, &notpat, &match_tree,
1617 				&paxmatch, &paxnflag, &notarg, &notarg,
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 				&copylinks, &copyhardlinks, &copysymlinks,
1634 				&copydlinks,
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