xref: /illumos-gate/usr/src/cmd/find/find.c (revision f3a525d9)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d35170d6Srm  * Common Development and Distribution License (the "License").
6d35170d6Srm  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22ef497ae3SRich Burridge  * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
2303f45afcSYuri Pankov  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
2405f32410SAndy Stormont  * Copyright (c) 2013 Andrew Stormont.  All rights reserved.
25*f3a525d9SJohn Levon  * Copyright 2020 Joyent, Inc.
267c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
3027d3a169SToomas Soome /*	  All Rights Reserved	*/
337c478bd9Sstevel@tonic-gate /*	Parts of this product may be derived from		*/
347c478bd9Sstevel@tonic-gate /*	Mortice Kern Systems Inc. and Berkeley 4.3 BSD systems.	*/
3527d3a169SToomas Soome /*	licensed from  Mortice Kern Systems Inc. and		*/
367c478bd9Sstevel@tonic-gate /*	the University of California.				*/
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * Copyright 1985, 1990 by Mortice Kern Systems Inc.  All rights reserved.
407c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate #include <stdio.h>
437c478bd9Sstevel@tonic-gate #include <errno.h>
447c478bd9Sstevel@tonic-gate #include <pwd.h>
457c478bd9Sstevel@tonic-gate #include <grp.h>
467c478bd9Sstevel@tonic-gate #include <sys/types.h>
477c478bd9Sstevel@tonic-gate #include <sys/stat.h>
487c478bd9Sstevel@tonic-gate #include <sys/param.h>
497c478bd9Sstevel@tonic-gate #include <sys/acl.h>
507c478bd9Sstevel@tonic-gate #include <limits.h>
517c478bd9Sstevel@tonic-gate #include <unistd.h>
527c478bd9Sstevel@tonic-gate #include <stdlib.h>
537c478bd9Sstevel@tonic-gate #include <locale.h>
547c478bd9Sstevel@tonic-gate #include <string.h>
557c478bd9Sstevel@tonic-gate #include <strings.h>
567c478bd9Sstevel@tonic-gate #include <ctype.h>
577c478bd9Sstevel@tonic-gate #include <wait.h>
587c478bd9Sstevel@tonic-gate #include <fnmatch.h>
597c478bd9Sstevel@tonic-gate #include <langinfo.h>
607c478bd9Sstevel@tonic-gate #include <ftw.h>
619ab6dc39Schin #include <libgen.h>
62b34cd89aSYuri Pankov #include <err.h>
63b34cd89aSYuri Pankov #include <regex.h>
643d63ea05Sas #include "getresponse.h"
667c478bd9Sstevel@tonic-gate #define	A_DAY		(long)(60*60*24)	/* a day full of seconds */
67da1a9cbeSjonb #define	A_MIN		(long)(60)
687c478bd9Sstevel@tonic-gate #define	BLKSIZ		512
697c478bd9Sstevel@tonic-gate #define	round(x, s)	(((x)+(s)-1)&~((s)-1))
707c478bd9Sstevel@tonic-gate #ifndef FTW_SLN
717c478bd9Sstevel@tonic-gate #define	FTW_SLN		7
727c478bd9Sstevel@tonic-gate #endif
737c478bd9Sstevel@tonic-gate #define	LINEBUF_SIZE		LINE_MAX	/* input or output lines */
747c478bd9Sstevel@tonic-gate #define	REMOTE_FS		"/etc/dfs/fstypes"
757c478bd9Sstevel@tonic-gate #define	N_FSTYPES		20
76d35170d6Srm #define	SHELL_MAXARGS		253	/* see doexec() for description */
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * This is the list of operations
807c478bd9Sstevel@tonic-gate  * F_USER and F_GROUP are named to avoid conflict with USER and GROUP defined
817c478bd9Sstevel@tonic-gate  * in sys/acl.h
827c478bd9Sstevel@tonic-gate  */
847c478bd9Sstevel@tonic-gate enum Command
857c478bd9Sstevel@tonic-gate {
86b34cd89aSYuri Pankov 	PRINT,
927c478bd9Sstevel@tonic-gate };
947c478bd9Sstevel@tonic-gate enum Type
957c478bd9Sstevel@tonic-gate {
967c478bd9Sstevel@tonic-gate 	Unary, Id, Num, Str, Exec, Cpio, Op
977c478bd9Sstevel@tonic-gate };
997c478bd9Sstevel@tonic-gate struct Args
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	char		name[10];
1027c478bd9Sstevel@tonic-gate 	enum Command	action;
1037c478bd9Sstevel@tonic-gate 	enum Type	type;
1047c478bd9Sstevel@tonic-gate };
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate  * Except for pathnames, these are the only legal arguments
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate static struct Args commands[] =
1107c478bd9Sstevel@tonic-gate {
111b34cd89aSYuri Pankov 	"!",		NOT,		Op,
112b34cd89aSYuri Pankov 	"(",		LPAREN,		Unary,
113b34cd89aSYuri Pankov 	")",		RPAREN,		Unary,
114b34cd89aSYuri Pankov 	"-a",		AND,		Op,
115b34cd89aSYuri Pankov 	"-acl",		ACL,		Unary,
116b34cd89aSYuri Pankov 	"-amin",	AMIN,		Num,
117b34cd89aSYuri Pankov 	"-and",		AND,		Op,
118b34cd89aSYuri Pankov 	"-atime",	ATIME,		Num,
119b34cd89aSYuri Pankov 	"-cmin",	CMIN,		Num,
120b34cd89aSYuri Pankov 	"-cpio",	CPIO,		Cpio,
121b34cd89aSYuri Pankov 	"-ctime",	CTIME,		Num,
122b34cd89aSYuri Pankov 	"-depth",	DEPTH,		Unary,
123ab823b7fSPrasad Joshi 	"-delete",	DELETE,		Unary,
124b34cd89aSYuri Pankov 	"-exec",	EXEC,		Exec,
125b34cd89aSYuri Pankov 	"-follow",	FOLLOW,		Unary,
126b34cd89aSYuri Pankov 	"-fstype",	FSTYPE,		Str,
1277c478bd9Sstevel@tonic-gate 	"-group",	F_GROUP,	Num,
128b34cd89aSYuri Pankov 	"-groupacl",	F_GROUPACL,	Num,
129b34cd89aSYuri Pankov 	"-iname",	INAME,		Str,
130b34cd89aSYuri Pankov 	"-inum",	INUM,		Num,
13105f32410SAndy Stormont 	"-ipath",	IPATH,		Str,
132b34cd89aSYuri Pankov 	"-iregex",	IREGEX,		Str,
13303f45afcSYuri Pankov 	"-links",	LINKS,		Num,
13403f45afcSYuri Pankov 	"-local",	LOCAL,		Unary,
135b34cd89aSYuri Pankov 	"-ls",		LS,		Unary,
136b34cd89aSYuri Pankov 	"-maxdepth",	MAXDEPTH,	Num,
137b34cd89aSYuri Pankov 	"-mindepth",	MINDEPTH,	Num,
138b34cd89aSYuri Pankov 	"-mmin",	MMIN,		Num,
139b34cd89aSYuri Pankov 	"-mount",	MOUNT,		Unary,
140b34cd89aSYuri Pankov 	"-mtime",	MTIME,		Num,
141b34cd89aSYuri Pankov 	"-name",	NAME,		Str,
142b34cd89aSYuri Pankov 	"-ncpio",	NCPIO,		Cpio,
143b34cd89aSYuri Pankov 	"-newer",	NEWER,		Str,
144b34cd89aSYuri Pankov 	"-nogroup",	NOGRP,		Unary,
145b34cd89aSYuri Pankov 	"-not",		NOT,		Op,
146b34cd89aSYuri Pankov 	"-nouser",	NOUSER,		Unary,
147b34cd89aSYuri Pankov 	"-o",		OR,		Op,
148b34cd89aSYuri Pankov 	"-ok",		OK,		Exec,
149b34cd89aSYuri Pankov 	"-or",		OR,		Op,
15005f32410SAndy Stormont 	"-path",	PATH,		Str,
151b34cd89aSYuri Pankov 	"-perm",	PERM,		Num,
152b34cd89aSYuri Pankov 	"-print",	PRINT,		Unary,
153b34cd89aSYuri Pankov 	"-print0",	PRINT0,		Unary,
154b34cd89aSYuri Pankov 	"-prune",	PRUNE,		Unary,
155b34cd89aSYuri Pankov 	"-regex",	REGEX,		Str,
156b34cd89aSYuri Pankov 	"-size",	SIZE,		Num,
157b34cd89aSYuri Pankov 	"-type",	TYPE,		Num,
158b34cd89aSYuri Pankov 	"-user",	F_USER,		Num,
159b34cd89aSYuri Pankov 	"-useracl",	F_USERACL,	Num,
160b34cd89aSYuri Pankov 	"-xattr",	XATTR,		Unary,
161b34cd89aSYuri Pankov 	"-xdev",	MOUNT,		Unary,
16227d3a169SToomas Soome 	0,		0,		0
1637c478bd9Sstevel@tonic-gate };
1657c478bd9Sstevel@tonic-gate union Item
1667c478bd9Sstevel@tonic-gate {
1677c478bd9Sstevel@tonic-gate 	struct Node	*np;
1687c478bd9Sstevel@tonic-gate 	struct Arglist	*vp;
1697c478bd9Sstevel@tonic-gate 	time_t		t;
1707c478bd9Sstevel@tonic-gate 	char		*cp;
1717c478bd9Sstevel@tonic-gate 	char		**ap;
1727c478bd9Sstevel@tonic-gate 	long		l;
1737c478bd9Sstevel@tonic-gate 	int		i;
1747c478bd9Sstevel@tonic-gate 	long long	ll;
1757c478bd9Sstevel@tonic-gate };
1777c478bd9Sstevel@tonic-gate struct Node
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 	struct Node	*next;
1807c478bd9Sstevel@tonic-gate 	enum Command	action;
1817c478bd9Sstevel@tonic-gate 	enum Type	type;
1827c478bd9Sstevel@tonic-gate 	union Item	first;
1837c478bd9Sstevel@tonic-gate 	union Item	second;
1847c478bd9Sstevel@tonic-gate };
1867c478bd9Sstevel@tonic-gate /* if no -print, -exec or -ok replace "expression" with "(expression) -print" */
1877c478bd9Sstevel@tonic-gate static	struct	Node PRINT_NODE = { 0, PRINT, 0, 0};
1887c478bd9Sstevel@tonic-gate static	struct	Node LPAREN_NODE = { 0, LPAREN, 0, 0};
1917c478bd9Sstevel@tonic-gate /*
1927c478bd9Sstevel@tonic-gate  * Prototype variable size arglist buffer
1937c478bd9Sstevel@tonic-gate  */
1957c478bd9Sstevel@tonic-gate struct Arglist
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	struct Arglist	*next;
1987c478bd9Sstevel@tonic-gate 	char		*end;
1997c478bd9Sstevel@tonic-gate 	char		*nextstr;
2007c478bd9Sstevel@tonic-gate 	char		**firstvar;
2017c478bd9Sstevel@tonic-gate 	char		**nextvar;
2027c478bd9Sstevel@tonic-gate 	char		*arglist[1];
2037c478bd9Sstevel@tonic-gate };
20627d3a169SToomas Soome static int		compile(char **, struct Node *, int *);
20727d3a169SToomas Soome static int		execute(const char *, const struct stat *, int,
20827d3a169SToomas Soome     struct FTW *);
20927d3a169SToomas Soome static int		doexec(const char *, char **, int *);
21027d3a169SToomas Soome static int		dodelete(const char *, const struct stat *,
21127d3a169SToomas Soome     struct FTW *);
21227d3a169SToomas Soome static struct Args	*lookup(char *);
21327d3a169SToomas Soome static int		ok(const char *, char *[]);
2146c83d09fSrobbin static void		usage(void)	__NORETURN;
21527d3a169SToomas Soome static struct Arglist	*varargs(char **);
21627d3a169SToomas Soome static int		list(const char *, const struct stat *);
21727d3a169SToomas Soome static char		*getgroup(gid_t);
21827d3a169SToomas Soome static FILE		*cmdopen(char *, char **, char *, FILE *);
21927d3a169SToomas Soome static int		cmdclose(FILE *);
22027d3a169SToomas Soome static char		*getshell(void);
22127d3a169SToomas Soome static void		init_remote_fs(void);
22227d3a169SToomas Soome static char		*getname(uid_t);
22327d3a169SToomas Soome static int		readmode(const char *);
22427d3a169SToomas Soome static mode_t		getmode(mode_t);
22527d3a169SToomas Soome static const char	*gettail(const char *);
22868a94df1Scf static int walkflags = FTW_CHDIR|FTW_PHYS|FTW_ANYERR|FTW_NOLOOP;
2297c478bd9Sstevel@tonic-gate static struct Node	*topnode;
2307c478bd9Sstevel@tonic-gate static struct Node	*freenode;	/* next free node we may use later */
2317c478bd9Sstevel@tonic-gate static char		*cpio[] = { "cpio", "-o", 0 };
2327c478bd9Sstevel@tonic-gate static char		*ncpio[] = { "cpio", "-oc", 0 };
2337c478bd9Sstevel@tonic-gate static char		*cpiol[] = { "cpio", "-oL", 0 };
2347c478bd9Sstevel@tonic-gate static char		*ncpiol[] = { "cpio", "-ocL", 0 };
2357c478bd9Sstevel@tonic-gate static time_t		now;
2367c478bd9Sstevel@tonic-gate static FILE		*output;
2377c478bd9Sstevel@tonic-gate static char		*dummyarg = (char *)-1;
2387c478bd9Sstevel@tonic-gate static int		lastval;
2397c478bd9Sstevel@tonic-gate static int		varsize;
2407c478bd9Sstevel@tonic-gate static struct Arglist	*lastlist;
2417c478bd9Sstevel@tonic-gate static char		*cmdname;
2427c478bd9Sstevel@tonic-gate static char		*remote_fstypes[N_FSTYPES+1];
2437c478bd9Sstevel@tonic-gate static int		fstype_index = 0;
2447c478bd9Sstevel@tonic-gate static int		action_expression = 0;	/* -print, -exec, or -ok */
2457c478bd9Sstevel@tonic-gate static int		error = 0;
2467c478bd9Sstevel@tonic-gate static int		paren_cnt = 0;	/* keeps track of parentheses */
247b34cd89aSYuri Pankov static int		Eflag = 0;
2487c478bd9Sstevel@tonic-gate static int		hflag = 0;
2497c478bd9Sstevel@tonic-gate static int		lflag = 0;
250d35170d6Srm /* set when doexec()-invoked utility returns non-zero */
251d35170d6Srm static int		exec_exitcode = 0;
252b34cd89aSYuri Pankov static regex_t		*preg = NULL;
253b34cd89aSYuri Pankov static int		npreg = 0;
254b34cd89aSYuri Pankov static int		mindepth = -1, maxdepth = -1;
2557c478bd9Sstevel@tonic-gate extern char		**environ;
2577c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)2587c478bd9Sstevel@tonic-gate main(int argc, char **argv)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate 	char *cp;
2617c478bd9Sstevel@tonic-gate 	int c;
2627c478bd9Sstevel@tonic-gate 	int paths;
2637c478bd9Sstevel@tonic-gate 	char *cwdpath;
2657c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2667c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
2677c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
2687c478bd9Sstevel@tonic-gate #endif
2697c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2717c478bd9Sstevel@tonic-gate 	cmdname = argv[0];
2727c478bd9Sstevel@tonic-gate 	if (time(&now) == (time_t)(-1)) {
2737c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: time() %s\n"),
2743d63ea05Sas 		    cmdname, strerror(errno));
2757c478bd9Sstevel@tonic-gate 		exit(1);
2767c478bd9Sstevel@tonic-gate 	}
277b34cd89aSYuri Pankov 	while ((c = getopt(argc, argv, "EHL")) != -1) {
2787c478bd9Sstevel@tonic-gate 		switch (c) {
279b34cd89aSYuri Pankov 		case 'E':
280b34cd89aSYuri Pankov 			Eflag = 1;
281b34cd89aSYuri Pankov 			break;
2827c478bd9Sstevel@tonic-gate 		case 'H':
2837c478bd9Sstevel@tonic-gate 			hflag = 1;
2847c478bd9Sstevel@tonic-gate 			lflag = 0;
2857c478bd9Sstevel@tonic-gate 			break;
2867c478bd9Sstevel@tonic-gate 		case 'L':
2877c478bd9Sstevel@tonic-gate 			hflag = 0;
2887c478bd9Sstevel@tonic-gate 			lflag = 1;
2897c478bd9Sstevel@tonic-gate 			break;
2907c478bd9Sstevel@tonic-gate 		case '?':
2917c478bd9Sstevel@tonic-gate 			usage();
2927c478bd9Sstevel@tonic-gate 			break;
2937c478bd9Sstevel@tonic-gate 		}
2947c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 	argc -= optind;
2977c478bd9Sstevel@tonic-gate 	argv += optind;
2997c478bd9Sstevel@tonic-gate 	if (argc < 1) {
3007c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
3017c478bd9Sstevel@tonic-gate 		    gettext("%s: insufficient number of arguments\n"), cmdname);
3027c478bd9Sstevel@tonic-gate 		usage();
3037c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 	for (paths = 0; (cp = argv[paths]) != 0; ++paths) {
3067c478bd9Sstevel@tonic-gate 		if (*cp == '-')
3077c478bd9Sstevel@tonic-gate 			break;
3087c478bd9Sstevel@tonic-gate 		else if ((*cp == '!' || *cp == '(') && *(cp+1) == 0)
3097c478bd9Sstevel@tonic-gate 			break;
3107c478bd9Sstevel@tonic-gate 	}
3127c478bd9Sstevel@tonic-gate 	if (paths == 0) /* no path-list */
3137c478bd9Sstevel@tonic-gate 		usage();
3157c478bd9Sstevel@tonic-gate 	output = stdout;
3177c478bd9Sstevel@tonic-gate 	/* lflag is the same as -follow */
3187c478bd9Sstevel@tonic-gate 	if (lflag)
3197c478bd9Sstevel@tonic-gate 		walkflags &= ~FTW_PHYS;
3217c478bd9Sstevel@tonic-gate 	/* allocate enough space for the compiler */
3227c478bd9Sstevel@tonic-gate 	topnode = malloc((argc + 1) * sizeof (struct Node));
3237c478bd9Sstevel@tonic-gate 	(void) memset(topnode, 0, (argc + 1) * sizeof (struct Node));
3257c478bd9Sstevel@tonic-gate 	if (compile(argv + paths, topnode, &action_expression) == 0) {
3267c478bd9Sstevel@tonic-gate 		/* no expression, default to -print */
3277c478bd9Sstevel@tonic-gate 		(void) memcpy(topnode, &PRINT_NODE, sizeof (struct Node));
3287c478bd9Sstevel@tonic-gate 	} else if (!action_expression) {
3297c478bd9Sstevel@tonic-gate 		/*
3307c478bd9Sstevel@tonic-gate 		 * if no action expression, insert an LPAREN node above topnode,
3317c478bd9Sstevel@tonic-gate 		 * with a PRINT node as its next node
3327c478bd9Sstevel@tonic-gate 		 */
3337c478bd9Sstevel@tonic-gate 		struct Node *savenode;
3357c478bd9Sstevel@tonic-gate 		if (freenode == NULL) {
3367c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: can't append -print"
3373d63ea05Sas 			    " implicitly; try explicit -print option\n"),
3383d63ea05Sas 			    cmdname);
3397c478bd9Sstevel@tonic-gate 			exit(1);
3407c478bd9Sstevel@tonic-gate 		}
3417c478bd9Sstevel@tonic-gate 		savenode = topnode;
3427c478bd9Sstevel@tonic-gate 		topnode = freenode++;
3437c478bd9Sstevel@tonic-gate 		(void) memcpy(topnode, &LPAREN_NODE, sizeof (struct Node));
3447c478bd9Sstevel@tonic-gate 		topnode->next = freenode;
3457c478bd9Sstevel@tonic-gate 		topnode->first.np = savenode;
3467c478bd9Sstevel@tonic-gate 		(void) memcpy(topnode->next, &PRINT_NODE, sizeof (struct Node));
3477c478bd9Sstevel@tonic-gate 	}
3497c478bd9Sstevel@tonic-gate 	while (paths--) {
3507c478bd9Sstevel@tonic-gate 		char *curpath;
3517c478bd9Sstevel@tonic-gate 		struct stat sb;
3537c478bd9Sstevel@tonic-gate 		curpath = *(argv++);
3557c478bd9Sstevel@tonic-gate 		/*
3567c478bd9Sstevel@tonic-gate 		 * If -H is specified, it means we walk the first
3577c478bd9Sstevel@tonic-gate 		 * level (pathname on command line) logically, following
3587c478bd9Sstevel@tonic-gate 		 * symlinks, but lower levels are walked physically.
3597c478bd9Sstevel@tonic-gate 		 * We use our own secret interface to nftw() to change
3607c478bd9Sstevel@tonic-gate 		 * the from stat to lstat after the top level is walked.
3617c478bd9Sstevel@tonic-gate 		 */
3627c478bd9Sstevel@tonic-gate 		if (hflag) {
3637c478bd9Sstevel@tonic-gate 			if (stat(curpath, &sb) < 0 && errno == ENOENT)
3647c478bd9Sstevel@tonic-gate 				walkflags &= ~FTW_HOPTION;
3657c478bd9Sstevel@tonic-gate 			else
3667c478bd9Sstevel@tonic-gate 				walkflags |= FTW_HOPTION;
3677c478bd9Sstevel@tonic-gate 		}
3697c478bd9Sstevel@tonic-gate 		/*
3707c478bd9Sstevel@tonic-gate 		 * We need this check as nftw needs a CWD and we have no
3717c478bd9Sstevel@tonic-gate 		 * way of returning back from that code with a meaningful
3727c478bd9Sstevel@tonic-gate 		 * error related to this
3737c478bd9Sstevel@tonic-gate 		 */
3747c478bd9Sstevel@tonic-gate 		if ((cwdpath = getcwd(NULL, PATH_MAX)) == NULL) {
3754b808d43SRich Burridge 			if ((errno == EACCES) && (walkflags & FTW_CHDIR)) {
3764b808d43SRich Burridge 				/*
3774b808d43SRich Burridge 				 * A directory above cwd is inaccessible,
3784b808d43SRich Burridge 				 * so don't do chdir(2)s. Slower, but at least
3794b808d43SRich Burridge 				 * it works.
3804b808d43SRich Burridge 				 */
3814b808d43SRich Burridge 				walkflags &= ~FTW_CHDIR;
3824b808d43SRich Burridge 				free(cwdpath);
3834b808d43SRich Burridge 			} else {
3844b808d43SRich Burridge 				(void) fprintf(stderr,
3854b808d43SRich Burridge 				    gettext("%s : cannot get the current "
3864b808d43SRich Burridge 				    "working directory\n"), cmdname);
3874b808d43SRich Burridge 				exit(1);
3884b808d43SRich Burridge 			}
3897c478bd9Sstevel@tonic-gate 		} else
3907c478bd9Sstevel@tonic-gate 			free(cwdpath);
3937c478bd9Sstevel@tonic-gate 		if (nftw(curpath, execute, 1000, walkflags)) {
3947c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
3957c478bd9Sstevel@tonic-gate 			    gettext("%s: cannot open %s: %s\n"),
3967c478bd9Sstevel@tonic-gate 			    cmdname, curpath, strerror(errno));
3977c478bd9Sstevel@tonic-gate 			error = 1;
3987c478bd9Sstevel@tonic-gate 		}
4007c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 	/* execute any remaining variable length lists */
4037c478bd9Sstevel@tonic-gate 	while (lastlist) {
4047c478bd9Sstevel@tonic-gate 		if (lastlist->end != lastlist->nextstr) {
4057c478bd9Sstevel@tonic-gate 			*lastlist->nextvar = 0;
40627d3a169SToomas Soome 			(void) doexec(NULL, lastlist->arglist,
407d35170d6Srm 			    &exec_exitcode);
4087c478bd9Sstevel@tonic-gate 		}
4097c478bd9Sstevel@tonic-gate 		lastlist = lastlist->next;
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 	if (output != stdout)
4127c478bd9Sstevel@tonic-gate 		return (cmdclose(output));
413d35170d6Srm 	return ((exec_exitcode != 0) ? exec_exitcode : error);
4147c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate  * compile the arguments
4187c478bd9Sstevel@tonic-gate  */
4207c478bd9Sstevel@tonic-gate static int
compile(char ** argv,struct Node * np,int * actionp)42127d3a169SToomas Soome compile(char **argv, struct Node *np, int *actionp)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	char *b;
4247c478bd9Sstevel@tonic-gate 	char **av;
4257c478bd9Sstevel@tonic-gate 	struct Node *oldnp = topnode;
4267c478bd9Sstevel@tonic-gate 	struct Args *argp;
4277c478bd9Sstevel@tonic-gate 	char **com;
4287c478bd9Sstevel@tonic-gate 	int i;
4297c478bd9Sstevel@tonic-gate 	enum Command wasop = PRINT;
4313d63ea05Sas 	if (init_yes() < 0) {
4323d63ea05Sas 		(void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
4333d63ea05Sas 		    strerror(errno));
4343d63ea05Sas 		exit(1);
4353d63ea05Sas 	}
4377c478bd9Sstevel@tonic-gate 	for (av = argv; *av && (argp = lookup(*av)); av++) {
4387c478bd9Sstevel@tonic-gate 		np->next = 0;
4397c478bd9Sstevel@tonic-gate 		np->action = argp->action;
4407c478bd9Sstevel@tonic-gate 		np->type = argp->type;
4417c478bd9Sstevel@tonic-gate 		np->second.i = 0;
4427c478bd9Sstevel@tonic-gate 		if (argp->type == Op) {
4437c478bd9Sstevel@tonic-gate 			if (wasop == NOT || (wasop && np->action != NOT)) {
4447c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
44527d3a169SToomas Soome 				    gettext("%s: operand follows operand\n"),
44627d3a169SToomas Soome 				    cmdname);
4477c478bd9Sstevel@tonic-gate 				exit(1);
4487c478bd9Sstevel@tonic-gate 			}
4497c478bd9Sstevel@tonic-gate 			if (np->action != NOT && oldnp == 0)
4507c478bd9Sstevel@tonic-gate 				goto err;
4517c478bd9Sstevel@tonic-gate 			wasop = argp->action;
4527c478bd9Sstevel@tonic-gate 		} else {
4537c478bd9Sstevel@tonic-gate 			wasop = PRINT;
4547c478bd9Sstevel@tonic-gate 			if (argp->type != Unary) {
4557c478bd9Sstevel@tonic-gate 				if (!(b = *++av)) {
45627d3a169SToomas Soome 					(void) fprintf(stderr, gettext(
45727d3a169SToomas Soome 					    "%s: incomplete statement\n"),
45827d3a169SToomas Soome 					    cmdname);
4597c478bd9Sstevel@tonic-gate 					exit(1);
4607c478bd9Sstevel@tonic-gate 				}
4617c478bd9Sstevel@tonic-gate 				if (argp->type == Num) {
462b34cd89aSYuri Pankov 					if (((argp->action == MAXDEPTH) ||
463b34cd89aSYuri Pankov 					    (argp->action == MINDEPTH)) &&
464b34cd89aSYuri Pankov 					    ((int)strtol(b, (char **)NULL,
465b34cd89aSYuri Pankov 					    10) < 0))
46627d3a169SToomas Soome 						errx(1, gettext(
46727d3a169SToomas Soome 						    "%s: value must be "
46827d3a169SToomas Soome 						    "positive"),
469b34cd89aSYuri Pankov 						    (argp->action == MAXDEPTH) ?
470b34cd89aSYuri Pankov 						    "maxdepth" : "mindepth");
4717c478bd9Sstevel@tonic-gate 					if ((argp->action != PERM) ||
4727c478bd9Sstevel@tonic-gate 					    (*b != '+')) {
4737c478bd9Sstevel@tonic-gate 						if (*b == '+' || *b == '-') {
4747c478bd9Sstevel@tonic-gate 							np->second.i = *b;
4757c478bd9Sstevel@tonic-gate 							b++;
4767c478bd9Sstevel@tonic-gate 						}
4777c478bd9Sstevel@tonic-gate 					}
4787c478bd9Sstevel@tonic-gate 				}
4797c478bd9Sstevel@tonic-gate 			}
4807c478bd9Sstevel@tonic-gate 		}
4817c478bd9Sstevel@tonic-gate 		switch (argp->action) {
4827c478bd9Sstevel@tonic-gate 		case AND:
4837c478bd9Sstevel@tonic-gate 			break;
4847c478bd9Sstevel@tonic-gate 		case NOT:
4857c478bd9Sstevel@tonic-gate 			break;
4867c478bd9Sstevel@tonic-gate 		case OR:
4877c478bd9Sstevel@tonic-gate 			np->first.np = topnode;
4887c478bd9Sstevel@tonic-gate 			topnode = np;
4897c478bd9Sstevel@tonic-gate 			oldnp->next = 0;
4907c478bd9Sstevel@tonic-gate 			break;
4927c478bd9Sstevel@tonic-gate 		case LPAREN: {
4937c478bd9Sstevel@tonic-gate 			struct Node *save = topnode;
4947c478bd9Sstevel@tonic-gate 			topnode = np+1;
4957c478bd9Sstevel@tonic-gate 			paren_cnt++;
4967c478bd9Sstevel@tonic-gate 			i = compile(++av, topnode, actionp);
4977c478bd9Sstevel@tonic-gate 			np->first.np = topnode;
4987c478bd9Sstevel@tonic-gate 			topnode = save;
4997c478bd9Sstevel@tonic-gate 			av += i;
5007c478bd9Sstevel@tonic-gate 			oldnp = np;
5017c478bd9Sstevel@tonic-gate 			np += i + 1;
5027c478bd9Sstevel@tonic-gate 			oldnp->next = np;
5037c478bd9Sstevel@tonic-gate 			continue;
5047c478bd9Sstevel@tonic-gate 		}
5067c478bd9Sstevel@tonic-gate 		case RPAREN:
5077c478bd9Sstevel@tonic-gate 			if (paren_cnt <= 0) {
5087c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
5097c478bd9Sstevel@tonic-gate 				    gettext("%s: unmatched ')'\n"),
5107c478bd9Sstevel@tonic-gate 				    cmdname);
5117c478bd9Sstevel@tonic-gate 				exit(1);
5127c478bd9Sstevel@tonic-gate 			}
5137c478bd9Sstevel@tonic-gate 			paren_cnt--;
5147c478bd9Sstevel@tonic-gate 			if (oldnp == 0)
5157c478bd9Sstevel@tonic-gate 				goto err;
5167c478bd9Sstevel@tonic-gate 			if (oldnp->type == Op) {
5177c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
5187c478bd9Sstevel@tonic-gate 				    gettext("%s: cannot immediately"
5197c478bd9Sstevel@tonic-gate 				    " follow an operand with ')'\n"),
5207c478bd9Sstevel@tonic-gate 				    cmdname);
5217c478bd9Sstevel@tonic-gate 				exit(1);
5227c478bd9Sstevel@tonic-gate 			}
5237c478bd9Sstevel@tonic-gate 			oldnp->next = 0;
5247c478bd9Sstevel@tonic-gate 			return (av-argv);
5267c478bd9Sstevel@tonic-gate 		case FOLLOW:
5277c478bd9Sstevel@tonic-gate 			walkflags &= ~FTW_PHYS;
5287c478bd9Sstevel@tonic-gate 			break;
5297c478bd9Sstevel@tonic-gate 		case MOUNT:
5307c478bd9Sstevel@tonic-gate 			walkflags |= FTW_MOUNT;
5317c478bd9Sstevel@tonic-gate 			break;
5327c478bd9Sstevel@tonic-gate 		case DEPTH:
5337c478bd9Sstevel@tonic-gate 			walkflags |= FTW_DEPTH;
5347c478bd9Sstevel@tonic-gate 			break;
535ab823b7fSPrasad Joshi 		case DELETE:
536ab823b7fSPrasad Joshi 			walkflags |= (FTW_DEPTH | FTW_PHYS);
537ab823b7fSPrasad Joshi 			walkflags &= ~FTW_CHDIR;
538ab823b7fSPrasad Joshi 			(*actionp)++;
539ab823b7fSPrasad Joshi 			break;
5417c478bd9Sstevel@tonic-gate 		case LOCAL:
5427c478bd9Sstevel@tonic-gate 			np->first.l = 0L;
5437c478bd9Sstevel@tonic-gate 			np->first.ll = 0LL;
5447c478bd9Sstevel@tonic-gate 			np->second.i = '+';
5457c478bd9Sstevel@tonic-gate 			/*
5467c478bd9Sstevel@tonic-gate 			 * Make it compatible to df -l for
5477c478bd9Sstevel@tonic-gate 			 * future enhancement. So, anything
5487c478bd9Sstevel@tonic-gate 			 * that is not remote, then it is
5497c478bd9Sstevel@tonic-gate 			 * local.
5507c478bd9Sstevel@tonic-gate 			 */
5517c478bd9Sstevel@tonic-gate 			init_remote_fs();
5527c478bd9Sstevel@tonic-gate 			break;
5547c478bd9Sstevel@tonic-gate 		case SIZE:
5557c478bd9Sstevel@tonic-gate 			if (b[strlen(b)-1] == 'c')
5567c478bd9Sstevel@tonic-gate 				np->action = CSIZE;
5577c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
5587c478bd9Sstevel@tonic-gate 		case INUM:
5597c478bd9Sstevel@tonic-gate 			np->first.ll = atoll(b);
5607c478bd9Sstevel@tonic-gate 			break;
562da1a9cbeSjonb 		case CMIN:
5637c478bd9Sstevel@tonic-gate 		case CTIME:
564da1a9cbeSjonb 		case MMIN:
5657c478bd9Sstevel@tonic-gate 		case MTIME:
566da1a9cbeSjonb 		case AMIN:
5677c478bd9Sstevel@tonic-gate 		case ATIME:
5687c478bd9Sstevel@tonic-gate 		case LINKS:
5697c478bd9Sstevel@tonic-gate 			np->first.l = atol(b);
5707c478bd9Sstevel@tonic-gate 			break;
5727c478bd9Sstevel@tonic-gate 		case F_USER:
573b34cd89aSYuri Pankov 		case F_GROUP:
574b34cd89aSYuri Pankov 		case F_USERACL:
575b34cd89aSYuri Pankov 		case F_GROUPACL: {
5767c478bd9Sstevel@tonic-gate 			struct	passwd	*pw;
5777c478bd9Sstevel@tonic-gate 			struct	group *gr;
578ef497ae3SRich Burridge 			long value;
579ef497ae3SRich Burridge 			char *q;
580ef497ae3SRich Burridge 
581ef497ae3SRich Burridge 			value = -1;
582b34cd89aSYuri Pankov 			if (argp->action == F_USER ||
583b34cd89aSYuri Pankov 			    argp->action == F_USERACL) {
5847c478bd9Sstevel@tonic-gate 				if ((pw = getpwnam(b)) != 0)
585ef497ae3SRich Burridge 					value = (long)pw->pw_uid;
5867c478bd9Sstevel@tonic-gate 			} else {
5877c478bd9Sstevel@tonic-gate 				if ((gr = getgrnam(b)) != 0)
588ef497ae3SRich Burridge 					value = (long)gr->gr_gid;
5897c478bd9Sstevel@tonic-gate 			}
590ef497ae3SRich Burridge 			if (value == -1) {
591ef497ae3SRich Burridge 				errno = 0;
592ef497ae3SRich Burridge 				value = strtol(b, &q, 10);
593ef497ae3SRich Burridge 				if (errno != 0 || q == b || *q != '\0') {
5947c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
5957c478bd9Sstevel@tonic-gate 					    "%s: cannot find %s name\n"),
59627d3a169SToomas Soome 					    cmdname, *av);
5977c478bd9Sstevel@tonic-gate 					exit(1);
5987c478bd9Sstevel@tonic-gate 				}
5997c478bd9Sstevel@tonic-gate 			}
600ef497ae3SRich Burridge 			np->first.l = value;
6017c478bd9Sstevel@tonic-gate 			break;
6027c478bd9Sstevel@tonic-gate 		}
6047c478bd9Sstevel@tonic-gate 		case EXEC:
6057c478bd9Sstevel@tonic-gate 		case OK:
6067c478bd9Sstevel@tonic-gate 			walkflags &= ~FTW_CHDIR;
6077c478bd9Sstevel@tonic-gate 			np->first.ap = av;
6087c478bd9Sstevel@tonic-gate 			(*actionp)++;
6097c478bd9Sstevel@tonic-gate 			for (;;) {
6107c478bd9Sstevel@tonic-gate 				if ((b = *av) == 0) {
61127d3a169SToomas Soome 					(void) fprintf(stderr, gettext(
61227d3a169SToomas Soome 					    "%s: incomplete statement\n"),
61327d3a169SToomas Soome 					    cmdname);
6147c478bd9Sstevel@tonic-gate 					exit(1);
6157c478bd9Sstevel@tonic-gate 				}
6167c478bd9Sstevel@tonic-gate 				if (strcmp(b, ";") == 0) {
6177c478bd9Sstevel@tonic-gate 					*av = 0;
6187c478bd9Sstevel@tonic-gate 					break;
6197c478bd9Sstevel@tonic-gate 				} else if (strcmp(b, "{}") == 0)
6207c478bd9Sstevel@tonic-gate 					*av = dummyarg;
6217c478bd9Sstevel@tonic-gate 				else if (strcmp(b, "+") == 0 &&
62227d3a169SToomas Soome 				    av[-1] == dummyarg && np->action == EXEC) {
6237c478bd9Sstevel@tonic-gate 					av[-1] = 0;
6247c478bd9Sstevel@tonic-gate 					np->first.vp = varargs(np->first.ap);
6257c478bd9Sstevel@tonic-gate 					np->action = VARARGS;
6267c478bd9Sstevel@tonic-gate 					break;
6277c478bd9Sstevel@tonic-gate 				}
6287c478bd9Sstevel@tonic-gate 				av++;
6297c478bd9Sstevel@tonic-gate 			}
6307c478bd9Sstevel@tonic-gate 			break;
6327c478bd9Sstevel@tonic-gate 		case NAME:
633b34cd89aSYuri Pankov 		case INAME:
63405f32410SAndy Stormont 		case PATH:
63505f32410SAndy Stormont 		case IPATH:
6367c478bd9Sstevel@tonic-gate 			np->first.cp = b;
6377c478bd9Sstevel@tonic-gate 			break;
638b34cd89aSYuri Pankov 		case REGEX:
639b34cd89aSYuri Pankov 		case IREGEX: {
640b34cd89aSYuri Pankov 			int error;
641b34cd89aSYuri Pankov 			size_t errlen;
642b34cd89aSYuri Pankov 			char *errmsg;
643b34cd89aSYuri Pankov 
644b34cd89aSYuri Pankov 			if ((preg = realloc(preg, (npreg + 1) *
645b34cd89aSYuri Pankov 			    sizeof (regex_t))) == NULL)
646b34cd89aSYuri Pankov 				err(1, "realloc");
647b34cd89aSYuri Pankov 			if ((error = regcomp(&preg[npreg], b,
648b34cd89aSYuri Pankov 			    ((np->action == IREGEX) ? REG_ICASE : 0) |
649b34cd89aSYuri Pankov 			    ((Eflag) ? REG_EXTENDED : 0))) != 0) {
650b34cd89aSYuri Pankov 				errlen = regerror(error, &preg[npreg], NULL, 0);
651b34cd89aSYuri Pankov 				if ((errmsg = malloc(errlen)) == NULL)
652b34cd89aSYuri Pankov 					err(1, "malloc");
653b34cd89aSYuri Pankov 				(void) regerror(error, &preg[npreg], errmsg,
654b34cd89aSYuri Pankov 				    errlen);
655b34cd89aSYuri Pankov 				errx(1, gettext("RE error: %s"), errmsg);
656b34cd89aSYuri Pankov 			}
657b34cd89aSYuri Pankov 			npreg++;
658b34cd89aSYuri Pankov 			break;
659b34cd89aSYuri Pankov 		}
6607c478bd9Sstevel@tonic-gate 		case PERM:
6617c478bd9Sstevel@tonic-gate 			if (*b == '-')
6627c478bd9Sstevel@tonic-gate 				++b;
66427d3a169SToomas Soome 			if (readmode(b) != 0) {
6657c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
6667c478bd9Sstevel@tonic-gate 				    "find: -perm: Bad permission string\n"));
6677c478bd9Sstevel@tonic-gate 				usage();
6687c478bd9Sstevel@tonic-gate 			}
6697c478bd9Sstevel@tonic-gate 			np->first.l = (long)getmode((mode_t)0);
6707c478bd9Sstevel@tonic-gate 			break;
6717c478bd9Sstevel@tonic-gate 		case TYPE:
6727c478bd9Sstevel@tonic-gate 			i = *b;
6737c478bd9Sstevel@tonic-gate 			np->first.l =
6747c478bd9Sstevel@tonic-gate 			    i == 'd' ? S_IFDIR :
6757c478bd9Sstevel@tonic-gate 			    i == 'b' ? S_IFBLK :
6767c478bd9Sstevel@tonic-gate 			    i == 'c' ? S_IFCHR :
6777c478bd9Sstevel@tonic-gate #ifdef S_IFIFO
6787c478bd9Sstevel@tonic-gate 			    i == 'p' ? S_IFIFO :
6797c478bd9Sstevel@tonic-gate #endif
6807c478bd9Sstevel@tonic-gate 			    i == 'f' ? S_IFREG :
6817c478bd9Sstevel@tonic-gate #ifdef S_IFLNK
6827c478bd9Sstevel@tonic-gate 			    i == 'l' ? S_IFLNK :
6837c478bd9Sstevel@tonic-gate #endif
6847c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK
6857c478bd9Sstevel@tonic-gate 			    i == 's' ? S_IFSOCK :
6867c478bd9Sstevel@tonic-gate #endif
6877c478bd9Sstevel@tonic-gate #ifdef S_IFDOOR
6887c478bd9Sstevel@tonic-gate 			    i == 'D' ? S_IFDOOR :
6897c478bd9Sstevel@tonic-gate #endif
6907c478bd9Sstevel@tonic-gate 			    0;
6917c478bd9Sstevel@tonic-gate 			break;
6937c478bd9Sstevel@tonic-gate 		case CPIO:
6947c478bd9Sstevel@tonic-gate 			if (walkflags & FTW_PHYS)
6957c478bd9Sstevel@tonic-gate 				com = cpio;
6967c478bd9Sstevel@tonic-gate 			else
6977c478bd9Sstevel@tonic-gate 				com = cpiol;
6987c478bd9Sstevel@tonic-gate 			goto common;
7007c478bd9Sstevel@tonic-gate 		case NCPIO: {
7017c478bd9Sstevel@tonic-gate 			FILE *fd;
7037c478bd9Sstevel@tonic-gate 			if (walkflags & FTW_PHYS)
7047c478bd9Sstevel@tonic-gate 				com = ncpio;
7057c478bd9Sstevel@tonic-gate 			else
7067c478bd9Sstevel@tonic-gate 				com = ncpiol;
7077c478bd9Sstevel@tonic-gate 		common:
7087c478bd9Sstevel@tonic-gate 			/* set up cpio */
7097c478bd9Sstevel@tonic-gate 			if ((fd = fopen(b, "w")) == NULL) {
7107c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
71127d3a169SToomas Soome 				    gettext("%s: cannot create %s\n"),
71227d3a169SToomas Soome 				    cmdname, b);
7137c478bd9Sstevel@tonic-gate 				exit(1);
7147c478bd9Sstevel@tonic-gate 			}
7167c478bd9Sstevel@tonic-gate 			np->first.l = (long)cmdopen("cpio", com, "w", fd);
7177c478bd9Sstevel@tonic-gate 			(void) fclose(fd);
7187c478bd9Sstevel@tonic-gate 			walkflags |= FTW_DEPTH;
7197c478bd9Sstevel@tonic-gate 			np->action = CPIO;
7207c478bd9Sstevel@tonic-gate 		}
7217c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
7227c478bd9Sstevel@tonic-gate 		case PRINT:
723b34cd89aSYuri Pankov 		case PRINT0:
7247c478bd9Sstevel@tonic-gate 			(*actionp)++;
7257c478bd9Sstevel@tonic-gate 			break;
7277c478bd9Sstevel@tonic-gate 		case NEWER: {
7287c478bd9Sstevel@tonic-gate 			struct stat statb;
7297c478bd9Sstevel@tonic-gate 			if (stat(b, &statb) < 0) {
7307c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
73127d3a169SToomas Soome 				    gettext("%s: cannot access %s\n"),
73227d3a169SToomas Soome 				    cmdname, b);
7337c478bd9Sstevel@tonic-gate 				exit(1);
7347c478bd9Sstevel@tonic-gate 			}
7357c478bd9Sstevel@tonic-gate 			np->first.l = statb.st_mtime;
7367c478bd9Sstevel@tonic-gate 			np->second.i = '+';
7377c478bd9Sstevel@tonic-gate 			break;
7387c478bd9Sstevel@tonic-gate 		}
7407c478bd9Sstevel@tonic-gate 		case PRUNE:
7417c478bd9Sstevel@tonic-gate 		case NOUSER:
7427c478bd9Sstevel@tonic-gate 		case NOGRP:
7437c478bd9Sstevel@tonic-gate 			break;
7447c478bd9Sstevel@tonic-gate 		case FSTYPE:
7457c478bd9Sstevel@tonic-gate 			np->first.cp = b;
7467c478bd9Sstevel@tonic-gate 			break;
7477c478bd9Sstevel@tonic-gate 		case LS:
7487c478bd9Sstevel@tonic-gate 			(*actionp)++;
7497c478bd9Sstevel@tonic-gate 			break;
7507c478bd9Sstevel@tonic-gate 		case XATTR:
7517c478bd9Sstevel@tonic-gate 			break;
7527c478bd9Sstevel@tonic-gate 		case ACL:
7537c478bd9Sstevel@tonic-gate 			break;
754b34cd89aSYuri Pankov 		case MAXDEPTH:
75527d3a169SToomas Soome 			maxdepth = (int)strtol(b, NULL, 10);
756b34cd89aSYuri Pankov 			break;
757b34cd89aSYuri Pankov 		case MINDEPTH:
75827d3a169SToomas Soome 			mindepth = (int)strtol(b, NULL, 10);
759b34cd89aSYuri Pankov 			break;
7607c478bd9Sstevel@tonic-gate 		}
7627c478bd9Sstevel@tonic-gate 		oldnp = np++;
7637c478bd9Sstevel@tonic-gate 		oldnp->next = np;
7647c478bd9Sstevel@tonic-gate 	}
7667c478bd9Sstevel@tonic-gate 	if ((*av) || (wasop))
7677c478bd9Sstevel@tonic-gate 		goto err;
7697c478bd9Sstevel@tonic-gate 	if (paren_cnt != 0) {
77027d3a169SToomas Soome 		(void) fprintf(stderr, gettext("%s: unmatched '('\n"), cmdname);
7717c478bd9Sstevel@tonic-gate 		exit(1);
7727c478bd9Sstevel@tonic-gate 	}
7747c478bd9Sstevel@tonic-gate 	/* just before returning, save next free node from the list */
7757c478bd9Sstevel@tonic-gate 	freenode = oldnp->next;
7767c478bd9Sstevel@tonic-gate 	oldnp->next = 0;
7777c478bd9Sstevel@tonic-gate 	return (av-argv);
7787c478bd9Sstevel@tonic-gate err:
7797c478bd9Sstevel@tonic-gate 	if (*av)
7807c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7817c478bd9Sstevel@tonic-gate 		    gettext("%s: bad option %s\n"), cmdname, *av);
7827c478bd9Sstevel@tonic-gate 	else
7837c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: bad option\n"), cmdname);
7847c478bd9Sstevel@tonic-gate 	usage();
7857c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
7867c478bd9Sstevel@tonic-gate }
7887c478bd9Sstevel@tonic-gate /*
7897c478bd9Sstevel@tonic-gate  * print out a usage message
7907c478bd9Sstevel@tonic-gate  */
7927c478bd9Sstevel@tonic-gate static void
usage(void)7936c83d09fSrobbin usage(void)
7947c478bd9Sstevel@tonic-gate {
7957c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
796b34cd89aSYuri Pankov 	    gettext("%s: [-E] [-H | -L] path-list predicate-list\n"), cmdname);
7977c478bd9Sstevel@tonic-gate 	exit(1);
7987c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate /*
8017c478bd9Sstevel@tonic-gate  * This is the function that gets executed at each node
8027c478bd9Sstevel@tonic-gate  */
8047c478bd9Sstevel@tonic-gate static int
execute(const char * name,const struct stat * statb,int type,struct FTW * state)80527d3a169SToomas Soome execute(const char *name, const struct stat *statb, int type, struct FTW *state)
8067c478bd9Sstevel@tonic-gate {
8077c478bd9Sstevel@tonic-gate 	struct Node *np = topnode;
8087c478bd9Sstevel@tonic-gate 	int val;
8097c478bd9Sstevel@tonic-gate 	time_t t;
8107c478bd9Sstevel@tonic-gate 	long l;
8117c478bd9Sstevel@tonic-gate 	long long ll;
8127c478bd9Sstevel@tonic-gate 	int not = 1;
81327d3a169SToomas Soome 	const char *filename;
814b34cd89aSYuri Pankov 	int cnpreg = 0;
8167c478bd9Sstevel@tonic-gate 	if (type == FTW_NS) {
8177c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: stat() error %s: %s\n"),
81827d3a169SToomas Soome 		    cmdname, name, strerror(errno));
8197c478bd9Sstevel@tonic-gate 		error = 1;
8207c478bd9Sstevel@tonic-gate 		return (0);
8217c478bd9Sstevel@tonic-gate 	} else if (type == FTW_DNR) {
8227c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: cannot read dir %s: %s\n"),
82327d3a169SToomas Soome 		    cmdname, name, strerror(errno));
8247c478bd9Sstevel@tonic-gate 		error = 1;
8250729abfeSRich Burridge 	} else if (type == FTW_SLN && lflag == 1) {
8267c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
82727d3a169SToomas Soome 		    gettext("%s: cannot follow symbolic link %s: %s\n"),
82827d3a169SToomas Soome 		    cmdname, name, strerror(errno));
8297c478bd9Sstevel@tonic-gate 		error = 1;
83068a94df1Scf 	} else if (type == FTW_DL) {
83168a94df1Scf 		(void) fprintf(stderr, gettext("%s: cycle detected for %s\n"),
83227d3a169SToomas Soome 		    cmdname, name);
83368a94df1Scf 		error = 1;
83468a94df1Scf 		return (0);
8357c478bd9Sstevel@tonic-gate 	}
837b34cd89aSYuri Pankov 	if ((maxdepth != -1 && state->level > maxdepth) ||
838b34cd89aSYuri Pankov 	    (mindepth != -1 && state->level < mindepth))
839b34cd89aSYuri Pankov 		return (0);
840b34cd89aSYuri Pankov 
8417c478bd9Sstevel@tonic-gate 	while (np) {
8427c478bd9Sstevel@tonic-gate 		switch (np->action) {
8437c478bd9Sstevel@tonic-gate 		case NOT:
8447c478bd9Sstevel@tonic-gate 			not = !not;
8457c478bd9Sstevel@tonic-gate 			np = np->next;
8467c478bd9Sstevel@tonic-gate 			continue;
8487c478bd9Sstevel@tonic-gate 		case AND:
8497c478bd9Sstevel@tonic-gate 			np = np->next;
8507c478bd9Sstevel@tonic-gate 			continue;
8527c478bd9Sstevel@tonic-gate 		case OR:
8537c478bd9Sstevel@tonic-gate 			if (np->first.np == np) {
8547c478bd9Sstevel@tonic-gate 				/*
8557c478bd9Sstevel@tonic-gate 				 * handle naked OR (no term on left hand side)
8567c478bd9Sstevel@tonic-gate 				 */
8577c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
8587c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid -o construction\n"),
8597c478bd9Sstevel@tonic-gate 				    cmdname);
8607c478bd9Sstevel@tonic-gate 				exit(2);
8617c478bd9Sstevel@tonic-gate 			}
8627c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
8637c478bd9Sstevel@tonic-gate 		case LPAREN: {
8647c478bd9Sstevel@tonic-gate 			struct Node *save = topnode;
8657c478bd9Sstevel@tonic-gate 			topnode = np->first.np;
8667c478bd9Sstevel@tonic-gate 			(void) execute(name, statb, type, state);
8677c478bd9Sstevel@tonic-gate 			val = lastval;
8687c478bd9Sstevel@tonic-gate 			topnode = save;
8697c478bd9Sstevel@tonic-gate 			if (np->action == OR) {
8707c478bd9Sstevel@tonic-gate 				if (val)
8717c478bd9Sstevel@tonic-gate 					return (0);
8727c478bd9Sstevel@tonic-gate 				val = 1;
8737c478bd9Sstevel@tonic-gate 			}
8747c478bd9Sstevel@tonic-gate 			break;
8757c478bd9Sstevel@tonic-gate 		}
8777c478bd9Sstevel@tonic-gate 		case LOCAL: {
8787c478bd9Sstevel@tonic-gate 			int	nremfs;
8797c478bd9Sstevel@tonic-gate 			val = 1;
8807c478bd9Sstevel@tonic-gate 			/*
8817c478bd9Sstevel@tonic-gate 			 * If file system type matches the remote
8827c478bd9Sstevel@tonic-gate 			 * file system type, then it is not local.
8837c478bd9Sstevel@tonic-gate 			 */
8847c478bd9Sstevel@tonic-gate 			for (nremfs = 0; nremfs < fstype_index; nremfs++) {
8857c478bd9Sstevel@tonic-gate 				if (strcmp(remote_fstypes[nremfs],
88627d3a169SToomas Soome 				    statb->st_fstype) == 0) {
8877c478bd9Sstevel@tonic-gate 					val = 0;
8887c478bd9Sstevel@tonic-gate 					break;
8897c478bd9Sstevel@tonic-gate 				}
8907c478bd9Sstevel@tonic-gate 			}
8917c478bd9Sstevel@tonic-gate 			break;
8927c478bd9Sstevel@tonic-gate 		}
8947c478bd9Sstevel@tonic-gate 		case TYPE:
8957c478bd9Sstevel@tonic-gate 			l = (long)statb->st_mode&S_IFMT;
8967c478bd9Sstevel@tonic-gate 			goto num;
8987c478bd9Sstevel@tonic-gate 		case PERM:
8997c478bd9Sstevel@tonic-gate 			l = (long)statb->st_mode&07777;
9007c478bd9Sstevel@tonic-gate 			if (np->second.i == '-')
9017c478bd9Sstevel@tonic-gate 				val = ((l&np->first.l) == np->first.l);
9027c478bd9Sstevel@tonic-gate 			else
9037c478bd9Sstevel@tonic-gate 				val = (l == np->first.l);
9047c478bd9Sstevel@tonic-gate 			break;
9067c478bd9Sstevel@tonic-gate 		case INUM:
9077c478bd9Sstevel@tonic-gate 			ll = (long long)statb->st_ino;
9087c478bd9Sstevel@tonic-gate 			goto llnum;
9097c478bd9Sstevel@tonic-gate 		case NEWER:
9107c478bd9Sstevel@tonic-gate 			l = statb->st_mtime;
9117c478bd9Sstevel@tonic-gate 			goto num;
9127c478bd9Sstevel@tonic-gate 		case ATIME:
9137c478bd9Sstevel@tonic-gate 			t = statb->st_atime;
9147c478bd9Sstevel@tonic-gate 			goto days;
9157c478bd9Sstevel@tonic-gate 		case CTIME:
9167c478bd9Sstevel@tonic-gate 			t = statb->st_ctime;
9177c478bd9Sstevel@tonic-gate 			goto days;
9187c478bd9Sstevel@tonic-gate 		case MTIME:
9197c478bd9Sstevel@tonic-gate 			t = statb->st_mtime;
9207c478bd9Sstevel@tonic-gate 		days:
9217c478bd9Sstevel@tonic-gate 			l = (now-t)/A_DAY;
9227c478bd9Sstevel@tonic-gate 			goto num;
923da1a9cbeSjonb 		case MMIN:
924da1a9cbeSjonb 			t = statb->st_mtime;
925da1a9cbeSjonb 			goto mins;
926da1a9cbeSjonb 		case AMIN:
927da1a9cbeSjonb 			t = statb->st_atime;
928da1a9cbeSjonb 			goto mins;
929da1a9cbeSjonb 		case CMIN:
930da1a9cbeSjonb 			t = statb->st_ctime;
931da1a9cbeSjonb 			goto mins;
932da1a9cbeSjonb 		mins:
933da1a9cbeSjonb 			l = (now-t)/A_MIN;
934da1a9cbeSjonb 			goto num;
9357c478bd9Sstevel@tonic-gate 		case CSIZE:
9367c478bd9Sstevel@tonic-gate 			ll = (long long)statb->st_size;
9377c478bd9Sstevel@tonic-gate 			goto llnum;
9387c478bd9Sstevel@tonic-gate 		case SIZE:
9397c478bd9Sstevel@tonic-gate 			ll = (long long)round(statb->st_size, BLKSIZ)/BLKSIZ;
9407c478bd9Sstevel@tonic-gate 			goto llnum;
9417c478bd9Sstevel@tonic-gate 		case F_USER:
9427c478bd9Sstevel@tonic-gate 			l = (long)statb->st_uid;
9437c478bd9Sstevel@tonic-gate 			goto num;
9447c478bd9Sstevel@tonic-gate 		case F_GROUP:
9457c478bd9Sstevel@tonic-gate 			l = (long)statb->st_gid;
9467c478bd9Sstevel@tonic-gate 			goto num;
9477c478bd9Sstevel@tonic-gate 		case LINKS:
9487c478bd9Sstevel@tonic-gate 			l = (long)statb->st_nlink;
9497c478bd9Sstevel@tonic-gate 			goto num;
9507c478bd9Sstevel@tonic-gate 		llnum:
9517c478bd9Sstevel@tonic-gate 			if (np->second.i == '+')
9527c478bd9Sstevel@tonic-gate 				val = (ll > np->first.ll);
9537c478bd9Sstevel@tonic-gate 			else if (np->second.i == '-')
9547c478bd9Sstevel@tonic-gate 				val = (ll < np->first.ll);
9557c478bd9Sstevel@tonic-gate 			else
9567c478bd9Sstevel@tonic-gate 				val = (ll == np->first.ll);
9577c478bd9Sstevel@tonic-gate 			break;
9587c478bd9Sstevel@tonic-gate 		num:
9597c478bd9Sstevel@tonic-gate 			if (np->second.i == '+')
9607c478bd9Sstevel@tonic-gate 				val = (l > np->first.l);
9617c478bd9Sstevel@tonic-gate 			else if (np->second.i == '-')
9627c478bd9Sstevel@tonic-gate 				val = (l < np->first.l);
9637c478bd9Sstevel@tonic-gate 			else
9647c478bd9Sstevel@tonic-gate 				val = (l == np->first.l);
9657c478bd9Sstevel@tonic-gate 			break;
9667c478bd9Sstevel@tonic-gate 		case OK:
9677c478bd9Sstevel@tonic-gate 			val = ok(name, np->first.ap);
9687c478bd9Sstevel@tonic-gate 			break;
9697c478bd9Sstevel@tonic-gate 		case EXEC:
970d35170d6Srm 			val = doexec(name, np->first.ap, NULL);
9717c478bd9Sstevel@tonic-gate 			break;
972ab823b7fSPrasad Joshi 		case DELETE:
973ab823b7fSPrasad Joshi 			val = dodelete(name, statb, state);
974ab823b7fSPrasad Joshi 			break;
9767c478bd9Sstevel@tonic-gate 		case VARARGS: {
9777c478bd9Sstevel@tonic-gate 			struct Arglist *ap = np->first.vp;
9787c478bd9Sstevel@tonic-gate 			char *cp;
9797c478bd9Sstevel@tonic-gate 			cp = ap->nextstr - (strlen(name)+1);
9807c478bd9Sstevel@tonic-gate 			if (cp >= (char *)(ap->nextvar+3)) {
9817c478bd9Sstevel@tonic-gate 				/* there is room just copy the name */
9827c478bd9Sstevel@tonic-gate 				val = 1;
9837c478bd9Sstevel@tonic-gate 				(void) strcpy(cp, name);
9847c478bd9Sstevel@tonic-gate 				*ap->nextvar++ = cp;
9857c478bd9Sstevel@tonic-gate 				ap->nextstr = cp;
9867c478bd9Sstevel@tonic-gate 			} else {
9877c478bd9Sstevel@tonic-gate 				/* no more room, exec command */
98827d3a169SToomas Soome 				*ap->nextvar++ = (char *)name;
9897c478bd9Sstevel@tonic-gate 				*ap->nextvar = 0;
9907c478bd9Sstevel@tonic-gate 				val = 1;
99127d3a169SToomas Soome 				(void) doexec(NULL, ap->arglist,
992d35170d6Srm 				    &exec_exitcode);
9937c478bd9Sstevel@tonic-gate 				ap->nextstr = ap->end;
9947c478bd9Sstevel@tonic-gate 				ap->nextvar = ap->firstvar;
9957c478bd9Sstevel@tonic-gate 			}
9967c478bd9Sstevel@tonic-gate 			break;
9977c478bd9Sstevel@tonic-gate 		}
9997c478bd9Sstevel@tonic-gate 		case DEPTH:
10007c478bd9Sstevel@tonic-gate 		case MOUNT:
10017c478bd9Sstevel@tonic-gate 		case FOLLOW:
10027c478bd9Sstevel@tonic-gate 			val = 1;
10037c478bd9Sstevel@tonic-gate 			break;
1005b34cd89aSYuri Pankov 		case NAME:
100605f32410SAndy Stormont 		case INAME:
100705f32410SAndy Stormont 		case PATH:
100805f32410SAndy Stormont 		case IPATH: {
100905f32410SAndy Stormont 			char *path;
101005f32410SAndy Stormont 			int fnmflags = 0;
101105f32410SAndy Stormont 
101205f32410SAndy Stormont 			if (np->action == INAME || np->action == IPATH)
101305f32410SAndy Stormont 				fnmflags = FNM_IGNORECASE;
10159ab6dc39Schin 			/*
10169ab6dc39Schin 			 * basename(3c) may modify name, so
10179ab6dc39Schin 			 * we need to pass another string
10189ab6dc39Schin 			 */
101905f32410SAndy Stormont 			if ((path = strdup(name)) == NULL) {
10209ab6dc39Schin 				(void) fprintf(stderr,
10219ab6dc39Schin 				    gettext("%s: cannot strdup() %s: %s\n"),
10226b238a5aSchin 				    cmdname, name, strerror(errno));
10239ab6dc39Schin 				exit(2);
10249ab6dc39Schin 			}
10257c478bd9Sstevel@tonic-gate 			/*
10267c478bd9Sstevel@tonic-gate 			 * XPG4 find should not treat a leading '.' in a
10277c478bd9Sstevel@tonic-gate 			 * filename specially for pattern matching.
10287c478bd9Sstevel@tonic-gate 			 * /usr/bin/find  will not pattern match a leading
10297c478bd9Sstevel@tonic-gate 			 * '.' in a filename, unless '.' is explicitly
10307c478bd9Sstevel@tonic-gate 			 * specified.
1031*f3a525d9SJohn Levon 			 *
1032*f3a525d9SJohn Levon 			 * The legacy behavior makes no sense for PATH.
10337c478bd9Sstevel@tonic-gate 			 */
1034b34cd89aSYuri Pankov #ifndef XPG4
1035*f3a525d9SJohn Levon 			if (np->action == NAME || np->action == INAME)
1036*f3a525d9SJohn Levon 				fnmflags |= FNM_PERIOD;
10377c478bd9Sstevel@tonic-gate #endif
103805f32410SAndy Stormont 
103905f32410SAndy Stormont 			val = !fnmatch(np->first.cp,
104027d3a169SToomas Soome 			    (np->action == NAME || np->action == INAME) ?
104127d3a169SToomas Soome 			    basename(path) : path, fnmflags);
104205f32410SAndy Stormont 			free(path);
10437c478bd9Sstevel@tonic-gate 			break;
10447c478bd9Sstevel@tonic-gate 		}
10467c478bd9Sstevel@tonic-gate 		case PRUNE:
10477c478bd9Sstevel@tonic-gate 			if (type == FTW_D)
10487c478bd9Sstevel@tonic-gate 				state->quit = FTW_PRUNE;
10497c478bd9Sstevel@tonic-gate 			val = 1;
10507c478bd9Sstevel@tonic-gate 			break;
10517c478bd9Sstevel@tonic-gate 		case NOUSER:
10527c478bd9Sstevel@tonic-gate 			val = ((getpwuid(statb->st_uid)) == 0);
10537c478bd9Sstevel@tonic-gate 			break;
10547c478bd9Sstevel@tonic-gate 		case NOGRP:
10557c478bd9Sstevel@tonic-gate 			val = ((getgrgid(statb->st_gid)) == 0);