hbase

heirloom base
git clone git://git.2f30.org/hbase
Log | Files | Refs | README

find.c (36563B)


      1 /*	find	COMPILE:	cc -o find -s -O -i find.c -lS	*/
      2 /*
      3  * Changes by Gunnar Ritter, Freiburg i. Br., Germany, September 2003.
      4  */
      5 /*	from Unix 7th Edition /usr/src/cmd/find.c	*/
      6 /*
      7  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  *   Redistributions of source code and documentation must retain the
     13  *    above copyright notice, this list of conditions and the following
     14  *    disclaimer.
     15  *   Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *   All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *      This product includes software developed or owned by Caldera
     21  *      International, Inc.
     22  *   Neither the name of Caldera International, Inc. nor the names of
     23  *    other contributors may be used to endorse or promote products
     24  *    derived from this software without specific prior written permission.
     25  *
     26  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
     27  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
     28  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     29  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     30  * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
     31  * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     34  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     35  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     36  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     37  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     38  */
     39 
     40 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
     41 #define	USED	__attribute__ ((used))
     42 #elif defined __GNUC__
     43 #define	USED	__attribute__ ((unused))
     44 #else
     45 #define	USED
     46 #endif
     47 #if defined (SU3)
     48 static const char sccsid[] USED = "@(#)find_su3.sl	1.45 (gritter) 5/8/06";
     49 #elif defined (SUS)
     50 static const char sccsid[] USED = "@(#)find_sus.sl	1.45 (gritter) 5/8/06";
     51 #else
     52 static const char sccsid[] USED = "@(#)find.sl	1.45 (gritter) 5/8/06";
     53 #endif
     54 
     55 #include <stdio.h>
     56 #include <stdlib.h>
     57 #include <string.h>
     58 #include <sys/types.h>
     59 #include <sys/stat.h>
     60 #include <sys/wait.h>
     61 #include <sys/resource.h>
     62 #include <fcntl.h>
     63 #include <unistd.h>
     64 #include <pwd.h>
     65 #include <time.h>
     66 #include <grp.h>
     67 #include <stdarg.h>
     68 #include <libgen.h>
     69 #include <errno.h>
     70 #include <locale.h>
     71 #include <signal.h>
     72 #if defined (SUS) || defined (SU3)
     73 #include <fnmatch.h>
     74 #endif
     75 #if defined (__linux__) || defined (_AIX) || defined (__hpux)
     76 #include <mntent.h>
     77 #endif
     78 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || \
     79 	defined (__DragonFly__) || defined (__APPLE__)
     80 #include <sys/param.h>
     81 #include <sys/mount.h>
     82 #endif
     83 #ifdef	_AIX
     84 #include <sys/sysmacros.h>
     85 #endif
     86 #ifndef	major
     87 #include <sys/mkdev.h>
     88 #endif
     89 #if __NetBSD_Version__>= 300000000
     90 #include <sys/statvfs.h>
     91 #define statfs statvfs
     92 #endif
     93 #include "getdir.h"
     94 #include "atoll.h"
     95 #define A_DAY	86400L /* a day full of seconds */
     96 #define EQ(x, y)	(strcmp(x, y)==0)
     97 
     98 #ifndef	MNTTYPE_IGNORE
     99 #define	MNTTYPE_IGNORE	""
    100 #endif
    101 
    102 #ifndef	S_IFDOOR
    103 #define	S_IFDOOR	0xD000
    104 #endif
    105 
    106 #ifndef	S_IFNWK
    107 #define	S_IFNWK		0x9000
    108 #endif
    109 
    110 #undef	ctime
    111 #define	ctime	find_ctime
    112 
    113 static char	*Pathname;
    114 
    115 struct aggregate {		/* for exec ... {} + */
    116 	long	a_cnt;		/* count of arguments */
    117 	long	a_cur;		/* current position in aggregate */
    118 	long	a_csz;		/* aggregate current length */
    119 	long	a_msz;		/* aggregate maximum length */
    120 	char	**a_vec;	/* arguments */
    121 	char	*a_spc;		/* aggregate space */
    122 	long	a_maxarg;	/* maximum arguments in e_vec */
    123 };
    124 
    125 struct anode {
    126 	int	(*F)(struct anode *);
    127 	union anode_l {
    128 		struct anode	*L;
    129 		char *pat;
    130 		time_t t;
    131 		uid_t u;
    132 		gid_t g;
    133 		ino_t i;
    134 		nlink_t link;
    135 		off_t sz;
    136 		mode_t per;
    137 		int com;
    138 		FILE *fp;
    139 		char *fstype;
    140 	} l;
    141 	union anode_r {
    142 		struct anode	*R;
    143 		int	s;
    144 		pid_t pid;
    145 		struct aggregate *a;
    146 	} r;
    147 };
    148 static char	*Fname;
    149 static time_t	Now;
    150 static int	Argc,
    151 	Ai,
    152 	Pi;
    153 static char	**Argv;
    154 /* cpio stuff */
    155 static int	Cpio;
    156 
    157 static struct stat Statb;
    158 
    159 /*
    160  * Keep track of all visited directories, to avoid loops caused by
    161  * symbolic links and to free storage and close files after fork().
    162  */
    163 static struct visit {
    164 	struct getdb	*v_db;	/* getdb struct for this level */
    165 	ino_t	v_ino;		/* inode number */
    166 	int	v_fd;		/* file descriptor */
    167 	dev_t	v_dev;		/* device id */
    168 } *visited;
    169 static int	vismax;		/* number of members in visited */
    170 
    171 /*
    172  * For -fstype, keep track of all filesystem types known to the system. If
    173  * we had st_fstype in struct stat as SVR4 does, this would be far more
    174  * reliable.
    175  */
    176 #if defined (__linux__) || defined (_AIX) || defined (__hpux)
    177 static struct fstype {
    178 	dev_t	fsdev;		/* device id of filesystem */
    179 	char	*fstype;	/* filesystem type */
    180 } *fstypes, *fscur;
    181 #endif	/* __linux__ || _AIX || __hpux */
    182 
    183 static int	Home = -1;
    184 static int	wanthome;
    185 static mode_t	um;		/* user's umask */
    186 static const char	*progname;
    187 static int	status;		/* exit status */
    188 static int	depth;		/* -depth flag */
    189 static int	Print = 1;	/* implicit -print */
    190 static int	Prune;		/* -prune at this point */
    191 static int	Mount;		/* -mount, -xdev */
    192 static int	Execplus;	/* have a -exec command {} + node */
    193 static int	HLflag;		/* -H or -L option given */
    194 static char	*Statfs;	/* result of statfs() on FreeBSD */
    195 static int	incomplete;	/* encountered an incomplete statement */
    196 extern int	sysv3;
    197 
    198 static int	(*statfn)(const char *, struct stat *) = lstat;
    199 
    200 static struct anode *expr(void);
    201 static struct anode *e1(void);
    202 static struct anode *e2(void);
    203 static struct anode *e3(void);
    204 static struct anode *mk(struct anode *);
    205 static void	oper(const char **);
    206 static char	*nxtarg(int);
    207 static int	and(struct anode *);
    208 static int	or(struct anode *);
    209 static int	not(struct anode *);
    210 static int	glob(struct anode *);
    211 static int	print(struct anode *);
    212 static int	prune(struct anode *);
    213 static int	null(struct anode *);
    214 static int	mtime(struct anode *);
    215 static int	atime(struct anode *);
    216 static int	ctime(struct anode *);
    217 static int	user(struct anode *);
    218 static int	ino(struct anode *);
    219 static int	group(struct anode *);
    220 static int	nogroup(struct anode *);
    221 static int	nouser(struct anode *);
    222 static int	links(struct anode *);
    223 static int	size(struct anode *);
    224 static int	sizec(struct anode *);
    225 static int	perm(struct anode *);
    226 static int	type(struct anode *);
    227 static int	exeq(struct anode *);
    228 static int	ok(struct anode *);
    229 static int	cpio(struct anode *);
    230 static int	newer(struct anode *);
    231 static int	cnewer(struct anode *);
    232 static int	anewer(struct anode *);
    233 static int	fstype(struct anode *);
    234 static int	local(struct anode *);
    235 static int	scomp(long long, long long, char);
    236 static int	doex(int, struct aggregate *);
    237 static struct aggregate *mkagg(long);
    238 static uid_t	getunum(const char *);
    239 static gid_t	getgnum(const char *);
    240 static const char	*getuser(uid_t);
    241 static const char	*getgroup(gid_t);
    242 #if defined (__linux__) || defined (_AIX) || defined (__hpux)
    243 static void	getfscur(dev_t);
    244 static void	getfstypes(void);
    245 #endif	/* __linux__ || _AIX || __hpux */
    246 static int	descend(char *, struct anode *, int);
    247 static int	descend1(char *, struct anode *, int);
    248 static int	descend2(char *, struct anode *, int);
    249 static void	setpath(char *, const char *, int);
    250 static void	pr(const char *, ...);
    251 static void	er(const char *, ...);
    252 static void	usage(void);
    253 static void	*srealloc(void *, size_t);
    254 static void	mkcpio(struct anode *, const char *, int);
    255 static void	trailer(struct anode *, int);
    256 static void	mknewer(struct anode *, const char *, int (*)(struct anode *));
    257 static mode_t	newmode(const char *ms, const mode_t pm);
    258 
    259 int
    260 main(int argc, char **argv)
    261 {
    262 	struct anode *exlist;
    263 	struct anode nlist = { null, { 0 }, { 0 } };
    264 	int paths;
    265 	register char *sp = 0;
    266 	int	i, j;
    267 
    268 	time(&Now);
    269 	umask(um = umask(0));
    270 	progname = basename(argv[0]);
    271 	setlocale(LC_COLLATE, "");
    272 	setlocale(LC_CTYPE, "");
    273 	if (getenv("SYSV3") != NULL)
    274 		sysv3 = 1;
    275 	for (i = 1; i < argc; i++) {
    276 		if (argv[i][0] != '-' || argv[i][1] == '\0')
    277 			break;
    278 		if (argv[i][1] == '-') {
    279 			i++;
    280 			break;
    281 		}
    282 		for (j = 1; argv[i][j]; j++)
    283 			if (argv[i][j] != 'H' && argv[i][j] != 'L')
    284 				goto brk;
    285 		for (j = 1; argv[i][j]; j++)
    286 			HLflag = argv[i][j];
    287 	}
    288 brk:	if (HLflag == 'L')
    289 		statfn = stat;
    290 	argc -= i - 1;
    291 	argv += i - 1;
    292 	Argc = argc; Argv = argv;
    293 	if(argc<2) {
    294 		pr("insufficient number of arguments");
    295 		usage();
    296 	}
    297 	for(Ai = paths = 1; Ai < argc; ++Ai, ++paths)
    298 		if(*Argv[Ai] == '-' || EQ(Argv[Ai], "(") || EQ(Argv[Ai], "!"))
    299 			break;
    300 	if(paths == 1) /* no path-list */
    301 		usage();
    302 	if(Ai<argc) {
    303 		if(!(exlist = expr())) /* parse and compile the arguments */
    304 			er("find: parsing error");
    305 		if(Ai<argc) {
    306 			pr("bad option %s", argv[Ai]);
    307 			usage();
    308 		}
    309 	} else
    310 		exlist = &nlist;
    311 	if (paths > 2)
    312 		wanthome = 1;
    313 	if (wanthome && (Home = open(".", O_RDONLY)) < 0)
    314 		er("bad starting directory");
    315 	for(Pi = 1; Pi < paths; ++Pi) {
    316 		if (Pi > 1 && Home >= 0 && fchdir(Home) < 0)
    317 			er("bad starting directory");
    318 		setpath(Pathname, Argv[Pi], 0);
    319 		Fname = sp = Pathname;
    320 		do
    321 			if (sp[0] == '/')
    322 				Fname = &sp[1];
    323 		while (*sp++);
    324 		descend(Pathname, exlist, 0); /* to find files that match  */
    325 	}
    326 	if(Cpio || Execplus)
    327 		trailer(exlist, 1);
    328 	exit(status);
    329 }
    330 
    331 /* compile time functions:  priority is  expr()<e1()<e2()<e3()  */
    332 
    333 /*ARGSUSED*/
    334 static struct anode *expr(void) { /* parse ALTERNATION (-o)  */
    335 	register struct anode * p1;
    336 	struct anode n = { 0, { 0 }, { 0 } };
    337 
    338 	p1 = e1() /* get left operand */ ;
    339 	if(EQ(nxtarg(0), "-o")) {
    340 		const char	*ops[] = { "-o", "-a", 0 };
    341 		oper(ops);
    342 		n.F = or, n.l.L = p1, n.r.R = expr();
    343 		return(mk(&n));
    344 	}
    345 	else if(Ai <= Argc) --Ai;
    346 	return(p1);
    347 }
    348 static struct anode *e1(void) { /* parse CONCATENATION (formerly -a) */
    349 	register struct anode * p1;
    350 	register char *a;
    351 	struct anode n = { 0, { 0 }, { 0 } };
    352 
    353 	p1 = e2();
    354 	a = nxtarg(0);
    355 	if(EQ(a, "-a")) {
    356 		const char	*ops[] = { "-o", "-a", 0 };
    357 		oper(ops);
    358 And:
    359 		n.F = and, n.l.L = p1, n.r.R = e1();
    360 		return(mk(&n));
    361 	} else if(EQ(a, "(") || EQ(a, "!") || (*a=='-' && !EQ(a, "-o"))) {
    362 		--Ai;
    363 		goto And;
    364 	} else if(Ai <= Argc) --Ai;
    365 	return(p1);
    366 }
    367 static struct anode *e2(void) { /* parse NOT (!) */
    368 	struct anode n = { 0, { 0 }, { 0 } };
    369 	if(EQ(nxtarg(0), "!")) {
    370 		const char	*ops[] = { "-o", "-a", "!", 0 };
    371 		oper(ops);
    372 		n.F = not, n.l.L = e3();
    373 		return(mk(&n));
    374 	}
    375 	else if(Ai <= Argc) --Ai;
    376 	return(e3());
    377 }
    378 static struct anode *e3(void) { /* parse parens and predicates */
    379 	struct anode *p1;
    380 	struct anode n = { 0, { 0 }, { 0 } };
    381 	long i, k;
    382 	register char *a, *b, s, *p, *q;
    383 
    384 	a = nxtarg(0);
    385 	if(EQ(a, "(")) {
    386 		const char	*ops[] = { "-o", "-a", 0 };
    387 		oper(ops);
    388 		p1 = expr();
    389 		a = nxtarg(1);
    390 		if(!EQ(a, ")")) goto err;
    391 		return(p1);
    392 	}
    393 	else if(EQ(a, "-depth")) {
    394 		depth = 1;
    395 		n.F = null;
    396 	} else if(EQ(a, "-follow")) {
    397 		statfn = stat;
    398 		n.F = null;
    399 	} else if(EQ(a, "-mount") || EQ(a, "-xdev")) {
    400 		Mount = 1;
    401 		n.F = null;
    402 	} else if(EQ(a, "-print")) {
    403 		Print = 0;
    404 		n.F = print;
    405 	} else if(EQ(a, "-prune"))
    406 		n.F = prune;
    407 	else if(EQ(a, "-nogroup"))
    408 		n.F = nogroup;
    409 	else if(EQ(a, "-nouser"))
    410 		n.F = nouser;
    411 	else if(EQ(a, "-local")) {
    412 #if defined (__linux__) || defined (_AIX) || defined (__hpux)
    413 		getfstypes();
    414 #endif	/* __linux__ || _AIX || __hpux */
    415 		n.F = local;
    416 		Statfs = a;
    417 	}
    418 	if (n.F)
    419 		return mk(&n);
    420 	b = nxtarg(2);
    421 	s = *b;
    422 	/*if(s=='+') b++;*/
    423 	if(EQ(a, "-name"))
    424 		n.F = glob, n.l.pat = b;
    425 	else if(EQ(a, "-mtime"))
    426 		n.F = mtime, n.l.t = atol(b), n.r.s = s;
    427 	else if(EQ(a, "-atime"))
    428 		n.F = atime, n.l.t = atol(b), n.r.s = s;
    429 	else if(EQ(a, "-ctime"))
    430 		n.F = ctime, n.l.t = atol(b), n.r.s = s;
    431 	else if(EQ(a, "-user"))
    432 		n.F = user, n.l.u = getunum(b), n.r.s = s;
    433 	else if(EQ(a, "-inum"))
    434 		n.F = ino, n.l.i = atoll(b), n.r.s = s;
    435 	else if(EQ(a, "-group"))
    436 		n.F = group, n.l.g = getgnum(b), n.r.s = s;
    437 	else if(EQ(a, "-size")) {
    438 		n.l.sz = atoll(b), n.r.s = s;
    439 		while (b[0] && b[1])
    440 			b++;
    441 		if (b[0] == 'c')
    442 			n.F = sizec;
    443 		else
    444 			n.F = size;
    445 	}
    446 	else if(EQ(a, "-links"))
    447 		n.F = links, n.l.link = atol(b), n.r.s = s;
    448 	else if(EQ(a, "-perm")) {
    449 		while (*b == '-')
    450 			b++;
    451 		n.F = perm, n.l.per = newmode(b, 0), n.r.s = s;
    452 #if defined (SUS) || defined (SU3)
    453 		if (s == '-')
    454 			n.l.per &= 07777;
    455 #endif
    456 	}
    457 	else if(EQ(a, "-type")) {
    458 		i = b[0] == '-' || b[0] == '+' ? b[1] : b[0];
    459 		i = i=='d' ? S_IFDIR :
    460 		    i=='b' ? S_IFBLK :
    461 		    i=='c' ? S_IFCHR :
    462 		    i=='D' ? S_IFDOOR :
    463 		    i=='f' ? S_IFREG :
    464 		    i=='l' ? S_IFLNK :
    465 		    i=='n' ? S_IFNWK :
    466 		    i=='p' ? S_IFIFO :
    467 		    i=='s' ? S_IFSOCK :
    468 		    0;
    469 		n.F = type, n.l.per = i;
    470 	}
    471 	else if (EQ(a, "-exec")) {
    472 		Print = 0;
    473 		wanthome = 1;
    474 		i = Ai - 1;
    475 		q = "";
    476 		k = 0;
    477 		while(!EQ(p = nxtarg(1), ";")) {
    478 			if (EQ(p, "+") && EQ(q, "{}")) {
    479 				n.r.a = mkagg(k);
    480 				break;
    481 			}
    482 			q = p;
    483 			k += strlen(p) + 1;
    484 		}
    485 		n.F = exeq, n.l.com = i;
    486 	}
    487 	else if (EQ(a, "-ok")) {
    488 		Print = 0;
    489 		wanthome = 1;
    490 		i = Ai - 1;
    491 		while(!EQ(p = nxtarg(1), ";"));
    492 		n.F = ok, n.l.com = i;
    493 	}
    494 	else if(EQ(a, "-cpio"))
    495 		mkcpio(&n, b, 0);
    496 	else if(EQ(a, "-ncpio"))
    497 		mkcpio(&n, b, 1);
    498 	else if(EQ(a, "-newer"))
    499 		mknewer(&n, b, newer);
    500 	else if(EQ(a, "-anewer"))
    501 		mknewer(&n, b, anewer);
    502 	else if(EQ(a, "-cnewer"))
    503 		mknewer(&n, b, cnewer);
    504 	else if(EQ(a, "-fstype")) {
    505 #if defined (__linux__) || defined (_AIX) || defined (__hpux)
    506 		getfstypes();
    507 #endif	/* __linux__ || _AIX || __hpux */
    508 		n.F = fstype, n.l.fstype = b;
    509 		Statfs = a;
    510 	}
    511 	if (n.F) {
    512 		if (incomplete)
    513 			nxtarg(1);
    514 		return mk(&n);
    515 	}
    516 err:	pr("bad option %s", a);
    517 	usage();
    518 	/*NOTREACHED*/
    519 	return 0;
    520 }
    521 static struct anode *mk(struct anode *p)
    522 {
    523 	struct anode	*n;
    524 
    525 	n = srealloc(NULL, sizeof *n);
    526 	*n = *p;
    527 	return(n);
    528 }
    529 static void oper(const char **ops)
    530 {
    531 	char	*a;
    532 
    533 	a = nxtarg(-1);
    534 	while (*ops)
    535 		if (EQ(a, *ops++))
    536 			er("operand follows operand");
    537 	Ai--;
    538 }
    539 
    540 static char *nxtarg(int must) { /* get next arg from command line */
    541 	static int strikes = 0;
    542 
    543 	if(must==1 && Ai>=Argc || strikes==3)
    544 		er("incomplete statement");
    545 	if(Ai>=Argc) {
    546 		if (must >= 0)
    547 			strikes++;
    548 		incomplete = 1;
    549 		Ai = Argc + 1;
    550 		return("");
    551 	}
    552 	return(Argv[Ai++]);
    553 }
    554 
    555 /* execution time functions */
    556 static int and(register struct anode *p)
    557 {
    558 	return(((*p->l.L->F)(p->l.L)) && ((*p->r.R->F)(p->r.R))?1:0);
    559 }
    560 static int or(register struct anode *p)
    561 {
    562 	 return(((*p->l.L->F)(p->l.L)) || ((*p->r.R->F)(p->r.R))?1:0);
    563 }
    564 static int not(register struct anode *p)
    565 {
    566 	return( !((*p->l.L->F)(p->l.L)));
    567 }
    568 #if !defined (SUS) && !defined (SU3)
    569 static int glob(register struct anode *p)
    570 {
    571 	extern int gmatch(const char *, const char *);
    572 	return(gmatch(Fname, p->l.pat));
    573 }
    574 #else	/* SUS, SU3 */
    575 static int glob(register struct anode *p)
    576 {
    577 	int	val;
    578 #ifdef	__GLIBC__
    579 	/* avoid glibc's broken [^...] */
    580 	extern char	**environ;
    581 	char	**savenv = environ;
    582 	char	*newenv[] = { "POSIXLY_CORRECT=", NULL };
    583 	environ = newenv;
    584 #endif	/* __GLIBC__ */
    585 	val = fnmatch(p->l.pat, Fname, FNM_PATHNAME) == 0;
    586 #ifdef	__GLIBC__
    587 	environ = savenv;
    588 #endif	/* __GLIBC__ */
    589 	return val;
    590 }
    591 #endif	/* SUS, SU3 */
    592 /*ARGSUSED*/
    593 static int print(register struct anode *p)
    594 {
    595 	puts(Pathname);
    596 	return(1);
    597 }
    598 /*ARGSUSED*/
    599 static int prune(register struct anode *p)
    600 {
    601 	if (!depth)
    602 		Prune = 1;
    603 	return(1);
    604 }
    605 /*ARGSUSED*/
    606 static int null(register struct anode *p)
    607 {
    608 	return(1);
    609 }
    610 static int mtime(register struct anode *p)
    611 {
    612 	return(scomp((Now - Statb.st_mtime) / A_DAY, p->l.t, p->r.s));
    613 }
    614 static int atime(register struct anode *p)
    615 {
    616 	return(scomp((Now - Statb.st_atime) / A_DAY, p->l.t, p->r.s));
    617 }
    618 static int ctime(register struct anode *p)
    619 {
    620 	return(scomp((Now - Statb.st_ctime) / A_DAY, p->l.t, p->r.s));
    621 }
    622 static int user(register struct anode *p)
    623 {
    624 	return(scomp(Statb.st_uid, p->l.u, p->r.s));
    625 }
    626 static int ino(register struct anode *p)
    627 {
    628 	return(scomp(Statb.st_ino, p->l.u, p->r.s));
    629 }
    630 static int group(register struct anode *p)
    631 {
    632 	return(p->l.u == Statb.st_gid);
    633 }
    634 static int nogroup(register struct anode *p)
    635 {
    636 	return(getgroup(Statb.st_gid) == NULL);
    637 }
    638 static int nouser(register struct anode *p)
    639 {
    640 	return(getuser(Statb.st_uid) == NULL);
    641 }
    642 static int links(register struct anode *p)
    643 {
    644 	return(scomp(Statb.st_nlink, p->l.link, p->r.s));
    645 }
    646 static int size(register struct anode *p)
    647 {
    648 	return(scomp(Statb.st_size?(Statb.st_size+511)>>9:0, p->l.sz, p->r.s));
    649 }
    650 static int sizec(register struct anode *p)
    651 {
    652 	return(scomp(Statb.st_size, p->l.sz, p->r.s));
    653 }
    654 static int perm(register struct anode *p)
    655 {
    656 	register int i;
    657 	i = (p->r.s=='-') ? p->l.per : 07777; /* '-' means only arg bits */
    658 	return((Statb.st_mode & i & 07777) == p->l.per);
    659 }
    660 static int type(register struct anode *p)
    661 {
    662 	return((Statb.st_mode&S_IFMT)==p->l.per);
    663 }
    664 static int exeq(register struct anode *p)
    665 {
    666 	if (p->r.a) {
    667 		if (Pathname) {
    668 			size_t	sz = strlen(Pathname) + 1;
    669 			if (p->r.a->a_csz + sz <= p->r.a->a_msz &&
    670 					p->r.a->a_cur < p->r.a->a_maxarg-1) {
    671 				strcpy(p->r.a->a_vec[p->r.a->a_cur++] =
    672 						&p->r.a->a_spc[p->r.a->a_csz],
    673 						Pathname);
    674 				p->r.a->a_csz += sz;
    675 				return 1;
    676 			} else {
    677 				if (p->r.a->a_cur == 0) {
    678 					p->r.a->a_vec[p->r.a->a_cur++] =
    679 						Pathname;
    680 					p->r.a->a_vec[p->r.a->a_cur] = NULL;
    681 				}
    682 				else {
    683 					p->r.a->a_vec[p->r.a->a_cur] = NULL;
    684 					fflush(stdout);
    685 					doex(p->l.com, p->r.a);
    686 					return exeq(p);
    687 				}
    688 			}
    689 		} else {
    690 			if (p->r.a->a_cur == 0)
    691 				return 1;
    692 			p->r.a->a_vec[p->r.a->a_cur] = NULL;
    693 		}
    694 	}
    695 	fflush(stdout); /* to flush possible `-print' */
    696 	return(doex(p->l.com, p->r.a));
    697 }
    698 static int ok(struct anode *p)
    699 {
    700 	char c;  int yes;
    701 	yes = 0;
    702 	fflush(stdout); /* to flush possible `-print' */
    703 	fprintf(stderr, "< %s ... %s >?   ", Argv[p->l.com], Pathname);
    704 	if (read(0, &c, 1) != 1)
    705 		exit(2);
    706 	yes = c == 'y';
    707 	if (c != '\n')
    708 		while (read(0, &c, 1) == 1 && c != '\n');
    709 	if(yes) return(doex(p->l.com, 0));
    710 	return(0);
    711 }
    712 
    713 static int cpio(struct anode *p)
    714 {
    715 	if (strchr(Pathname, '\n')) {
    716 		pr("file name \"%s\" contains a newline character; "
    717 			"file not archived", Pathname);
    718 		status |= 1;
    719 	} else
    720 		fprintf(p->l.fp, "%s\n", Pathname);
    721 	return(1);
    722 }
    723 static int newer(register struct anode *p)
    724 {
    725 	return Statb.st_mtime > p->l.t;
    726 }
    727 static int anewer(register struct anode *p)
    728 {
    729 	return Statb.st_atime > p->l.t;
    730 }
    731 static int cnewer(register struct anode *p)
    732 {
    733 	return Statb.st_ctime > p->l.t;
    734 }
    735 static int fstype(register struct anode *p)
    736 {
    737 #if defined (__linux__) || defined (_AIX) || defined (__hpux)
    738 	return(EQ(fscur->fstype, p->l.fstype));
    739 #elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
    740 		|| defined (__DragonFly__) || defined (__APPLE__)
    741 	return(EQ(Statfs, p->l.fstype));
    742 #else
    743 	return(EQ(Statb.st_fstype, p->l.fstype));
    744 #endif
    745 }
    746 static int local(register struct anode *p)
    747 {
    748 #if defined (__linux__) || defined (_AIX) || defined (__hpux)
    749 	return(strcmp(fscur->fstype, "nfs") && strcmp(fscur->fstype, "smbfs"));
    750 #elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
    751 		|| defined (__DragonFly__) || defined (__APPLE__)
    752 	return(strcmp(Statfs, "nfs") != 0);
    753 #else
    754 	return(strcmp(Statb.st_fstype, "nfs") != 0);
    755 #endif
    756 }
    757 
    758 /* support functions */
    759 /* funny signed compare */
    760 static int scomp(register long long a, register long long b, register char s)
    761 {
    762 	if(s == '+')
    763 		return(a > b);
    764 	if(s == '-')
    765 		return(a < (b * -1));
    766 	return(a == b);
    767 }
    768 
    769 static int
    770 doex(int com, struct aggregate *a)
    771 {
    772 	register int np;
    773 	register char *na;
    774 	char **oargv;
    775 	int oargc;
    776 	static char **nargv;
    777 	static int narga;
    778 	static int ccode;
    779 	pid_t	pid;
    780 
    781 	ccode = np = 0;
    782 	oargv = Argv;
    783 	oargc = com;
    784 	while (na=oargv[oargc++]) {
    785 		if (np >= narga-1)
    786 			nargv = srealloc(nargv, (narga+=20) * sizeof *nargv);
    787 		if(strcmp(na, ";")==0 && oargv == Argv) break;
    788 		if(strcmp(na, "{}")==0 && oargv == Argv) {
    789 			if (a) {
    790 				oargv = a->a_vec;
    791 				oargc = 0;
    792 			} else
    793 				nargv[np++] = Pathname;
    794 		}
    795 		else nargv[np++] = na;
    796 	}
    797 	if (a) {
    798 		a->a_cur = 0;
    799 		a->a_csz = 0;
    800 	}
    801 	if (np==0) return(9);
    802 	nargv[np] = 0;
    803 	if(pid = fork()) /*parent*/ while (wait(&ccode) != pid);
    804 	else { /*child*/
    805 		if (fchdir(Home) < 0) {
    806 			pr("bad starting directory");
    807 			_exit(1);
    808 		}
    809 		execvp(nargv[0], nargv);
    810 		_exit(1);
    811 	}
    812 	if (a && ccode) {
    813 		if (WIFSIGNALED(ccode))
    814 			status |= WTERMSIG(ccode) | 0200;
    815 		else if (WIFEXITED(ccode))
    816 			status |= WEXITSTATUS(ccode);
    817 	}
    818 	return(ccode && a==NULL ? 0:1);
    819 }
    820 
    821 static struct aggregate *mkagg(long baselen)
    822 {
    823 	static size_t	envsz;
    824 	extern char	**environ;
    825 	register int	i;
    826 	struct aggregate	*a;
    827 
    828 	a = srealloc(NULL, sizeof *a);
    829 	if (envsz == 0)
    830 		for (i = 0; environ[i]; i++)
    831 			envsz += strlen(environ[i]) + 1;
    832 	a->a_msz = sysconf(_SC_ARG_MAX) - baselen - envsz - 2048;
    833 	a->a_spc = srealloc(NULL, a->a_msz);
    834 	a->a_maxarg = 8192;
    835 	a->a_vec = srealloc(NULL, a->a_maxarg * sizeof *a->a_vec);
    836 	a->a_csz = 0;
    837 	a->a_cur = 0;
    838 	Execplus = 1;
    839 	return a;
    840 }
    841 
    842 static uid_t getunum(const char *s) { /* find user name and return number */
    843 	struct passwd *pwd;
    844 	char *x;
    845 	uid_t u;
    846 
    847 	if ((pwd = getpwnam(s)) != NULL)
    848 		return pwd->pw_uid;
    849 	u = strtol(s, &x, 10);
    850 	if (*x == '\0')
    851 		return u;
    852 	er("cannot find %s name", s);
    853 	/*NOTREACHED*/
    854 	return 0;
    855 }
    856 
    857 static gid_t getgnum(const char *s) { /* find group name and return number */
    858 	struct group *grp;
    859 	char *x;
    860 	gid_t g;
    861 
    862 	if ((grp = getgrnam(s)) != NULL)
    863 		return grp->gr_gid;
    864 	g = strtol(s, &x, 10);
    865 	if (*x == '\0')
    866 		return g;
    867 	er("cannot find %s name", s);
    868 	/*NOTREACHED*/
    869 	return 0;
    870 }
    871 
    872 #define	CACHESIZE	16
    873 
    874 static const char *getuser(uid_t uid)
    875 {
    876 	static struct {
    877 		char	*name;
    878 		uid_t	uid;
    879 	} cache[CACHESIZE];
    880 	static int	last;
    881 	int	i;
    882 	struct passwd	*pwd;
    883 	const char	*name;
    884 
    885 	for (i = 0; i < CACHESIZE && cache[i].name; i++)
    886 		if (cache[i].uid == uid)
    887 			goto found;
    888 	if ((pwd = getpwuid(uid)) != NULL)
    889 		name = pwd->pw_name;
    890 	else
    891 		name = "";
    892 	if (i >= CACHESIZE) {
    893 		if (last >= CACHESIZE)
    894 			last = 0;
    895 		i = last++;
    896 	}
    897 	if (cache[i].name)
    898 		free(cache[i].name);
    899 	cache[i].name = strdup(name);
    900 	cache[i].uid = uid;
    901 found:	return cache[i].name[0] ? cache[i].name : NULL;
    902 }
    903 
    904 static const char *getgroup(gid_t gid)
    905 {
    906 	static struct {
    907 		char	*name;
    908 		gid_t	gid;
    909 	} cache[CACHESIZE];
    910 	static int	last;
    911 	int	i;
    912 	struct group	*grp;
    913 	const char	*name;
    914 
    915 	for (i = 0; i < CACHESIZE && cache[i].name; i++)
    916 		if (cache[i].gid == gid)
    917 			goto found;
    918 	if ((grp = getgrgid(gid)) != NULL)
    919 		name = grp->gr_name;
    920 	else
    921 		name = "";
    922 	if (i >= CACHESIZE) {
    923 		if (last >= CACHESIZE)
    924 			last = 0;
    925 		i = last++;
    926 	}
    927 	if (cache[i].name)
    928 		free(cache[i].name);
    929 	cache[i].name = strdup(name);
    930 	cache[i].gid = gid;
    931 found:	return cache[i].name[0] ? cache[i].name : NULL;
    932 }
    933 
    934 #if defined (__linux__) || defined (_AIX) || defined (__hpux)
    935 static void getfscur(dev_t dev)
    936 {
    937 	int	i;
    938 
    939 	for (i = 0; fstypes[i].fstype; i++)
    940 		if (fstypes[i].fsdev == dev) {
    941 			fscur = &fstypes[i];
    942 			return;
    943 		}
    944 	er("filesystem type for %s unknown", Pathname);
    945 }
    946 
    947 static void getfstypes(void)
    948 {
    949 	struct stat	st;
    950 	FILE	*fp;
    951 	struct mntent	*mp;
    952 #ifdef	__hpux
    953 	const char mtab[] = "/etc/mnttab";
    954 #else	/* __linux__, _AIX */
    955 	const char mtab[] = "/etc/mtab";
    956 #endif	/* __linux__, _AIX */
    957 	int	i = 0;
    958 
    959 	if (fstypes)
    960 		return;
    961 	if ((fp = setmntent(mtab, "r")) == NULL)
    962 		er("cannot open %s: %s", mtab, strerror(errno));
    963 	while ((mp = getmntent(fp)) != NULL) {
    964 		if (EQ(mp->mnt_type, MNTTYPE_IGNORE))
    965 			continue;
    966 		if (stat(mp->mnt_dir, &st) < 0)
    967 			continue;
    968 		fstypes = srealloc(fstypes, (i+1) * sizeof *fstypes);
    969 		fstypes[i].fsdev = st.st_dev;
    970 		fstypes[i].fstype = strdup(mp->mnt_type);
    971 		i++;
    972 	}
    973 	endmntent(fp);
    974 }
    975 #endif	/* __linux__ || _AIX || __hpux */
    976 
    977 /*
    978  * First part of descend, called for any file found.
    979  */
    980 static int descend(char *fname, struct anode *exlist, int level)
    981 {
    982 	struct stat	ost;
    983 	register char *c1;
    984 	int i;
    985 	int rv = 0;
    986 
    987 	if(statfn(fname, &Statb)<0) {
    988 		if (statfn != lstat && lstat(fname, &Statb) == 0)
    989 		nof:	c1 = "cannot follow symbolic link %s: %s";
    990 		else if (sysv3)
    991 			c1 = "stat() failed: %s: %s";
    992 		else if (errno == ENOENT || errno == ENOTDIR)
    993 			c1 = "cannot open %s: %s";
    994 		else
    995 			c1 = "stat() error %s: %s";
    996 		pr(c1, Pathname, strerror(errno));
    997 		status = 18;
    998 		return(0);
    999 	}
   1000 	if (level == 0 && HLflag == 'H' && (Statb.st_mode&S_IFMT) == S_IFLNK) {
   1001 		struct stat	nst;
   1002 		if (stat(fname, &nst) == 0)
   1003 			Statb = nst;
   1004 		else if (errno == ELOOP)
   1005 			goto nof;
   1006 	}
   1007 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || \
   1008 		defined (__DragonFly__) || defined (__APPLE__)
   1009 	if (Statfs != NULL) {
   1010 		static struct statfs	sf;
   1011 		if (statfs(fname, &sf) < 0) {
   1012 			pr("statfs() error %s: %s", Pathname, strerror(errno));
   1013 			status = 18;
   1014 			return(0);
   1015 		}
   1016 		Statfs = sf.f_fstypename;
   1017 	}
   1018 #endif	/* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
   1019 	if (Mount) {
   1020 		static dev_t	curdev;
   1021 		if (level == 0)
   1022 			curdev = Statb.st_dev;
   1023 		else if (curdev != Statb.st_dev)
   1024 			return(0);
   1025 	}
   1026 	Prune = 0;
   1027 	if (!depth) {
   1028 #if defined (__linux__) || defined (_AIX) || defined (__hpux)
   1029 		if (fstypes)
   1030 			getfscur(Statb.st_dev);
   1031 #endif	/* __linux__ || _AIX || __hpux */
   1032 		if((*exlist->F)(exlist) && Print)
   1033 		puts(Pathname);
   1034 	} else
   1035 		ost = Statb;
   1036 	if(Prune || (Statb.st_mode&S_IFMT)!=S_IFDIR)
   1037 		goto reg;
   1038 	if (statfn != lstat) {
   1039 		for (i = 0; i < level; i++)
   1040 			if (Statb.st_dev == visited[i].v_dev &&
   1041 					Statb.st_ino == visited[i].v_ino) {
   1042 #ifdef	SU3
   1043 				pr("Symbolic link loop at %s", Pathname);
   1044 				status = 18;
   1045 #endif	/* SU3 */
   1046 				goto reg;
   1047 			}
   1048 	}
   1049 	if (level >= vismax) {
   1050 		vismax += 20;
   1051 		visited = srealloc(visited, sizeof *visited * vismax);
   1052 	}
   1053 	visited[level].v_dev = Statb.st_dev;
   1054 	visited[level].v_ino = Statb.st_ino;
   1055 
   1056 	rv = descend1(fname, exlist, level);
   1057 
   1058 reg:
   1059 	if (depth) {
   1060 		Statb = ost;
   1061 #if defined (__linux__) || defined (_AIX) || defined (__hpux)
   1062 		if (fstypes)
   1063 			getfscur(Statb.st_dev);
   1064 #endif	/* __linux__ || _AIX || __hpux */
   1065 		if ((*exlist->F)(exlist) && Print)
   1066 			puts(Pathname);
   1067 	}
   1068 	return(rv);
   1069 }
   1070 
   1071 /*
   1072  * Second part of descend, called for any directory found.
   1073  */
   1074 static int descend1(char *fname, struct anode *exlist, int level)
   1075 {
   1076 	int	dir = 0; /* open directory */
   1077 	register char *c1;
   1078 	struct getdb *db;
   1079 	register struct direc *dp;
   1080 	int endofname;
   1081 	int err;
   1082 	int oflags = O_RDONLY;
   1083 
   1084 #ifdef	O_DIRECTORY
   1085 	oflags |= O_DIRECTORY;
   1086 #endif
   1087 #ifdef	O_NOFOLLOW
   1088 	if (statfn == lstat && (HLflag != 'H' || level > 0))
   1089 		oflags |= O_NOFOLLOW;
   1090 #endif
   1091 	if ((dir = open(fname, oflags)) < 0 ||
   1092 			fcntl(dir, F_SETFD, FD_CLOEXEC) < 0 ||
   1093 			fchdir(dir) < 0) {
   1094 		if (dir >= 0)
   1095 			close(dir);
   1096 		else if (errno == EMFILE && descend2(fname, exlist, level))
   1097 			/*
   1098 			 * A possible performance improvement would be to
   1099 			 * call descend2() in the directory above, since
   1100 			 * the current method involves one fork() call per
   1101 			 * subdirectory at this level. The condition occurs
   1102 			 * so rarely that it seems hardly worth optimization
   1103 			 * though.
   1104 			 */
   1105 			return 0;
   1106 		pr("cannot open %s: %s", Pathname, strerror(errno));
   1107 		status = 18;
   1108 		return 0;
   1109 	}
   1110 	if ((db = getdb_alloc(Pathname, dir)) == NULL) {
   1111 		write(2, "no memory\n", 10);
   1112 		_exit(077);
   1113 	}
   1114 	visited[level].v_db = db;
   1115 	visited[level].v_fd = dir;
   1116 	for(c1 = Pathname; *c1; ++c1);
   1117 	if(*(c1-1) == '/')
   1118 		--c1;
   1119 	endofname = c1 - Pathname;
   1120 
   1121 	while ((dp = getdir(db, &err)) != NULL) {
   1122 		if((dp->d_name[0]=='.' && dp->d_name[1]=='\0') ||
   1123 				(dp->d_name[0]=='.' &&
   1124 				 dp->d_name[1]=='.' && dp->d_name[2]=='\0'))
   1125 			continue;
   1126 		setpath(&Pathname[endofname], dp->d_name, 1);
   1127 		Fname = &Pathname[endofname+1];
   1128 		if(descend(Fname, exlist, level+1)) {
   1129 			if (fchdir(dir) < 0)
   1130 				er("bad directory tree");
   1131 		}
   1132 	}
   1133 	Pathname[endofname] = '\0';
   1134 	getdb_free(db);
   1135 	if (err) {
   1136 		pr("cannot read dir %s: %s", Pathname, strerror(errno));
   1137 		status = 18;
   1138 	}
   1139 	close(dir);
   1140 	visited[level].v_fd = -1;
   1141 	return 1;
   1142 }
   1143 
   1144 /*
   1145  * Third part of descend, called if the limit of open file descriptors
   1146  * is exceeded (EMFILE).
   1147  */
   1148 static int descend2(char *fname, struct anode *exlist, int level)
   1149 {
   1150 	pid_t	pid;
   1151 	int	i;
   1152 
   1153 	if (Cpio || Execplus)
   1154 		trailer(exlist, 0);
   1155 	fflush(stdout);
   1156 	switch (pid = fork()) {
   1157 	case 0:
   1158 		for (i = 0; i < level-1; i++) {
   1159 			if (visited[i].v_fd >= 0) {
   1160 				getdb_free(visited[i].v_db);
   1161 				close(visited[i].v_fd);
   1162 				visited[i].v_fd = -1;
   1163 			}
   1164 		}
   1165 		status |= 0;
   1166 		descend1(fname, exlist, level);
   1167 		if (Cpio || Execplus)
   1168 			trailer(exlist, 0);
   1169 		exit(status);
   1170 		/*NOTREACHED*/
   1171 	default:
   1172 		while (waitpid(pid, &i, 0) != pid);
   1173 		if (i && WIFSIGNALED(i)) {
   1174 			struct rlimit	rl;
   1175 
   1176 			rl.rlim_cur = rl.rlim_max = 0;
   1177 			setrlimit(RLIMIT_CORE, &rl);
   1178 			raise(WTERMSIG(i));
   1179 			pause();
   1180 		}
   1181 		if (i)
   1182 			status |= WEXITSTATUS(i);
   1183 		return 1;
   1184 	case -1:
   1185 		return 0;
   1186 	}
   1187 }
   1188 static void setpath(char *eos, const char *fn, int slash)
   1189 {
   1190 	static char	*pathend;
   1191 	char	*opath;
   1192 
   1193 	for (;;) {
   1194 		if (eos >= pathend) {
   1195 			pathend += 14;
   1196 			opath = Pathname;
   1197 			Pathname = srealloc(Pathname, pathend - Pathname);
   1198 			eos += Pathname - opath;
   1199 			pathend += Pathname - opath;
   1200 		}
   1201 		if (slash) {
   1202 			*eos++ = '/';
   1203 			slash = 0;
   1204 		} else
   1205 			if ((*eos++ = *fn++) == '\0')
   1206 				break;
   1207 	}
   1208 }
   1209 
   1210 static void pr(const char *s, ...)
   1211 {
   1212 	va_list	ap;
   1213 
   1214 	fprintf(stderr, "%s: ", progname);
   1215 	va_start(ap, s);
   1216 	vfprintf(stderr, s, ap);
   1217 	va_end(ap);
   1218 	fprintf(stderr, "\n");
   1219 }
   1220 
   1221 static void er(const char *s, ...)
   1222 {
   1223 	va_list	ap;
   1224 
   1225 	fprintf(stderr, "%s: ", progname);
   1226 	va_start(ap, s);
   1227 	vfprintf(stderr, s, ap);
   1228 	va_end(ap);
   1229 	fprintf(stderr, "\n");
   1230 	exit(1);
   1231 }
   1232 
   1233 static void usage(void)
   1234 {
   1235 	er("path-list predicate-list");
   1236 }
   1237 
   1238 static void *srealloc(void *op, size_t n)
   1239 {
   1240 	void	*np;
   1241 
   1242 	if ((np = realloc(op, n)) == NULL) {
   1243 		write(2, "no memory\n", 10);
   1244 		_exit(077);
   1245 	}
   1246 	return np;
   1247 }
   1248 
   1249 static void mkcpio(struct anode *p, const char *b, int ascii)
   1250 {
   1251 	int	fd, pd[2];
   1252 	char	flags[20], *cp;
   1253 
   1254 	p->F = cpio;
   1255 	if (*b == '\0')
   1256 		return;
   1257 	depth = 1;
   1258 	Print = 0;
   1259 	Cpio = 1;
   1260 	if (pipe(pd) < 0 || (p->l.fp = fdopen(pd[1], "w")) == NULL)
   1261 		er("pipe() %s", strerror(errno));
   1262 	if ((fd = creat(b, 0666)) < 0)
   1263 		er("cannot create %s", b);
   1264 	switch (p->r.pid = fork()) {
   1265 	case -1:
   1266 		er("can't fork");
   1267 		/*NOTREACHED*/
   1268 	case 0:
   1269 		dup2(pd[0], 0);
   1270 		close(pd[0]);
   1271 		close(pd[1]);
   1272 		dup2(fd, 1);
   1273 		close(fd);
   1274 		cp = flags;
   1275 		*cp++ = '-';
   1276 		*cp++ = 'o';
   1277 		*cp++ = 'B';
   1278 		if (ascii)
   1279 			*cp++ = 'c';
   1280 		if (statfn == stat)
   1281 			*cp++ = 'L';
   1282 		*cp = '\0';
   1283 		execlp("cpio", "cpio", flags, NULL);
   1284 		pr("cannot exec cpio: %s", strerror(errno));
   1285 		_exit(0177);
   1286 		/*NOTREACHED*/
   1287 	}
   1288 	close(pd[0]);
   1289 	close(fd);
   1290 }
   1291 
   1292 static void
   1293 trailer(register struct anode *p, int termcpio)
   1294 {
   1295 	char	*Opath = Pathname;
   1296 	Pathname = 0;
   1297 	if (p->F == or || p->F == and) {
   1298 		trailer(p->l.L, termcpio);
   1299 		trailer(p->r.R, termcpio);
   1300 	} else if (p->F == not)
   1301 		trailer(p->l.L, termcpio);
   1302 	else if (p->F == cpio) {
   1303 		if (termcpio) {
   1304 			int	s;
   1305 
   1306 			fclose(p->l.fp);
   1307 			while (waitpid(p->r.pid, &s, 0) != p->r.pid);
   1308 			if (s) {
   1309 				if (WIFEXITED(s))
   1310 					status |= WEXITSTATUS(s);
   1311 				else if (WIFSIGNALED(s))
   1312 					status |= WTERMSIG(s) | 0200;
   1313 			}
   1314 		} else
   1315 			fflush(p->l.fp);
   1316 	} else if (p->F == exeq && p->r.a)
   1317 		exeq(p);
   1318 	Pathname = Opath;
   1319 }
   1320 
   1321 static void
   1322 mknewer(struct anode *p, const char *b, int (*f)(struct anode *))
   1323 {
   1324 	if (*b && stat(b, &Statb) < 0)
   1325 		er("cannot access %s", b);
   1326 	p->l.t = Statb.st_mtime;
   1327 	p->F = f;
   1328 }
   1329 
   1330 /*
   1331  * Changes by Gunnar Ritter, Freiburg i. Br., Germany, September 2003.
   1332  */
   1333 /*	from Unix 7th Edition /usr/src/cmd/chmod.c	*/
   1334 /*
   1335  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
   1336  *
   1337  * Redistribution and use in source and binary forms, with or without
   1338  * modification, are permitted provided that the following conditions
   1339  * are met:
   1340  *   Redistributions of source code and documentation must retain the
   1341  *    above copyright notice, this list of conditions and the following
   1342  *    disclaimer.
   1343  *   Redistributions in binary form must reproduce the above copyright
   1344  *    notice, this list of conditions and the following disclaimer in the
   1345  *    documentation and/or other materials provided with the distribution.
   1346  *   All advertising materials mentioning features or use of this software
   1347  *    must display the following acknowledgement:
   1348  *      This product includes software developed or owned by Caldera
   1349  *      International, Inc.
   1350  *   Neither the name of Caldera International, Inc. nor the names of
   1351  *    other contributors may be used to endorse or promote products
   1352  *    derived from this software without specific prior written permission.
   1353  *
   1354  * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
   1355  * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
   1356  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   1357  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   1358  * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
   1359  * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
   1360  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   1361  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   1362  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   1363  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
   1364  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
   1365  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   1366  */
   1367 
   1368 #define	USER	05700	/* user's bits */
   1369 #define	GROUP	02070	/* group's bits */
   1370 #define	OTHER	00007	/* other's bits */
   1371 #define	ALL	07777	/* all */
   1372 
   1373 #define	READ	00444	/* read permit */
   1374 #define	WRITE	00222	/* write permit */
   1375 #define	EXEC	00111	/* exec permit */
   1376 #define	SETID	06000	/* set[ug]id */
   1377 #define	STICKY	01000	/* sticky bit */
   1378 
   1379 #ifndef	S_ENFMT
   1380 #define	S_ENFMT	02000	/* mandatory locking bit */
   1381 #endif
   1382 
   1383 static mode_t	absol(const char **);
   1384 static mode_t	who(const char **, mode_t *);
   1385 static int	what(const char **);
   1386 static mode_t	where(const char **, mode_t, int *, int *, const mode_t);
   1387 
   1388 static mode_t
   1389 newmode(const char *ms, const mode_t pm)
   1390 {
   1391 	register mode_t	o, m, b;
   1392 	int	lock, setsgid = 0, cleared = 0, copy = 0;
   1393 	mode_t	nm, om, mm;
   1394 	const char *mo = ms;
   1395 
   1396 	nm = om = pm;
   1397 	m = absol(&ms);
   1398 	if (!*ms) {
   1399 		nm = m;
   1400 		goto out;
   1401 	}
   1402 	if ((lock = (nm&S_IFMT) != S_IFDIR && (nm&(S_ENFMT|S_IXGRP)) == S_ENFMT)
   1403 			== 01)
   1404 		nm &= ~(mode_t)S_ENFMT;
   1405 	do {
   1406 		m = who(&ms, &mm);
   1407 		while (o = what(&ms)) {
   1408 			b = where(&ms, nm, &lock, &copy, pm);
   1409 			switch (o) {
   1410 			case '+':
   1411 				nm |= b & m & ~mm;
   1412 				if (b & S_ISGID)
   1413 					setsgid = 1;
   1414 				if (lock & 04)
   1415 					lock |= 02;
   1416 				break;
   1417 			case '-':
   1418 				nm &= ~(b & m & ~mm);
   1419 				if (b & S_ISGID)
   1420 					setsgid = 1;
   1421 				if (lock & 04)
   1422 					lock = 0;
   1423 				break;
   1424 			case '=':
   1425 				nm &= ~m;
   1426 				nm |= b & m & ~mm;
   1427 				lock &= ~01;
   1428 				if (lock & 04)
   1429 					lock |= 02;
   1430 				om = 0;
   1431 				if (copy == 0)
   1432 					cleared = 1;
   1433 				break;
   1434 			}
   1435 			lock &= ~04;
   1436 		}
   1437 	} while (*ms++ == ',');
   1438 	if (*--ms)
   1439 		er("bad permissions: %s", mo);
   1440 out:	if (pm & S_IFDIR) {
   1441 		if ((pm & S_ISGID) && setsgid == 0)
   1442 			nm |= S_ISGID;
   1443 		else if ((nm & S_ISGID) && setsgid == 0)
   1444 			nm &= ~(mode_t)S_ISGID;
   1445 	}
   1446 	return(nm);
   1447 }
   1448 
   1449 static mode_t
   1450 absol(const char **ms)
   1451 {
   1452 	register int c, i;
   1453 
   1454 	i = 0;
   1455 	while ((c = *(*ms)++) >= '0' && c <= '7')
   1456 		i = (i << 3) + (c - '0');
   1457 	(*ms)--;
   1458 	return(i);
   1459 }
   1460 
   1461 static mode_t
   1462 who(const char **ms, mode_t *mp)
   1463 {
   1464 	register int m;
   1465 
   1466 	m = 0;
   1467 	*mp = 0;
   1468 	for (;;) switch (*(*ms)++) {
   1469 	case 'u':
   1470 		m |= USER;
   1471 		continue;
   1472 	case 'g':
   1473 		m |= GROUP;
   1474 		continue;
   1475 	case 'o':
   1476 		m |= OTHER;
   1477 		continue;
   1478 	case 'a':
   1479 		m |= ALL;
   1480 		continue;
   1481 	default:
   1482 		(*ms)--;
   1483 		if (m == 0) {
   1484 			m = ALL;
   1485 			*mp = um;
   1486 		}
   1487 		return m;
   1488 	}
   1489 }
   1490 
   1491 static int
   1492 what(const char **ms)
   1493 {
   1494 	switch (**ms) {
   1495 	case '+':
   1496 	case '-':
   1497 	case '=':
   1498 		return *(*ms)++;
   1499 	}
   1500 	return(0);
   1501 }
   1502 
   1503 static mode_t
   1504 where(const char **ms, mode_t om, int *lock, int *copy, const mode_t pm)
   1505 {
   1506 	register mode_t m;
   1507 
   1508 	m = 0;
   1509 	*copy = 0;
   1510 	switch (**ms) {
   1511 	case 'u':
   1512 		m = (om & USER) >> 6;
   1513 		goto dup;
   1514 	case 'g':
   1515 		m = (om & GROUP) >> 3;
   1516 		goto dup;
   1517 	case 'o':
   1518 		m = (om & OTHER);
   1519 	dup:
   1520 		*copy = 1;
   1521 		m &= (READ|WRITE|EXEC);
   1522 		m |= (m << 3) | (m << 6);
   1523 		++(*ms);
   1524 		return m;
   1525 	}
   1526 	for (;;) switch (*(*ms)++) {
   1527 	case 'r':
   1528 		m |= READ;
   1529 		continue;
   1530 	case 'w':
   1531 		m |= WRITE;
   1532 		continue;
   1533 	case 'x':
   1534 		m |= EXEC;
   1535 		continue;
   1536 	case 'X':
   1537 		if ((pm&S_IFMT) == S_IFDIR || (pm & EXEC))
   1538 			m |= EXEC;
   1539 		continue;
   1540 	case 'l':
   1541 		if ((pm&S_IFMT) != S_IFDIR)
   1542 			*lock |= 04;
   1543 		continue;
   1544 	case 's':
   1545 		m |= SETID;
   1546 		continue;
   1547 	case 't':
   1548 		m |= STICKY;
   1549 		continue;
   1550 	default:
   1551 		(*ms)--;
   1552 		return m;
   1553 	}
   1554 }