xref: /titanic_53/usr/src/cmd/find/find.c (revision 03f45afce6d104ff4050265b34c6aa64f1fed366)
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
5d35170d6Srm88369  * Common Development and Distribution License (the "License").
6d35170d6Srm88369  * 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.
23*03f45afcSYuri Pankov  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26da1a9cbeSjonb 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*	Parts of this product may be derived from		*/
327c478bd9Sstevel@tonic-gate /*	Mortice Kern Systems Inc. and Berkeley 4.3 BSD systems.	*/
337c478bd9Sstevel@tonic-gate /*	licensed from  Mortice Kern Systems Inc. and 		*/
347c478bd9Sstevel@tonic-gate /*	the University of California.				*/
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate  * Copyright 1985, 1990 by Mortice Kern Systems Inc.  All rights reserved.
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include <stdio.h>
417c478bd9Sstevel@tonic-gate #include <errno.h>
427c478bd9Sstevel@tonic-gate #include <pwd.h>
437c478bd9Sstevel@tonic-gate #include <grp.h>
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
457c478bd9Sstevel@tonic-gate #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <sys/param.h>
477c478bd9Sstevel@tonic-gate #include <sys/acl.h>
487c478bd9Sstevel@tonic-gate #include <limits.h>
497c478bd9Sstevel@tonic-gate #include <unistd.h>
507c478bd9Sstevel@tonic-gate #include <stdlib.h>
517c478bd9Sstevel@tonic-gate #include <locale.h>
527c478bd9Sstevel@tonic-gate #include <string.h>
537c478bd9Sstevel@tonic-gate #include <strings.h>
547c478bd9Sstevel@tonic-gate #include <ctype.h>
557c478bd9Sstevel@tonic-gate #include <wait.h>
567c478bd9Sstevel@tonic-gate #include <fnmatch.h>
577c478bd9Sstevel@tonic-gate #include <langinfo.h>
587c478bd9Sstevel@tonic-gate #include <ftw.h>
599ab6dc39Schin #include <libgen.h>
60b34cd89aSYuri Pankov #include <err.h>
61b34cd89aSYuri Pankov #include <regex.h>
623d63ea05Sas145665 #include "getresponse.h"
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #define	A_DAY		(long)(60*60*24)	/* a day full of seconds */
65da1a9cbeSjonb #define	A_MIN		(long)(60)
667c478bd9Sstevel@tonic-gate #define	BLKSIZ		512
677c478bd9Sstevel@tonic-gate #define	round(x, s)	(((x)+(s)-1)&~((s)-1))
687c478bd9Sstevel@tonic-gate #ifndef FTW_SLN
697c478bd9Sstevel@tonic-gate #define	FTW_SLN		7
707c478bd9Sstevel@tonic-gate #endif
717c478bd9Sstevel@tonic-gate #define	LINEBUF_SIZE		LINE_MAX	/* input or output lines */
727c478bd9Sstevel@tonic-gate #define	REMOTE_FS		"/etc/dfs/fstypes"
737c478bd9Sstevel@tonic-gate #define	N_FSTYPES		20
74d35170d6Srm88369 #define	SHELL_MAXARGS		253	/* see doexec() for description */
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * This is the list of operations
787c478bd9Sstevel@tonic-gate  * F_USER and F_GROUP are named to avoid conflict with USER and GROUP defined
797c478bd9Sstevel@tonic-gate  * in sys/acl.h
807c478bd9Sstevel@tonic-gate  */
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate enum Command
837c478bd9Sstevel@tonic-gate {
84b34cd89aSYuri Pankov 	PRINT,
85b34cd89aSYuri Pankov 	ACL, AMIN, AND, ATIME, CMIN, CPIO, CSIZE, CTIME, DEPTH, EXEC, F_GROUP,
86b34cd89aSYuri Pankov 	F_GROUPACL, F_USER, F_USERACL, FOLLOW, FSTYPE, INAME, INUM, IREGEX,
87b34cd89aSYuri Pankov 	LINKS, LOCAL, LPAREN, LS, MAXDEPTH, MINDEPTH, MMIN, MOUNT, MTIME, NAME,
88b34cd89aSYuri Pankov 	NCPIO, NEWER, NOGRP, NOT, NOUSER, OK, OR, PERM, PRINT0, PRUNE, REGEX,
89b34cd89aSYuri Pankov 	RPAREN, SIZE, TYPE, VARARGS, XATTR
907c478bd9Sstevel@tonic-gate };
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate enum Type
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	Unary, Id, Num, Str, Exec, Cpio, Op
957c478bd9Sstevel@tonic-gate };
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate struct Args
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate 	char		name[10];
1007c478bd9Sstevel@tonic-gate 	enum Command	action;
1017c478bd9Sstevel@tonic-gate 	enum Type	type;
1027c478bd9Sstevel@tonic-gate };
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * Except for pathnames, these are the only legal arguments
1067c478bd9Sstevel@tonic-gate  */
1077c478bd9Sstevel@tonic-gate static struct Args commands[] =
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate 	"!",		NOT,		Op,
1107c478bd9Sstevel@tonic-gate 	"(",		LPAREN,		Unary,
1117c478bd9Sstevel@tonic-gate 	")",		RPAREN,		Unary,
1127c478bd9Sstevel@tonic-gate 	"-a",		AND,		Op,
113b34cd89aSYuri Pankov 	"-acl",		ACL,		Unary,
114da1a9cbeSjonb 	"-amin",	AMIN,		Num,
115b34cd89aSYuri Pankov 	"-and",		AND,		Op,
1167c478bd9Sstevel@tonic-gate 	"-atime",	ATIME,		Num,
117da1a9cbeSjonb 	"-cmin",	CMIN,		Num,
118b34cd89aSYuri Pankov 	"-cpio",	CPIO,		Cpio,
1197c478bd9Sstevel@tonic-gate 	"-ctime",	CTIME,		Num,
1207c478bd9Sstevel@tonic-gate 	"-depth",	DEPTH,		Unary,
1217c478bd9Sstevel@tonic-gate 	"-exec",	EXEC,		Exec,
1227c478bd9Sstevel@tonic-gate 	"-follow",	FOLLOW,		Unary,
123b34cd89aSYuri Pankov 	"-fstype",	FSTYPE,		Str,
1247c478bd9Sstevel@tonic-gate 	"-group",	F_GROUP,	Num,
125b34cd89aSYuri Pankov 	"-groupacl",	F_GROUPACL,	Num,
126b34cd89aSYuri Pankov 	"-iname",	INAME,		Str,
1277c478bd9Sstevel@tonic-gate 	"-inum",	INUM,		Num,
128b34cd89aSYuri Pankov 	"-iregex",	IREGEX,		Str,
129*03f45afcSYuri Pankov 	"-links",	LINKS,		Num,
130*03f45afcSYuri Pankov 	"-local",	LOCAL,		Unary,
131b34cd89aSYuri Pankov 	"-ls",		LS,		Unary,
132b34cd89aSYuri Pankov 	"-maxdepth",	MAXDEPTH,	Num,
133b34cd89aSYuri Pankov 	"-mindepth",	MINDEPTH,	Num,
134da1a9cbeSjonb 	"-mmin",	MMIN,		Num,
135b34cd89aSYuri Pankov 	"-mount",	MOUNT,		Unary,
1367c478bd9Sstevel@tonic-gate 	"-mtime",	MTIME,		Num,
1377c478bd9Sstevel@tonic-gate 	"-name",	NAME,		Str,
1387c478bd9Sstevel@tonic-gate 	"-ncpio",	NCPIO,		Cpio,
1397c478bd9Sstevel@tonic-gate 	"-newer",	NEWER,		Str,
140b34cd89aSYuri Pankov 	"-nogroup",	NOGRP,		Unary,
141b34cd89aSYuri Pankov 	"-not",		NOT,		Op,
142b34cd89aSYuri Pankov 	"-nouser",	NOUSER,		Unary,
1437c478bd9Sstevel@tonic-gate 	"-o",		OR,		Op,
1447c478bd9Sstevel@tonic-gate 	"-ok",		OK,		Exec,
145b34cd89aSYuri Pankov 	"-or",		OR,		Op,
1467c478bd9Sstevel@tonic-gate 	"-perm",	PERM,		Num,
1477c478bd9Sstevel@tonic-gate 	"-print",	PRINT,		Unary,
148b34cd89aSYuri Pankov 	"-print0",	PRINT0,		Unary,
149b34cd89aSYuri Pankov 	"-prune",	PRUNE,		Unary,
150b34cd89aSYuri Pankov 	"-regex",	REGEX,		Str,
1517c478bd9Sstevel@tonic-gate 	"-size",	SIZE,		Num,
1527c478bd9Sstevel@tonic-gate 	"-type",	TYPE,		Num,
1537c478bd9Sstevel@tonic-gate 	"-user",	F_USER,		Num,
154b34cd89aSYuri Pankov 	"-useracl",	F_USERACL,	Num,
1557c478bd9Sstevel@tonic-gate 	"-xattr",	XATTR,		Unary,
156b34cd89aSYuri Pankov 	"-xdev",	MOUNT,		Unary,
1577c478bd9Sstevel@tonic-gate 	NULL,		0,		0
1587c478bd9Sstevel@tonic-gate };
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate union Item
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	struct Node	*np;
1637c478bd9Sstevel@tonic-gate 	struct Arglist	*vp;
1647c478bd9Sstevel@tonic-gate 	time_t		t;
1657c478bd9Sstevel@tonic-gate 	char		*cp;
1667c478bd9Sstevel@tonic-gate 	char		**ap;
1677c478bd9Sstevel@tonic-gate 	long		l;
1687c478bd9Sstevel@tonic-gate 	int		i;
1697c478bd9Sstevel@tonic-gate 	long long	ll;
1707c478bd9Sstevel@tonic-gate };
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate struct Node
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate 	struct Node	*next;
1757c478bd9Sstevel@tonic-gate 	enum Command	action;
1767c478bd9Sstevel@tonic-gate 	enum Type	type;
1777c478bd9Sstevel@tonic-gate 	union Item	first;
1787c478bd9Sstevel@tonic-gate 	union Item	second;
1797c478bd9Sstevel@tonic-gate };
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /* if no -print, -exec or -ok replace "expression" with "(expression) -print" */
1827c478bd9Sstevel@tonic-gate static	struct	Node PRINT_NODE = { 0, PRINT, 0, 0};
1837c478bd9Sstevel@tonic-gate static	struct	Node LPAREN_NODE = { 0, LPAREN, 0, 0};
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate /*
1877c478bd9Sstevel@tonic-gate  * Prototype variable size arglist buffer
1887c478bd9Sstevel@tonic-gate  */
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate struct Arglist
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	struct Arglist	*next;
1937c478bd9Sstevel@tonic-gate 	char		*end;
1947c478bd9Sstevel@tonic-gate 	char		*nextstr;
1957c478bd9Sstevel@tonic-gate 	char		**firstvar;
1967c478bd9Sstevel@tonic-gate 	char		**nextvar;
1977c478bd9Sstevel@tonic-gate 	char		*arglist[1];
1987c478bd9Sstevel@tonic-gate };
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate static int		compile();
2027c478bd9Sstevel@tonic-gate static int		execute();
203d35170d6Srm88369 static int		doexec(char *, char **, int *);
2047c478bd9Sstevel@tonic-gate static struct Args	*lookup();
2057c478bd9Sstevel@tonic-gate static int		ok();
2066c83d09fSrobbin static void		usage(void)	__NORETURN;
2077c478bd9Sstevel@tonic-gate static struct Arglist	*varargs();
2087c478bd9Sstevel@tonic-gate static int		list();
2097c478bd9Sstevel@tonic-gate static char		*getgroup();
2107c478bd9Sstevel@tonic-gate static FILE		*cmdopen();
2117c478bd9Sstevel@tonic-gate static int		cmdclose();
2127c478bd9Sstevel@tonic-gate static char		*getshell();
2137c478bd9Sstevel@tonic-gate static void 		init_remote_fs();
2147c478bd9Sstevel@tonic-gate static char		*getname();
2157c478bd9Sstevel@tonic-gate static int		readmode();
2167c478bd9Sstevel@tonic-gate static mode_t		getmode();
2177c478bd9Sstevel@tonic-gate static char		*gettail();
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 
22068a94df1Scf46844 static int walkflags = FTW_CHDIR|FTW_PHYS|FTW_ANYERR|FTW_NOLOOP;
2217c478bd9Sstevel@tonic-gate static struct Node	*topnode;
2227c478bd9Sstevel@tonic-gate static struct Node	*freenode;	/* next free node we may use later */
2237c478bd9Sstevel@tonic-gate static char		*cpio[] = { "cpio", "-o", 0 };
2247c478bd9Sstevel@tonic-gate static char		*ncpio[] = { "cpio", "-oc", 0 };
2257c478bd9Sstevel@tonic-gate static char		*cpiol[] = { "cpio", "-oL", 0 };
2267c478bd9Sstevel@tonic-gate static char		*ncpiol[] = { "cpio", "-ocL", 0 };
2277c478bd9Sstevel@tonic-gate static time_t		now;
2287c478bd9Sstevel@tonic-gate static FILE		*output;
2297c478bd9Sstevel@tonic-gate static char		*dummyarg = (char *)-1;
2307c478bd9Sstevel@tonic-gate static int		lastval;
2317c478bd9Sstevel@tonic-gate static int		varsize;
2327c478bd9Sstevel@tonic-gate static struct Arglist	*lastlist;
2337c478bd9Sstevel@tonic-gate static char		*cmdname;
2347c478bd9Sstevel@tonic-gate static char		*remote_fstypes[N_FSTYPES+1];
2357c478bd9Sstevel@tonic-gate static int		fstype_index = 0;
2367c478bd9Sstevel@tonic-gate static int		action_expression = 0;	/* -print, -exec, or -ok */
2377c478bd9Sstevel@tonic-gate static int		error = 0;
2387c478bd9Sstevel@tonic-gate static int		paren_cnt = 0;	/* keeps track of parentheses */
239b34cd89aSYuri Pankov static int		Eflag = 0;
2407c478bd9Sstevel@tonic-gate static int		hflag = 0;
2417c478bd9Sstevel@tonic-gate static int		lflag = 0;
242d35170d6Srm88369 /* set when doexec()-invoked utility returns non-zero */
243d35170d6Srm88369 static int		exec_exitcode = 0;
244b34cd89aSYuri Pankov static regex_t		*preg = NULL;
245b34cd89aSYuri Pankov static int		npreg = 0;
246b34cd89aSYuri Pankov static int		mindepth = -1, maxdepth = -1;
2477c478bd9Sstevel@tonic-gate extern char		**environ;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate int
2507c478bd9Sstevel@tonic-gate main(int argc, char **argv)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate 	char *cp;
2537c478bd9Sstevel@tonic-gate 	int c;
2547c478bd9Sstevel@tonic-gate 	int paths;
2557c478bd9Sstevel@tonic-gate 	char *cwdpath;
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2587c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
2597c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
2607c478bd9Sstevel@tonic-gate #endif
2617c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	cmdname = argv[0];
2647c478bd9Sstevel@tonic-gate 	if (time(&now) == (time_t)(-1)) {
2657c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: time() %s\n"),
2667c478bd9Sstevel@tonic-gate 		    cmdname, strerror(errno));
2677c478bd9Sstevel@tonic-gate 		exit(1);
2687c478bd9Sstevel@tonic-gate 	}
269b34cd89aSYuri Pankov 	while ((c = getopt(argc, argv, "EHL")) != -1) {
2707c478bd9Sstevel@tonic-gate 		switch (c) {
271b34cd89aSYuri Pankov 		case 'E':
272b34cd89aSYuri Pankov 			Eflag = 1;
273b34cd89aSYuri Pankov 			break;
2747c478bd9Sstevel@tonic-gate 		case 'H':
2757c478bd9Sstevel@tonic-gate 			hflag = 1;
2767c478bd9Sstevel@tonic-gate 			lflag = 0;
2777c478bd9Sstevel@tonic-gate 			break;
2787c478bd9Sstevel@tonic-gate 		case 'L':
2797c478bd9Sstevel@tonic-gate 			hflag = 0;
2807c478bd9Sstevel@tonic-gate 			lflag = 1;
2817c478bd9Sstevel@tonic-gate 			break;
2827c478bd9Sstevel@tonic-gate 		case '?':
2837c478bd9Sstevel@tonic-gate 			usage();
2847c478bd9Sstevel@tonic-gate 			break;
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	argc -= optind;
2897c478bd9Sstevel@tonic-gate 	argv += optind;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	if (argc < 1) {
2927c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2937c478bd9Sstevel@tonic-gate 		    gettext("%s: insufficient number of arguments\n"), cmdname);
2947c478bd9Sstevel@tonic-gate 		usage();
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	for (paths = 0; (cp = argv[paths]) != 0; ++paths) {
2987c478bd9Sstevel@tonic-gate 		if (*cp == '-')
2997c478bd9Sstevel@tonic-gate 			break;
3007c478bd9Sstevel@tonic-gate 		else if ((*cp == '!' || *cp == '(') && *(cp+1) == 0)
3017c478bd9Sstevel@tonic-gate 			break;
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	if (paths == 0) /* no path-list */
3057c478bd9Sstevel@tonic-gate 		usage();
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	output = stdout;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	/* lflag is the same as -follow */
3107c478bd9Sstevel@tonic-gate 	if (lflag)
3117c478bd9Sstevel@tonic-gate 		walkflags &= ~FTW_PHYS;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	/* allocate enough space for the compiler */
3147c478bd9Sstevel@tonic-gate 	topnode = malloc((argc + 1) * sizeof (struct Node));
3157c478bd9Sstevel@tonic-gate 	(void) memset(topnode, 0, (argc + 1) * sizeof (struct Node));
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	if (compile(argv + paths, topnode, &action_expression) == 0) {
3187c478bd9Sstevel@tonic-gate 		/* no expression, default to -print */
3197c478bd9Sstevel@tonic-gate 		(void) memcpy(topnode, &PRINT_NODE, sizeof (struct Node));
3207c478bd9Sstevel@tonic-gate 	} else if (!action_expression) {
3217c478bd9Sstevel@tonic-gate 		/*
3227c478bd9Sstevel@tonic-gate 		 * if no action expression, insert an LPAREN node above topnode,
3237c478bd9Sstevel@tonic-gate 		 * with a PRINT node as its next node
3247c478bd9Sstevel@tonic-gate 		 */
3257c478bd9Sstevel@tonic-gate 		struct Node *savenode;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 		if (freenode == NULL) {
3287c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s: can't append -print"
3297c478bd9Sstevel@tonic-gate 			    " implicitly; try explicit -print option\n"),
3307c478bd9Sstevel@tonic-gate 			    cmdname);
3317c478bd9Sstevel@tonic-gate 			exit(1);
3327c478bd9Sstevel@tonic-gate 		}
3337c478bd9Sstevel@tonic-gate 		savenode = topnode;
3347c478bd9Sstevel@tonic-gate 		topnode = freenode++;
3357c478bd9Sstevel@tonic-gate 		(void) memcpy(topnode, &LPAREN_NODE, sizeof (struct Node));
3367c478bd9Sstevel@tonic-gate 		topnode->next = freenode;
3377c478bd9Sstevel@tonic-gate 		topnode->first.np = savenode;
3387c478bd9Sstevel@tonic-gate 		(void) memcpy(topnode->next, &PRINT_NODE, sizeof (struct Node));
3397c478bd9Sstevel@tonic-gate 	}
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	while (paths--) {
3427c478bd9Sstevel@tonic-gate 		char *curpath;
3437c478bd9Sstevel@tonic-gate 		struct stat sb;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 		curpath = *(argv++);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 		/*
3487c478bd9Sstevel@tonic-gate 		 * If -H is specified, it means we walk the first
3497c478bd9Sstevel@tonic-gate 		 * level (pathname on command line) logically, following
3507c478bd9Sstevel@tonic-gate 		 * symlinks, but lower levels are walked physically.
3517c478bd9Sstevel@tonic-gate 		 * We use our own secret interface to nftw() to change
3527c478bd9Sstevel@tonic-gate 		 * the from stat to lstat after the top level is walked.
3537c478bd9Sstevel@tonic-gate 		 */
3547c478bd9Sstevel@tonic-gate 		if (hflag) {
3557c478bd9Sstevel@tonic-gate 			if (stat(curpath, &sb) < 0 && errno == ENOENT)
3567c478bd9Sstevel@tonic-gate 				walkflags &= ~FTW_HOPTION;
3577c478bd9Sstevel@tonic-gate 			else
3587c478bd9Sstevel@tonic-gate 				walkflags |= FTW_HOPTION;
3597c478bd9Sstevel@tonic-gate 		}
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 		/*
3627c478bd9Sstevel@tonic-gate 		 * We need this check as nftw needs a CWD and we have no
3637c478bd9Sstevel@tonic-gate 		 * way of returning back from that code with a meaningful
3647c478bd9Sstevel@tonic-gate 		 * error related to this
3657c478bd9Sstevel@tonic-gate 		 */
3667c478bd9Sstevel@tonic-gate 		if ((cwdpath = getcwd(NULL, PATH_MAX)) == NULL) {
3674b808d43SRich Burridge 			if ((errno == EACCES) && (walkflags & FTW_CHDIR)) {
3684b808d43SRich Burridge 				/*
3694b808d43SRich Burridge 				 * A directory above cwd is inaccessible,
3704b808d43SRich Burridge 				 * so don't do chdir(2)s. Slower, but at least
3714b808d43SRich Burridge 				 * it works.
3724b808d43SRich Burridge 				 */
3734b808d43SRich Burridge 				walkflags &= ~FTW_CHDIR;
3744b808d43SRich Burridge 				free(cwdpath);
3754b808d43SRich Burridge 			} else {
3767c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3774b808d43SRich Burridge 				    gettext("%s : cannot get the current "
3784b808d43SRich Burridge 				    "working directory\n"), cmdname);
3797c478bd9Sstevel@tonic-gate 				exit(1);
3804b808d43SRich Burridge 			}
3817c478bd9Sstevel@tonic-gate 		} else
3827c478bd9Sstevel@tonic-gate 			free(cwdpath);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		if (nftw(curpath, execute, 1000, walkflags)) {
3867c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
3877c478bd9Sstevel@tonic-gate 			    gettext("%s: cannot open %s: %s\n"),
3887c478bd9Sstevel@tonic-gate 			    cmdname, curpath, strerror(errno));
3897c478bd9Sstevel@tonic-gate 			error = 1;
3907c478bd9Sstevel@tonic-gate 		}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	}
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	/* execute any remaining variable length lists */
3957c478bd9Sstevel@tonic-gate 	while (lastlist) {
3967c478bd9Sstevel@tonic-gate 		if (lastlist->end != lastlist->nextstr) {
3977c478bd9Sstevel@tonic-gate 			*lastlist->nextvar = 0;
398d35170d6Srm88369 			(void) doexec((char *)0, lastlist->arglist,
399d35170d6Srm88369 			    &exec_exitcode);
4007c478bd9Sstevel@tonic-gate 		}
4017c478bd9Sstevel@tonic-gate 		lastlist = lastlist->next;
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 	if (output != stdout)
4047c478bd9Sstevel@tonic-gate 		return (cmdclose(output));
405d35170d6Srm88369 	return ((exec_exitcode != 0) ? exec_exitcode : error);
4067c478bd9Sstevel@tonic-gate }
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate /*
4097c478bd9Sstevel@tonic-gate  * compile the arguments
4107c478bd9Sstevel@tonic-gate  */
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate static int
4137c478bd9Sstevel@tonic-gate compile(argv, np, actionp)
4147c478bd9Sstevel@tonic-gate char **argv;
4157c478bd9Sstevel@tonic-gate struct Node *np;
4167c478bd9Sstevel@tonic-gate int *actionp;
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	char *b;
4197c478bd9Sstevel@tonic-gate 	char **av;
4207c478bd9Sstevel@tonic-gate 	struct Node *oldnp = topnode;
4217c478bd9Sstevel@tonic-gate 	struct Args *argp;
4227c478bd9Sstevel@tonic-gate 	char **com;
4237c478bd9Sstevel@tonic-gate 	int i;
4247c478bd9Sstevel@tonic-gate 	enum Command wasop = PRINT;
4257c478bd9Sstevel@tonic-gate 
4263d63ea05Sas145665 	if (init_yes() < 0) {
4273d63ea05Sas145665 		(void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
4283d63ea05Sas145665 		    strerror(errno));
4293d63ea05Sas145665 		exit(1);
4303d63ea05Sas145665 	}
4313d63ea05Sas145665 
4327c478bd9Sstevel@tonic-gate 	for (av = argv; *av && (argp = lookup(*av)); av++) {
4337c478bd9Sstevel@tonic-gate 		np->next = 0;
4347c478bd9Sstevel@tonic-gate 		np->action = argp->action;
4357c478bd9Sstevel@tonic-gate 		np->type = argp->type;
4367c478bd9Sstevel@tonic-gate 		np->second.i = 0;
4377c478bd9Sstevel@tonic-gate 		if (argp->type == Op) {
4387c478bd9Sstevel@tonic-gate 			if (wasop == NOT || (wasop && np->action != NOT)) {
4397c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
4407c478bd9Sstevel@tonic-gate 				gettext("%s: operand follows operand\n"),
4417c478bd9Sstevel@tonic-gate 						cmdname);
4427c478bd9Sstevel@tonic-gate 				exit(1);
4437c478bd9Sstevel@tonic-gate 			}
4447c478bd9Sstevel@tonic-gate 			if (np->action != NOT && oldnp == 0)
4457c478bd9Sstevel@tonic-gate 				goto err;
4467c478bd9Sstevel@tonic-gate 			wasop = argp->action;
4477c478bd9Sstevel@tonic-gate 		} else {
4487c478bd9Sstevel@tonic-gate 			wasop = PRINT;
4497c478bd9Sstevel@tonic-gate 			if (argp->type != Unary) {
4507c478bd9Sstevel@tonic-gate 				if (!(b = *++av)) {
4517c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
4527c478bd9Sstevel@tonic-gate 					gettext("%s: incomplete statement\n"),
4537c478bd9Sstevel@tonic-gate 							cmdname);
4547c478bd9Sstevel@tonic-gate 					exit(1);
4557c478bd9Sstevel@tonic-gate 				}
4567c478bd9Sstevel@tonic-gate 				if (argp->type == Num) {
457b34cd89aSYuri Pankov 					if (((argp->action == MAXDEPTH) ||
458b34cd89aSYuri Pankov 					    (argp->action == MINDEPTH)) &&
459b34cd89aSYuri Pankov 					    ((int)strtol(b, (char **)NULL,
460b34cd89aSYuri Pankov 					    10) < 0))
461b34cd89aSYuri Pankov 						errx(1,
462b34cd89aSYuri Pankov 					gettext("%s: value must be positive"),
463b34cd89aSYuri Pankov 						    (argp->action == MAXDEPTH) ?
464b34cd89aSYuri Pankov 						    "maxdepth" : "mindepth");
4657c478bd9Sstevel@tonic-gate 					if ((argp->action != PERM) ||
4667c478bd9Sstevel@tonic-gate 					    (*b != '+')) {
4677c478bd9Sstevel@tonic-gate 						if (*b == '+' || *b == '-') {
4687c478bd9Sstevel@tonic-gate 							np->second.i = *b;
4697c478bd9Sstevel@tonic-gate 							b++;
4707c478bd9Sstevel@tonic-gate 						}
4717c478bd9Sstevel@tonic-gate 					}
4727c478bd9Sstevel@tonic-gate 				}
4737c478bd9Sstevel@tonic-gate 			}
4747c478bd9Sstevel@tonic-gate 		}
4757c478bd9Sstevel@tonic-gate 		switch (argp->action) {
4767c478bd9Sstevel@tonic-gate 		case AND:
4777c478bd9Sstevel@tonic-gate 			break;
4787c478bd9Sstevel@tonic-gate 		case NOT:
4797c478bd9Sstevel@tonic-gate 			break;
4807c478bd9Sstevel@tonic-gate 		case OR:
4817c478bd9Sstevel@tonic-gate 			np->first.np = topnode;
4827c478bd9Sstevel@tonic-gate 			topnode = np;
4837c478bd9Sstevel@tonic-gate 			oldnp->next = 0;
4847c478bd9Sstevel@tonic-gate 			break;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 		case LPAREN: {
4877c478bd9Sstevel@tonic-gate 			struct Node *save = topnode;
4887c478bd9Sstevel@tonic-gate 			topnode = np+1;
4897c478bd9Sstevel@tonic-gate 			paren_cnt++;
4907c478bd9Sstevel@tonic-gate 			i = compile(++av, topnode, actionp);
4917c478bd9Sstevel@tonic-gate 			np->first.np = topnode;
4927c478bd9Sstevel@tonic-gate 			topnode = save;
4937c478bd9Sstevel@tonic-gate 			av += i;
4947c478bd9Sstevel@tonic-gate 			oldnp = np;
4957c478bd9Sstevel@tonic-gate 			np += i + 1;
4967c478bd9Sstevel@tonic-gate 			oldnp->next = np;
4977c478bd9Sstevel@tonic-gate 			continue;
4987c478bd9Sstevel@tonic-gate 		}
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 		case RPAREN:
5017c478bd9Sstevel@tonic-gate 			if (paren_cnt <= 0) {
5027c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
5037c478bd9Sstevel@tonic-gate 				    gettext("%s: unmatched ')'\n"),
5047c478bd9Sstevel@tonic-gate 				    cmdname);
5057c478bd9Sstevel@tonic-gate 				exit(1);
5067c478bd9Sstevel@tonic-gate 			}
5077c478bd9Sstevel@tonic-gate 			paren_cnt--;
5087c478bd9Sstevel@tonic-gate 			if (oldnp == 0)
5097c478bd9Sstevel@tonic-gate 				goto err;
5107c478bd9Sstevel@tonic-gate 			if (oldnp->type == Op) {
5117c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
5127c478bd9Sstevel@tonic-gate 				    gettext("%s: cannot immediately"
5137c478bd9Sstevel@tonic-gate 				    " follow an operand with ')'\n"),
5147c478bd9Sstevel@tonic-gate 				    cmdname);
5157c478bd9Sstevel@tonic-gate 				exit(1);
5167c478bd9Sstevel@tonic-gate 			}
5177c478bd9Sstevel@tonic-gate 			oldnp->next = 0;
5187c478bd9Sstevel@tonic-gate 			return (av-argv);
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 		case FOLLOW:
5217c478bd9Sstevel@tonic-gate 			walkflags &= ~FTW_PHYS;
5227c478bd9Sstevel@tonic-gate 			break;
5237c478bd9Sstevel@tonic-gate 		case MOUNT:
5247c478bd9Sstevel@tonic-gate 			walkflags |= FTW_MOUNT;
5257c478bd9Sstevel@tonic-gate 			break;
5267c478bd9Sstevel@tonic-gate 		case DEPTH:
5277c478bd9Sstevel@tonic-gate 			walkflags |= FTW_DEPTH;
5287c478bd9Sstevel@tonic-gate 			break;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 		case LOCAL:
5317c478bd9Sstevel@tonic-gate 			np->first.l = 0L;
5327c478bd9Sstevel@tonic-gate 			np->first.ll = 0LL;
5337c478bd9Sstevel@tonic-gate 			np->second.i = '+';
5347c478bd9Sstevel@tonic-gate 			/*
5357c478bd9Sstevel@tonic-gate 			 * Make it compatible to df -l for
5367c478bd9Sstevel@tonic-gate 			 * future enhancement. So, anything
5377c478bd9Sstevel@tonic-gate 			 * that is not remote, then it is
5387c478bd9Sstevel@tonic-gate 			 * local.
5397c478bd9Sstevel@tonic-gate 			 */
5407c478bd9Sstevel@tonic-gate 			init_remote_fs();
5417c478bd9Sstevel@tonic-gate 			break;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 		case SIZE:
5447c478bd9Sstevel@tonic-gate 			if (b[strlen(b)-1] == 'c')
5457c478bd9Sstevel@tonic-gate 				np->action = CSIZE;
5467c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
5477c478bd9Sstevel@tonic-gate 		case INUM:
5487c478bd9Sstevel@tonic-gate 			np->first.ll = atoll(b);
5497c478bd9Sstevel@tonic-gate 			break;
5507c478bd9Sstevel@tonic-gate 
551da1a9cbeSjonb 		case CMIN:
5527c478bd9Sstevel@tonic-gate 		case CTIME:
553da1a9cbeSjonb 		case MMIN:
5547c478bd9Sstevel@tonic-gate 		case MTIME:
555da1a9cbeSjonb 		case AMIN:
5567c478bd9Sstevel@tonic-gate 		case ATIME:
5577c478bd9Sstevel@tonic-gate 		case LINKS:
5587c478bd9Sstevel@tonic-gate 			np->first.l = atol(b);
5597c478bd9Sstevel@tonic-gate 			break;
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 		case F_USER:
562b34cd89aSYuri Pankov 		case F_GROUP:
563b34cd89aSYuri Pankov 		case F_USERACL:
564b34cd89aSYuri Pankov 		case F_GROUPACL: {
5657c478bd9Sstevel@tonic-gate 			struct	passwd	*pw;
5667c478bd9Sstevel@tonic-gate 			struct	group *gr;
567ef497ae3SRich Burridge 			long value;
568ef497ae3SRich Burridge 			char *q;
569ef497ae3SRich Burridge 
570ef497ae3SRich Burridge 			value = -1;
571b34cd89aSYuri Pankov 			if (argp->action == F_USER ||
572b34cd89aSYuri Pankov 			    argp->action == F_USERACL) {
5737c478bd9Sstevel@tonic-gate 				if ((pw = getpwnam(b)) != 0)
574ef497ae3SRich Burridge 					value = (long)pw->pw_uid;
5757c478bd9Sstevel@tonic-gate 			} else {
5767c478bd9Sstevel@tonic-gate 				if ((gr = getgrnam(b)) != 0)
577ef497ae3SRich Burridge 					value = (long)gr->gr_gid;
5787c478bd9Sstevel@tonic-gate 			}
579ef497ae3SRich Burridge 			if (value == -1) {
580ef497ae3SRich Burridge 				errno = 0;
581ef497ae3SRich Burridge 				value = strtol(b, &q, 10);
582ef497ae3SRich Burridge 				if (errno != 0 || q == b || *q != '\0') {
5837c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
5847c478bd9Sstevel@tonic-gate 					    "%s: cannot find %s name\n"),
5857c478bd9Sstevel@tonic-gate 						cmdname, *av);
5867c478bd9Sstevel@tonic-gate 					exit(1);
5877c478bd9Sstevel@tonic-gate 				}
5887c478bd9Sstevel@tonic-gate 			}
589ef497ae3SRich Burridge 			np->first.l = value;
5907c478bd9Sstevel@tonic-gate 			break;
5917c478bd9Sstevel@tonic-gate 		}
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 		case EXEC:
5947c478bd9Sstevel@tonic-gate 		case OK:
5957c478bd9Sstevel@tonic-gate 			walkflags &= ~FTW_CHDIR;
5967c478bd9Sstevel@tonic-gate 			np->first.ap = av;
5977c478bd9Sstevel@tonic-gate 			(*actionp)++;
5987c478bd9Sstevel@tonic-gate 			for (;;) {
5997c478bd9Sstevel@tonic-gate 				if ((b = *av) == 0) {
6007c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
6017c478bd9Sstevel@tonic-gate 					gettext("%s: incomplete statement\n"),
6027c478bd9Sstevel@tonic-gate 						cmdname);
6037c478bd9Sstevel@tonic-gate 					exit(1);
6047c478bd9Sstevel@tonic-gate 				}
6057c478bd9Sstevel@tonic-gate 				if (strcmp(b, ";") == 0) {
6067c478bd9Sstevel@tonic-gate 					*av = 0;
6077c478bd9Sstevel@tonic-gate 					break;
6087c478bd9Sstevel@tonic-gate 				} else if (strcmp(b, "{}") == 0)
6097c478bd9Sstevel@tonic-gate 					*av = dummyarg;
6107c478bd9Sstevel@tonic-gate 				else if (strcmp(b, "+") == 0 &&
6117c478bd9Sstevel@tonic-gate 					av[-1] == dummyarg &&
6127c478bd9Sstevel@tonic-gate 					np->action == EXEC) {
6137c478bd9Sstevel@tonic-gate 					av[-1] = 0;
6147c478bd9Sstevel@tonic-gate 					np->first.vp = varargs(np->first.ap);
6157c478bd9Sstevel@tonic-gate 					np->action = VARARGS;
6167c478bd9Sstevel@tonic-gate 					break;
6177c478bd9Sstevel@tonic-gate 				}
6187c478bd9Sstevel@tonic-gate 				av++;
6197c478bd9Sstevel@tonic-gate 			}
6207c478bd9Sstevel@tonic-gate 			break;
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 		case NAME:
623b34cd89aSYuri Pankov 		case INAME:
6247c478bd9Sstevel@tonic-gate 			np->first.cp = b;
6257c478bd9Sstevel@tonic-gate 			break;
626b34cd89aSYuri Pankov 		case REGEX:
627b34cd89aSYuri Pankov 		case IREGEX: {
628b34cd89aSYuri Pankov 			int error;
629b34cd89aSYuri Pankov 			size_t errlen;
630b34cd89aSYuri Pankov 			char *errmsg;
631b34cd89aSYuri Pankov 
632b34cd89aSYuri Pankov 			if ((preg = realloc(preg, (npreg + 1) *
633b34cd89aSYuri Pankov 			    sizeof (regex_t))) == NULL)
634b34cd89aSYuri Pankov 				err(1, "realloc");
635b34cd89aSYuri Pankov 			if ((error = regcomp(&preg[npreg], b,
636b34cd89aSYuri Pankov 			    ((np->action == IREGEX) ? REG_ICASE : 0) |
637b34cd89aSYuri Pankov 			    ((Eflag) ? REG_EXTENDED : 0))) != 0) {
638b34cd89aSYuri Pankov 				errlen = regerror(error, &preg[npreg], NULL, 0);
639b34cd89aSYuri Pankov 				if ((errmsg = malloc(errlen)) == NULL)
640b34cd89aSYuri Pankov 					err(1, "malloc");
641b34cd89aSYuri Pankov 				(void) regerror(error, &preg[npreg], errmsg,
642b34cd89aSYuri Pankov 				    errlen);
643b34cd89aSYuri Pankov 				errx(1, gettext("RE error: %s"), errmsg);
644b34cd89aSYuri Pankov 			}
645b34cd89aSYuri Pankov 			npreg++;
646b34cd89aSYuri Pankov 			break;
647b34cd89aSYuri Pankov 		}
6487c478bd9Sstevel@tonic-gate 		case PERM:
6497c478bd9Sstevel@tonic-gate 			if (*b == '-')
6507c478bd9Sstevel@tonic-gate 				++b;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 			if (readmode(b) != NULL) {
6537c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
6547c478bd9Sstevel@tonic-gate 				    "find: -perm: Bad permission string\n"));
6557c478bd9Sstevel@tonic-gate 				usage();
6567c478bd9Sstevel@tonic-gate 			}
6577c478bd9Sstevel@tonic-gate 			np->first.l = (long)getmode((mode_t)0);
6587c478bd9Sstevel@tonic-gate 			break;
6597c478bd9Sstevel@tonic-gate 		case TYPE:
6607c478bd9Sstevel@tonic-gate 			i = *b;
6617c478bd9Sstevel@tonic-gate 			np->first.l =
6627c478bd9Sstevel@tonic-gate 			    i == 'd' ? S_IFDIR :
6637c478bd9Sstevel@tonic-gate 			    i == 'b' ? S_IFBLK :
6647c478bd9Sstevel@tonic-gate 			    i == 'c' ? S_IFCHR :
6657c478bd9Sstevel@tonic-gate #ifdef S_IFIFO
6667c478bd9Sstevel@tonic-gate 			    i == 'p' ? S_IFIFO :
6677c478bd9Sstevel@tonic-gate #endif
6687c478bd9Sstevel@tonic-gate 			    i == 'f' ? S_IFREG :
6697c478bd9Sstevel@tonic-gate #ifdef S_IFLNK
6707c478bd9Sstevel@tonic-gate 			    i == 'l' ? S_IFLNK :
6717c478bd9Sstevel@tonic-gate #endif
6727c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK
6737c478bd9Sstevel@tonic-gate 			    i == 's' ? S_IFSOCK :
6747c478bd9Sstevel@tonic-gate #endif
6757c478bd9Sstevel@tonic-gate #ifdef S_IFDOOR
6767c478bd9Sstevel@tonic-gate 			    i == 'D' ? S_IFDOOR :
6777c478bd9Sstevel@tonic-gate #endif
6787c478bd9Sstevel@tonic-gate 			    0;
6797c478bd9Sstevel@tonic-gate 			break;
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 		case CPIO:
6827c478bd9Sstevel@tonic-gate 			if (walkflags & FTW_PHYS)
6837c478bd9Sstevel@tonic-gate 				com = cpio;
6847c478bd9Sstevel@tonic-gate 			else
6857c478bd9Sstevel@tonic-gate 				com = cpiol;
6867c478bd9Sstevel@tonic-gate 			goto common;
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 		case NCPIO: {
6897c478bd9Sstevel@tonic-gate 			FILE *fd;
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 			if (walkflags & FTW_PHYS)
6927c478bd9Sstevel@tonic-gate 				com = ncpio;
6937c478bd9Sstevel@tonic-gate 			else
6947c478bd9Sstevel@tonic-gate 				com = ncpiol;
6957c478bd9Sstevel@tonic-gate 		common:
6967c478bd9Sstevel@tonic-gate 			/* set up cpio */
6977c478bd9Sstevel@tonic-gate 			if ((fd = fopen(b, "w")) == NULL) {
6987c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
6997c478bd9Sstevel@tonic-gate 					gettext("%s: cannot create %s\n"),
7007c478bd9Sstevel@tonic-gate 					cmdname, b);
7017c478bd9Sstevel@tonic-gate 				exit(1);
7027c478bd9Sstevel@tonic-gate 			}
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 			np->first.l = (long)cmdopen("cpio", com, "w", fd);
7057c478bd9Sstevel@tonic-gate 			(void) fclose(fd);
7067c478bd9Sstevel@tonic-gate 			walkflags |= FTW_DEPTH;
7077c478bd9Sstevel@tonic-gate 			np->action = CPIO;
7087c478bd9Sstevel@tonic-gate 		}
7097c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
7107c478bd9Sstevel@tonic-gate 		case PRINT:
711b34cd89aSYuri Pankov 		case PRINT0:
7127c478bd9Sstevel@tonic-gate 			(*actionp)++;
7137c478bd9Sstevel@tonic-gate 			break;
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 		case NEWER: {
7167c478bd9Sstevel@tonic-gate 			struct stat statb;
7177c478bd9Sstevel@tonic-gate 			if (stat(b, &statb) < 0) {
7187c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
7197c478bd9Sstevel@tonic-gate 					gettext("%s: cannot access %s\n"),
7207c478bd9Sstevel@tonic-gate 					cmdname, b);
7217c478bd9Sstevel@tonic-gate 				exit(1);
7227c478bd9Sstevel@tonic-gate 			}
7237c478bd9Sstevel@tonic-gate 			np->first.l = statb.st_mtime;
7247c478bd9Sstevel@tonic-gate 			np->second.i = '+';
7257c478bd9Sstevel@tonic-gate 			break;
7267c478bd9Sstevel@tonic-gate 		}
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 		case PRUNE:
7297c478bd9Sstevel@tonic-gate 		case NOUSER:
7307c478bd9Sstevel@tonic-gate 		case NOGRP:
7317c478bd9Sstevel@tonic-gate 			break;
7327c478bd9Sstevel@tonic-gate 		case FSTYPE:
7337c478bd9Sstevel@tonic-gate 			np->first.cp = b;
7347c478bd9Sstevel@tonic-gate 			break;
7357c478bd9Sstevel@tonic-gate 		case LS:
7367c478bd9Sstevel@tonic-gate 			(*actionp)++;
7377c478bd9Sstevel@tonic-gate 			break;
7387c478bd9Sstevel@tonic-gate 		case XATTR:
7397c478bd9Sstevel@tonic-gate 			break;
7407c478bd9Sstevel@tonic-gate 		case ACL:
7417c478bd9Sstevel@tonic-gate 			break;
742b34cd89aSYuri Pankov 		case MAXDEPTH:
743b34cd89aSYuri Pankov 			maxdepth = (int)strtol(b, (char **)NULL, 10);
744b34cd89aSYuri Pankov 			break;
745b34cd89aSYuri Pankov 		case MINDEPTH:
746b34cd89aSYuri Pankov 			mindepth = (int)strtol(b, (char **)NULL, 10);
747b34cd89aSYuri Pankov 			break;
7487c478bd9Sstevel@tonic-gate 		}
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 		oldnp = np++;
7517c478bd9Sstevel@tonic-gate 		oldnp->next = np;
7527c478bd9Sstevel@tonic-gate 	}
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	if ((*av) || (wasop))
7557c478bd9Sstevel@tonic-gate 		goto err;
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if (paren_cnt != 0) {
7587c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: unmatched '('\n"),
7597c478bd9Sstevel@tonic-gate 		cmdname);
7607c478bd9Sstevel@tonic-gate 		exit(1);
7617c478bd9Sstevel@tonic-gate 	}
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	/* just before returning, save next free node from the list */
7647c478bd9Sstevel@tonic-gate 	freenode = oldnp->next;
7657c478bd9Sstevel@tonic-gate 	oldnp->next = 0;
7667c478bd9Sstevel@tonic-gate 	return (av-argv);
7677c478bd9Sstevel@tonic-gate err:
7687c478bd9Sstevel@tonic-gate 	if (*av)
7697c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7707c478bd9Sstevel@tonic-gate 		    gettext("%s: bad option %s\n"), cmdname, *av);
7717c478bd9Sstevel@tonic-gate 	else
7727c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: bad option\n"), cmdname);
7737c478bd9Sstevel@tonic-gate 	usage();
7747c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate /*
7787c478bd9Sstevel@tonic-gate  * print out a usage message
7797c478bd9Sstevel@tonic-gate  */
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate static void
7826c83d09fSrobbin usage(void)
7837c478bd9Sstevel@tonic-gate {
7847c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
785b34cd89aSYuri Pankov 	    gettext("%s: [-E] [-H | -L] path-list predicate-list\n"), cmdname);
7867c478bd9Sstevel@tonic-gate 	exit(1);
7877c478bd9Sstevel@tonic-gate }
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate /*
7907c478bd9Sstevel@tonic-gate  * This is the function that gets executed at each node
7917c478bd9Sstevel@tonic-gate  */
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate static int
7947c478bd9Sstevel@tonic-gate execute(name, statb, type, state)
7957c478bd9Sstevel@tonic-gate char *name;
7967c478bd9Sstevel@tonic-gate struct stat *statb;
7977c478bd9Sstevel@tonic-gate int type;
7987c478bd9Sstevel@tonic-gate struct FTW *state;
7997c478bd9Sstevel@tonic-gate {
8007c478bd9Sstevel@tonic-gate 	struct Node *np = topnode;
8017c478bd9Sstevel@tonic-gate 	int val;
8027c478bd9Sstevel@tonic-gate 	time_t t;
8037c478bd9Sstevel@tonic-gate 	long l;
8047c478bd9Sstevel@tonic-gate 	long long ll;
8057c478bd9Sstevel@tonic-gate 	int not = 1;
8067c478bd9Sstevel@tonic-gate 	char *filename;
807b34cd89aSYuri Pankov 	int cnpreg = 0;
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	if (type == FTW_NS) {
8107c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: stat() error %s: %s\n"),
8117c478bd9Sstevel@tonic-gate 			cmdname, name, strerror(errno));
8127c478bd9Sstevel@tonic-gate 		error = 1;
8137c478bd9Sstevel@tonic-gate 		return (0);
8147c478bd9Sstevel@tonic-gate 	} else if (type == FTW_DNR) {
8157c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: cannot read dir %s: %s\n"),
8167c478bd9Sstevel@tonic-gate 			cmdname, name, strerror(errno));
8177c478bd9Sstevel@tonic-gate 		error = 1;
8180729abfeSRich Burridge 	} else if (type == FTW_SLN && lflag == 1) {
8197c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
8207c478bd9Sstevel@tonic-gate 			gettext("%s: cannot follow symbolic link %s: %s\n"),
8217c478bd9Sstevel@tonic-gate 			cmdname, name, strerror(errno));
8227c478bd9Sstevel@tonic-gate 		error = 1;
82368a94df1Scf46844 	} else if (type == FTW_DL) {
82468a94df1Scf46844 		(void) fprintf(stderr, gettext("%s: cycle detected for %s\n"),
82568a94df1Scf46844 			cmdname, name);
82668a94df1Scf46844 		error = 1;
82768a94df1Scf46844 		return (0);
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 
830b34cd89aSYuri Pankov 	if ((maxdepth != -1 && state->level > maxdepth) ||
831b34cd89aSYuri Pankov 	    (mindepth != -1 && state->level < mindepth))
832b34cd89aSYuri Pankov 		return (0);
833b34cd89aSYuri Pankov 
8347c478bd9Sstevel@tonic-gate 	while (np) {
8357c478bd9Sstevel@tonic-gate 		switch (np->action) {
8367c478bd9Sstevel@tonic-gate 		case NOT:
8377c478bd9Sstevel@tonic-gate 			not = !not;
8387c478bd9Sstevel@tonic-gate 			np = np->next;
8397c478bd9Sstevel@tonic-gate 			continue;
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 		case AND:
8427c478bd9Sstevel@tonic-gate 			np = np->next;
8437c478bd9Sstevel@tonic-gate 			continue;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 		case OR:
8467c478bd9Sstevel@tonic-gate 			if (np->first.np == np) {
8477c478bd9Sstevel@tonic-gate 				/*
8487c478bd9Sstevel@tonic-gate 				 * handle naked OR (no term on left hand side)
8497c478bd9Sstevel@tonic-gate 				 */
8507c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
8517c478bd9Sstevel@tonic-gate 				    gettext("%s: invalid -o construction\n"),
8527c478bd9Sstevel@tonic-gate 				    cmdname);
8537c478bd9Sstevel@tonic-gate 				exit(2);
8547c478bd9Sstevel@tonic-gate 			}
8557c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
8567c478bd9Sstevel@tonic-gate 		case LPAREN: {
8577c478bd9Sstevel@tonic-gate 			struct Node *save = topnode;
8587c478bd9Sstevel@tonic-gate 			topnode = np->first.np;
8597c478bd9Sstevel@tonic-gate 			(void) execute(name, statb, type, state);
8607c478bd9Sstevel@tonic-gate 			val = lastval;
8617c478bd9Sstevel@tonic-gate 			topnode = save;
8627c478bd9Sstevel@tonic-gate 			if (np->action == OR) {
8637c478bd9Sstevel@tonic-gate 				if (val)
8647c478bd9Sstevel@tonic-gate 					return (0);
8657c478bd9Sstevel@tonic-gate 				val = 1;
8667c478bd9Sstevel@tonic-gate 			}
8677c478bd9Sstevel@tonic-gate 			break;
8687c478bd9Sstevel@tonic-gate 		}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 		case LOCAL: {
8717c478bd9Sstevel@tonic-gate 			int	nremfs;
8727c478bd9Sstevel@tonic-gate 			val = 1;
8737c478bd9Sstevel@tonic-gate 			/*
8747c478bd9Sstevel@tonic-gate 			 * If file system type matches the remote
8757c478bd9Sstevel@tonic-gate 			 * file system type, then it is not local.
8767c478bd9Sstevel@tonic-gate 			 */
8777c478bd9Sstevel@tonic-gate 			for (nremfs = 0; nremfs < fstype_index; nremfs++) {
8787c478bd9Sstevel@tonic-gate 				if (strcmp(remote_fstypes[nremfs],
8797c478bd9Sstevel@tonic-gate 						statb->st_fstype) == 0) {
8807c478bd9Sstevel@tonic-gate 					val = 0;
8817c478bd9Sstevel@tonic-gate 					break;
8827c478bd9Sstevel@tonic-gate 				}
8837c478bd9Sstevel@tonic-gate 			}
8847c478bd9Sstevel@tonic-gate 			break;
8857c478bd9Sstevel@tonic-gate 		}
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 		case TYPE:
8887c478bd9Sstevel@tonic-gate 			l = (long)statb->st_mode&S_IFMT;
8897c478bd9Sstevel@tonic-gate 			goto num;
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 		case PERM:
8927c478bd9Sstevel@tonic-gate 			l = (long)statb->st_mode&07777;
8937c478bd9Sstevel@tonic-gate 			if (np->second.i == '-')
8947c478bd9Sstevel@tonic-gate 				val = ((l&np->first.l) == np->first.l);
8957c478bd9Sstevel@tonic-gate 			else
8967c478bd9Sstevel@tonic-gate 				val = (l == np->first.l);
8977c478bd9Sstevel@tonic-gate 			break;
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 		case INUM:
9007c478bd9Sstevel@tonic-gate 			ll = (long long)statb->st_ino;
9017c478bd9Sstevel@tonic-gate 			goto llnum;
9027c478bd9Sstevel@tonic-gate 		case NEWER:
9037c478bd9Sstevel@tonic-gate 			l = statb->st_mtime;
9047c478bd9Sstevel@tonic-gate 			goto num;
9057c478bd9Sstevel@tonic-gate 		case ATIME:
9067c478bd9Sstevel@tonic-gate 			t = statb->st_atime;
9077c478bd9Sstevel@tonic-gate 			goto days;
9087c478bd9Sstevel@tonic-gate 		case CTIME:
9097c478bd9Sstevel@tonic-gate 			t = statb->st_ctime;
9107c478bd9Sstevel@tonic-gate 			goto days;
9117c478bd9Sstevel@tonic-gate 		case MTIME:
9127c478bd9Sstevel@tonic-gate 			t = statb->st_mtime;
9137c478bd9Sstevel@tonic-gate 		days:
9147c478bd9Sstevel@tonic-gate 			l = (now-t)/A_DAY;
9157c478bd9Sstevel@tonic-gate 			goto num;
916da1a9cbeSjonb 		case MMIN:
917da1a9cbeSjonb 			t = statb->st_mtime;
918da1a9cbeSjonb 			goto mins;
919da1a9cbeSjonb 		case AMIN:
920da1a9cbeSjonb 			t = statb->st_atime;
921da1a9cbeSjonb 			goto mins;
922da1a9cbeSjonb 		case CMIN:
923da1a9cbeSjonb 			t = statb->st_ctime;
924da1a9cbeSjonb 			goto mins;
925da1a9cbeSjonb 		mins:
926da1a9cbeSjonb 			l = (now-t)/A_MIN;
927da1a9cbeSjonb 			goto num;
9287c478bd9Sstevel@tonic-gate 		case CSIZE:
9297c478bd9Sstevel@tonic-gate 			ll = (long long)statb->st_size;
9307c478bd9Sstevel@tonic-gate 			goto llnum;
9317c478bd9Sstevel@tonic-gate 		case SIZE:
9327c478bd9Sstevel@tonic-gate 			ll = (long long)round(statb->st_size, BLKSIZ)/BLKSIZ;
9337c478bd9Sstevel@tonic-gate 			goto llnum;
9347c478bd9Sstevel@tonic-gate 		case F_USER:
9357c478bd9Sstevel@tonic-gate 			l = (long)statb->st_uid;
9367c478bd9Sstevel@tonic-gate 			goto num;
9377c478bd9Sstevel@tonic-gate 		case F_GROUP:
9387c478bd9Sstevel@tonic-gate 			l = (long)statb->st_gid;
9397c478bd9Sstevel@tonic-gate 			goto num;
9407c478bd9Sstevel@tonic-gate 		case LINKS:
9417c478bd9Sstevel@tonic-gate 			l = (long)statb->st_nlink;
9427c478bd9Sstevel@tonic-gate 			goto num;
9437c478bd9Sstevel@tonic-gate 		llnum:
9447c478bd9Sstevel@tonic-gate 			if (np->second.i == '+')
9457c478bd9Sstevel@tonic-gate 				val = (ll > np->first.ll);
9467c478bd9Sstevel@tonic-gate 			else if (np->second.i == '-')
9477c478bd9Sstevel@tonic-gate 				val = (ll < np->first.ll);
9487c478bd9Sstevel@tonic-gate 			else
9497c478bd9Sstevel@tonic-gate 				val = (ll == np->first.ll);
9507c478bd9Sstevel@tonic-gate 			break;
9517c478bd9Sstevel@tonic-gate 		num:
9527c478bd9Sstevel@tonic-gate 			if (np->second.i == '+')
9537c478bd9Sstevel@tonic-gate 				val = (l > np->first.l);
9547c478bd9Sstevel@tonic-gate 			else if (np->second.i == '-')
9557c478bd9Sstevel@tonic-gate 				val = (l < np->first.l);
9567c478bd9Sstevel@tonic-gate 			else
9577c478bd9Sstevel@tonic-gate 				val = (l == np->first.l);
9587c478bd9Sstevel@tonic-gate 			break;
9597c478bd9Sstevel@tonic-gate 		case OK:
9607c478bd9Sstevel@tonic-gate 			val = ok(name, np->first.ap);
9617c478bd9Sstevel@tonic-gate 			break;
9627c478bd9Sstevel@tonic-gate 		case EXEC:
963d35170d6Srm88369 			val = doexec(name, np->first.ap, NULL);
9647c478bd9Sstevel@tonic-gate 			break;
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 		case VARARGS: {
9677c478bd9Sstevel@tonic-gate 			struct Arglist *ap = np->first.vp;
9687c478bd9Sstevel@tonic-gate 			char *cp;
9697c478bd9Sstevel@tonic-gate 			cp = ap->nextstr - (strlen(name)+1);
9707c478bd9Sstevel@tonic-gate 			if (cp >= (char *)(ap->nextvar+3)) {
9717c478bd9Sstevel@tonic-gate 				/* there is room just copy the name */
9727c478bd9Sstevel@tonic-gate 				val = 1;
9737c478bd9Sstevel@tonic-gate 				(void) strcpy(cp, name);
9747c478bd9Sstevel@tonic-gate 				*ap->nextvar++ = cp;
9757c478bd9Sstevel@tonic-gate 				ap->nextstr = cp;
9767c478bd9Sstevel@tonic-gate 			} else {
9777c478bd9Sstevel@tonic-gate 				/* no more room, exec command */
9787c478bd9Sstevel@tonic-gate 				*ap->nextvar++ = name;
9797c478bd9Sstevel@tonic-gate 				*ap->nextvar = 0;
9807c478bd9Sstevel@tonic-gate 				val = 1;
981d35170d6Srm88369 				(void) doexec((char *)0, ap->arglist,
982d35170d6Srm88369 				    &exec_exitcode);
9837c478bd9Sstevel@tonic-gate 				ap->nextstr = ap->end;
9847c478bd9Sstevel@tonic-gate 				ap->nextvar = ap->firstvar;
9857c478bd9Sstevel@tonic-gate 			}
9867c478bd9Sstevel@tonic-gate 			break;
9877c478bd9Sstevel@tonic-gate 		}
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 		case DEPTH:
9907c478bd9Sstevel@tonic-gate 		case MOUNT:
9917c478bd9Sstevel@tonic-gate 		case FOLLOW:
9927c478bd9Sstevel@tonic-gate 			val = 1;
9937c478bd9Sstevel@tonic-gate 			break;
9947c478bd9Sstevel@tonic-gate 
995b34cd89aSYuri Pankov 		case NAME:
996b34cd89aSYuri Pankov 		case INAME: {
9979ab6dc39Schin 			char *name1;
998b34cd89aSYuri Pankov 			int fnmflags = (np->action == INAME) ?
999b34cd89aSYuri Pankov 			    FNM_IGNORECASE : 0;
10009ab6dc39Schin 
10019ab6dc39Schin 			/*
10029ab6dc39Schin 			 * basename(3c) may modify name, so
10039ab6dc39Schin 			 * we need to pass another string
10049ab6dc39Schin 			 */
10059ab6dc39Schin 			if ((name1 = strdup(name)) == NULL) {
10069ab6dc39Schin 				(void) fprintf(stderr,
10079ab6dc39Schin 				    gettext("%s: cannot strdup() %s: %s\n"),
10086b238a5aSchin 				    cmdname, name, strerror(errno));
10099ab6dc39Schin 				exit(2);
10109ab6dc39Schin 			}
10117c478bd9Sstevel@tonic-gate 			/*
10127c478bd9Sstevel@tonic-gate 			 * XPG4 find should not treat a leading '.' in a
10137c478bd9Sstevel@tonic-gate 			 * filename specially for pattern matching.
10147c478bd9Sstevel@tonic-gate 			 * /usr/bin/find  will not pattern match a leading
10157c478bd9Sstevel@tonic-gate 			 * '.' in a filename, unless '.' is explicitly
10167c478bd9Sstevel@tonic-gate 			 * specified.
10177c478bd9Sstevel@tonic-gate 			 */
1018b34cd89aSYuri Pankov #ifndef XPG4
1019b34cd89aSYuri Pankov 			fnmflags |= FNM_PERIOD;
10207c478bd9Sstevel@tonic-gate #endif
1021b34cd89aSYuri Pankov 			val = !fnmatch(np->first.cp, basename(name1), fnmflags);
10223dcc7f33Schin 			free(name1);
10237c478bd9Sstevel@tonic-gate 			break;
10247c478bd9Sstevel@tonic-gate 		}
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 		case PRUNE:
10277c478bd9Sstevel@tonic-gate 			if (type == FTW_D)
10287c478bd9Sstevel@tonic-gate 				state->quit = FTW_PRUNE;
10297c478bd9Sstevel@tonic-gate 			val = 1;
10307c478bd9Sstevel@tonic-gate 			break;
10317c478bd9Sstevel@tonic-gate 		case NOUSER:
10327c478bd9Sstevel@tonic-gate 			val = ((getpwuid(statb->st_uid)) == 0);
10337c478bd9Sstevel@tonic-gate 			break;
10347c478bd9Sstevel@tonic-gate 		case NOGRP:
10357c478bd9Sstevel@tonic-gate 			val = ((getgrgid(statb->st_gid)) == 0);
10367c478bd9Sstevel@tonic-gate 			break;
10377c478bd9Sstevel@tonic-gate 		case FSTYPE:
10387c478bd9Sstevel@tonic-gate 			val = (strcmp(np->first.cp, statb->st_fstype) == 0);
10397c478bd9Sstevel@tonic-gate 			break;
10407c478bd9Sstevel@tonic-gate 		case CPIO:
10417c478bd9Sstevel@tonic-gate 			output = (FILE *)np->first.l;
10427c478bd9Sstevel@tonic-gate 			(void) fprintf(output, "%s\n", name);
10437c478bd9Sstevel@tonic-gate 			val = 1;
10447c478bd9Sstevel@tonic-gate 			break;
10457c478bd9Sstevel@tonic-gate 		case PRINT:
1046b34cd89aSYuri Pankov 		case PRINT0:
1047b34cd89aSYuri Pankov 			(void) fprintf(stdout, "%s%c", name,
1048b34cd89aSYuri Pankov 			    (np->action == PRINT) ? '\n' : '\0');
10497c478bd9Sstevel@tonic-gate 			val = 1;
10507c478bd9Sstevel@tonic-gate 			break;
10517c478bd9Sstevel@tonic-gate 		case LS:
10527c478bd9Sstevel@tonic-gate 			(void) list(name, statb);
10537c478bd9Sstevel@tonic-gate 			val = 1;
10547c478bd9Sstevel@tonic-gate 			break;
10557c478bd9Sstevel@tonic-gate 		case XATTR:
1056f467e6fbSJohn Sonnenschein 			filename = (walkflags & FTW_CHDIR) ?
1057f467e6fbSJohn Sonnenschein 				gettail(name) : name;
10587c478bd9Sstevel@tonic-gate 			val = (pathconf(filename, _PC_XATTR_EXISTS) == 1);
10597c478bd9Sstevel@tonic-gate 			break;
10607c478bd9Sstevel@tonic-gate 		case ACL:
10617c478bd9Sstevel@tonic-gate 			/*
10627c478bd9Sstevel@tonic-gate 			 * Need to get the tail of the file name, since we have
10637c478bd9Sstevel@tonic-gate 			 * already chdir()ed into the directory (performed in
10647c478bd9Sstevel@tonic-gate 			 * nftw()) of the file
10657c478bd9Sstevel@tonic-gate 			 */
1066f467e6fbSJohn Sonnenschein 			filename = (walkflags & FTW_CHDIR) ?
1067f467e6fbSJohn Sonnenschein 				gettail(name) : name;
1068f467e6fbSJohn Sonnenschein 			val = acl_trivial(filename);
10697c478bd9Sstevel@tonic-gate 			break;
1070b34cd89aSYuri Pankov 		case F_USERACL:
1071b34cd89aSYuri Pankov 		case F_GROUPACL: {
1072b34cd89aSYuri Pankov 			int i;
1073b34cd89aSYuri Pankov 			acl_t *acl;
1074b34cd89aSYuri Pankov 			void *acl_entry;
1075b34cd89aSYuri Pankov 			aclent_t *p1;
1076b34cd89aSYuri Pankov 			ace_t *p2;
1077b34cd89aSYuri Pankov 
1078b34cd89aSYuri Pankov 			filename = (walkflags & FTW_CHDIR) ?
1079b34cd89aSYuri Pankov 			    gettail(name) : name;
1080b34cd89aSYuri Pankov 			val = 0;
1081b34cd89aSYuri Pankov 			if (acl_get(filename, 0, &acl) != 0)
1082b34cd89aSYuri Pankov 				break;
1083b34cd89aSYuri Pankov 			for (i = 0, acl_entry = acl->acl_aclp;
1084b34cd89aSYuri Pankov 			    i != acl->acl_cnt; i++) {
1085b34cd89aSYuri Pankov 				if (acl->acl_type == ACLENT_T) {
1086b34cd89aSYuri Pankov 					p1 = (aclent_t *)acl_entry;
1087b34cd89aSYuri Pankov 					if (p1->a_id == np->first.l) {
1088b34cd89aSYuri Pankov 						val = 1;
1089b34cd89aSYuri Pankov 						acl_free(acl);
1090b34cd89aSYuri Pankov 						break;
1091b34cd89aSYuri Pankov 					}
1092b34cd89aSYuri Pankov 				} else {
1093b34cd89aSYuri Pankov 					p2 = (ace_t *)acl_entry;
1094b34cd89aSYuri Pankov 					if (p2->a_who == np->first.l) {
1095b34cd89aSYuri Pankov 						val = 1;
1096b34cd89aSYuri Pankov 						acl_free(acl);
1097b34cd89aSYuri Pankov 						break;
1098b34cd89aSYuri Pankov 					}
1099b34cd89aSYuri Pankov 				}
1100b34cd89aSYuri Pankov 				acl_entry = ((char *)acl_entry +
1101b34cd89aSYuri Pankov 				    acl->acl_entry_size);
1102b34cd89aSYuri Pankov 			}
1103b34cd89aSYuri Pankov 			acl_free(acl);
1104b34cd89aSYuri Pankov 			break;
1105b34cd89aSYuri Pankov 		}
1106b34cd89aSYuri Pankov 		case IREGEX:
1107b34cd89aSYuri Pankov 		case REGEX: {
1108b34cd89aSYuri Pankov 			regmatch_t pmatch;
1109b34cd89aSYuri Pankov 
1110b34cd89aSYuri Pankov 			val = 0;
1111b34cd89aSYuri Pankov 			if (regexec(&preg[cnpreg], name, 1, &pmatch, NULL) == 0)
1112b34cd89aSYuri Pankov 				val = ((pmatch.rm_so == 0) &&
1113b34cd89aSYuri Pankov 				    (pmatch.rm_eo == strlen(name)));
1114b34cd89aSYuri Pankov 			cnpreg++;
1115b34cd89aSYuri Pankov 			break;
1116b34cd89aSYuri Pankov 		}
1117b34cd89aSYuri Pankov 		case MAXDEPTH:
1118b34cd89aSYuri Pankov 			if (state->level == maxdepth && type == FTW_D)
1119b34cd89aSYuri Pankov 				state->quit = FTW_PRUNE;
1120b34cd89aSYuri Pankov 			/* FALLTHROUGH */
1121b34cd89aSYuri Pankov 		case MINDEPTH:
1122b34cd89aSYuri Pankov 			val = 1;
1123b34cd89aSYuri Pankov 			break;
11247c478bd9Sstevel@tonic-gate 		}
11257c478bd9Sstevel@tonic-gate 		/*
11267c478bd9Sstevel@tonic-gate 		 * evaluate 'val' and 'not' (exclusive-or)
11277c478bd9Sstevel@tonic-gate 		 * if no inversion (not == 1), return only when val == 0
11287c478bd9Sstevel@tonic-gate 		 * (primary not true). Otherwise, invert the primary
11297c478bd9Sstevel@tonic-gate 		 * and return when the primary is true.
11307c478bd9Sstevel@tonic-gate 		 * 'Lastval' saves the last result (fail or pass) when
11317c478bd9Sstevel@tonic-gate 		 * returning back to the calling routine.
11327c478bd9Sstevel@tonic-gate 		 */
11337c478bd9Sstevel@tonic-gate 		if (val^not) {
11347c478bd9Sstevel@tonic-gate 			lastval = 0;
11357c478bd9Sstevel@tonic-gate 			return (0);
11367c478bd9Sstevel@tonic-gate 		}
11377c478bd9Sstevel@tonic-gate 		lastval = 1;
11387c478bd9Sstevel@tonic-gate 		not = 1;
11397c478bd9Sstevel@tonic-gate 		np = np->next;
11407c478bd9Sstevel@tonic-gate 	}
11417c478bd9Sstevel@tonic-gate 	return (0);
11427c478bd9Sstevel@tonic-gate }
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate /*
11457c478bd9Sstevel@tonic-gate  * code for the -ok option
11467c478bd9Sstevel@tonic-gate  */
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate static int
11497c478bd9Sstevel@tonic-gate ok(name, argv)
11507c478bd9Sstevel@tonic-gate char *name;
11517c478bd9Sstevel@tonic-gate char *argv[];
11527c478bd9Sstevel@tonic-gate {
11533d63ea05Sas145665 	int  c;
11543d63ea05Sas145665 	int i = 0;
11553d63ea05Sas145665 	char resp[LINE_MAX + 1];
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	(void) fflush(stdout); 	/* to flush possible `-print' */
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	if ((*argv != dummyarg) && (strcmp(*argv, name)))
11607c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "< %s ... %s >?   ", *argv, name);
11617c478bd9Sstevel@tonic-gate 	else
11627c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "< {} ... %s >?   ", name);
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	(void) fflush(stderr);
11653d63ea05Sas145665 
11663d63ea05Sas145665 	while ((c = getchar()) != '\n') {
11677c478bd9Sstevel@tonic-gate 		if (c == EOF)
11687c478bd9Sstevel@tonic-gate 			exit(2);
11693d63ea05Sas145665 		if (i < LINE_MAX)
11703d63ea05Sas145665 			resp[i++] = c;
11713d63ea05Sas145665 	}
11723d63ea05Sas145665 	resp[i] = '\0';
11733d63ea05Sas145665 
11743d63ea05Sas145665 	if (yes_check(resp))
11753d63ea05Sas145665 		return (doexec(name, argv, NULL));
11767c478bd9Sstevel@tonic-gate 	else
11773d63ea05Sas145665 		return (0);
11787c478bd9Sstevel@tonic-gate }
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate /*
11817c478bd9Sstevel@tonic-gate  * execute argv with {} replaced by name
1182d35170d6Srm88369  *
1183d35170d6Srm88369  * Per XPG6, find must exit non-zero if an invocation through
1184d35170d6Srm88369  * -exec, punctuated by a plus sign, exits non-zero, so set
1185d35170d6Srm88369  * exitcode if we see a non-zero exit.
1186d35170d6Srm88369  * exitcode should be NULL when -exec or -ok is not punctuated
1187d35170d6Srm88369  * by a plus sign.
11887c478bd9Sstevel@tonic-gate  */
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate static int
1191d35170d6Srm88369 doexec(char *name, char *argv[], int *exitcode)
11927c478bd9Sstevel@tonic-gate {
11937c478bd9Sstevel@tonic-gate 	char *cp;
11947c478bd9Sstevel@tonic-gate 	char **av = argv;
1195d35170d6Srm88369 	char *newargs[1 + SHELL_MAXARGS + 1];
11967c478bd9Sstevel@tonic-gate 	int dummyseen = 0;
1197d35170d6Srm88369 	int i, j, status, rc, r = 0;
1198d35170d6Srm88369 	int exit_status = 0;
1199d35170d6Srm88369 	pid_t pid, pid1;
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);	  /* to flush possible `-print' */
12027c478bd9Sstevel@tonic-gate 	if (name) {
12037c478bd9Sstevel@tonic-gate 		while (cp = *av++) {
12047c478bd9Sstevel@tonic-gate 			if (cp == dummyarg) {
12057c478bd9Sstevel@tonic-gate 				dummyseen = 1;
12067c478bd9Sstevel@tonic-gate 				av[-1] = name;
12077c478bd9Sstevel@tonic-gate 			}
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 		}
12107c478bd9Sstevel@tonic-gate 	}
12117c478bd9Sstevel@tonic-gate 	if (argv[0] == NULL)    /* null command line */
12127c478bd9Sstevel@tonic-gate 		return (r);
12137c478bd9Sstevel@tonic-gate 
1214d35170d6Srm88369 	if ((pid = fork()) == -1) {
1215d35170d6Srm88369 		/* fork failed */
1216d35170d6Srm88369 		if (exitcode != NULL)
1217d35170d6Srm88369 			*exitcode = 1;
1218d35170d6Srm88369 		return (0);
1219d35170d6Srm88369 	}
1220d35170d6Srm88369 	if (pid != 0) {
1221d35170d6Srm88369 		/* parent */
1222d35170d6Srm88369 		do {
1223d35170d6Srm88369 			/* wait for child to exit */
1224d35170d6Srm88369 			if ((rc = wait(&r)) == -1 && errno != EINTR) {
1225d35170d6Srm88369 				(void) fprintf(stderr,
1226d35170d6Srm88369 				    gettext("wait failed %s"), strerror(errno));
1227d35170d6Srm88369 
1228d35170d6Srm88369 				if (exitcode != NULL)
1229d35170d6Srm88369 					*exitcode = 1;
1230d35170d6Srm88369 				return (0);
1231d35170d6Srm88369 			}
1232d35170d6Srm88369 		} while (rc != pid);
1233d35170d6Srm88369 	} else {
1234d35170d6Srm88369 		/* child */
12357c478bd9Sstevel@tonic-gate 		(void) execvp(argv[0], argv);
1236d35170d6Srm88369 		if (errno != E2BIG)
1237d35170d6Srm88369 			exit(1);
1238d35170d6Srm88369 
1239d35170d6Srm88369 		/*
1240d35170d6Srm88369 		 * We are in a situation where argv[0] points to a
1241d35170d6Srm88369 		 * script without the interpreter line, e.g. #!/bin/sh.
1242d35170d6Srm88369 		 * execvp() will execute either /usr/bin/sh or
1243d35170d6Srm88369 		 * /usr/xpg4/bin/sh against the script, and you will be
1244d35170d6Srm88369 		 * limited to SHELL_MAXARGS arguments. If you try to
1245d35170d6Srm88369 		 * pass more than SHELL_MAXARGS arguments, execvp()
1246d35170d6Srm88369 		 * fails with E2BIG.
1247d35170d6Srm88369 		 * See usr/src/lib/libc/port/gen/execvp.c.
1248d35170d6Srm88369 		 *
1249d35170d6Srm88369 		 * In this situation, process the argument list by
1250d35170d6Srm88369 		 * packets of SHELL_MAXARGS arguments with respect of
1251d35170d6Srm88369 		 * the following rules:
1252d35170d6Srm88369 		 * 1. the invocations have to complete before find exits
1253d35170d6Srm88369 		 * 2. only one invocation can be running at a time
1254d35170d6Srm88369 		 */
1255d35170d6Srm88369 
1256d35170d6Srm88369 		i = 1;
1257d35170d6Srm88369 		newargs[0] = argv[0];
1258d35170d6Srm88369 
1259d35170d6Srm88369 		while (argv[i]) {
1260d35170d6Srm88369 			j = 1;
1261d35170d6Srm88369 			while (j <= SHELL_MAXARGS && argv[i]) {
1262d35170d6Srm88369 				newargs[j++] = argv[i++];
1263d35170d6Srm88369 			}
1264d35170d6Srm88369 			newargs[j] = NULL;
1265d35170d6Srm88369 
1266d35170d6Srm88369 			if ((pid1 = fork()) == -1) {
1267d35170d6Srm88369 				/* fork failed */
12687c478bd9Sstevel@tonic-gate 				exit(1);
12697c478bd9Sstevel@tonic-gate 			}
1270d35170d6Srm88369 			if (pid1 == 0) {
1271d35170d6Srm88369 				/* child */
1272d35170d6Srm88369 				(void) execvp(newargs[0], newargs);
1273d35170d6Srm88369 				exit(1);
1274d35170d6Srm88369 			}
1275d35170d6Srm88369 
1276d35170d6Srm88369 			status = 0;
1277d35170d6Srm88369 
1278d35170d6Srm88369 			do {
1279d35170d6Srm88369 				/* wait for the child to exit */
1280d35170d6Srm88369 				if ((rc = wait(&status)) == -1 &&
1281d35170d6Srm88369 				    errno != EINTR) {
1282d35170d6Srm88369 					(void) fprintf(stderr,
1283d35170d6Srm88369 					    gettext("wait failed %s"),
1284d35170d6Srm88369 					    strerror(errno));
1285d35170d6Srm88369 					exit(1);
1286d35170d6Srm88369 				}
1287d35170d6Srm88369 			} while (rc != pid1);
1288d35170d6Srm88369 
1289d35170d6Srm88369 			if (status)
1290d35170d6Srm88369 				exit_status = 1;
1291d35170d6Srm88369 		}
1292d35170d6Srm88369 		/* all the invocations have completed */
1293d35170d6Srm88369 		exit(exit_status);
1294d35170d6Srm88369 	}
1295d35170d6Srm88369 
12967c478bd9Sstevel@tonic-gate 	if (name && dummyseen) {
12977c478bd9Sstevel@tonic-gate 		for (av = argv; cp = *av++; ) {
12987c478bd9Sstevel@tonic-gate 			if (cp == name)
12997c478bd9Sstevel@tonic-gate 				av[-1] = dummyarg;
13007c478bd9Sstevel@tonic-gate 		}
13017c478bd9Sstevel@tonic-gate 	}
13027c478bd9Sstevel@tonic-gate 
1303d35170d6Srm88369 	if (r && exitcode != NULL)
1304d35170d6Srm88369 		*exitcode = 3; /* use to indicate error in cmd invocation */
1305d35170d6Srm88369 
13067c478bd9Sstevel@tonic-gate 	return (!r);
13077c478bd9Sstevel@tonic-gate }
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate /*
13117c478bd9Sstevel@tonic-gate  *  Table lookup routine
13127c478bd9Sstevel@tonic-gate  */
13137c478bd9Sstevel@tonic-gate static struct Args *
13147c478bd9Sstevel@tonic-gate lookup(word)
13157c478bd9Sstevel@tonic-gate char *word;
13167c478bd9Sstevel@tonic-gate {
13177c478bd9Sstevel@tonic-gate 	struct Args *argp = commands;
13187c478bd9Sstevel@tonic-gate 	int second;
13197c478bd9Sstevel@tonic-gate 	if (word == 0 || *word == 0)
13207c478bd9Sstevel@tonic-gate 		return (0);
13217c478bd9Sstevel@tonic-gate 	second = word[1];
13227c478bd9Sstevel@tonic-gate 	while (*argp->name) {
13237c478bd9Sstevel@tonic-gate 		if (second == argp->name[1] && strcmp(word, argp->name) == 0)
13247c478bd9Sstevel@tonic-gate 			return (argp);
13257c478bd9Sstevel@tonic-gate 		argp++;
13267c478bd9Sstevel@tonic-gate 	}
13277c478bd9Sstevel@tonic-gate 	return (0);
13287c478bd9Sstevel@tonic-gate }
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate /*
13327c478bd9Sstevel@tonic-gate  * Get space for variable length argument list
13337c478bd9Sstevel@tonic-gate  */
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate static struct Arglist *
13367c478bd9Sstevel@tonic-gate varargs(com)
13377c478bd9Sstevel@tonic-gate char **com;
13387c478bd9Sstevel@tonic-gate {
13397c478bd9Sstevel@tonic-gate 	struct Arglist *ap;
13407c478bd9Sstevel@tonic-gate 	int n;
13417c478bd9Sstevel@tonic-gate 	char **ep;
13427c478bd9Sstevel@tonic-gate 	if (varsize == 0) {
13437c478bd9Sstevel@tonic-gate 		n = 2*sizeof (char **);
13447c478bd9Sstevel@tonic-gate 		for (ep = environ; *ep; ep++)
13457c478bd9Sstevel@tonic-gate 			n += (strlen(*ep)+sizeof (ep) + 1);
13467c478bd9Sstevel@tonic-gate 		varsize = sizeof (struct Arglist)+ARG_MAX-PATH_MAX-n-1;
13477c478bd9Sstevel@tonic-gate 	}
13487c478bd9Sstevel@tonic-gate 	ap = (struct Arglist *)malloc(varsize+1);
13497c478bd9Sstevel@tonic-gate 	ap->end = (char *)ap + varsize;
13507c478bd9Sstevel@tonic-gate 	ap->nextstr = ap->end;
13517c478bd9Sstevel@tonic-gate 	ap->nextvar = ap->arglist;
13527c478bd9Sstevel@tonic-gate 	while (*ap->nextvar++ = *com++);
13537c478bd9Sstevel@tonic-gate 	ap->nextvar--;
13547c478bd9Sstevel@tonic-gate 	ap->firstvar = ap->nextvar;
13557c478bd9Sstevel@tonic-gate 	ap->next = lastlist;
13567c478bd9Sstevel@tonic-gate 	lastlist = ap;
13577c478bd9Sstevel@tonic-gate 	return (ap);
13587c478bd9Sstevel@tonic-gate }
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate /*
13617c478bd9Sstevel@tonic-gate  * filter command support
13627c478bd9Sstevel@tonic-gate  * fork and exec cmd(argv) according to mode:
13637c478bd9Sstevel@tonic-gate  *
13647c478bd9Sstevel@tonic-gate  *	"r"	with fp as stdin of cmd (default stdin), cmd stdout returned
13657c478bd9Sstevel@tonic-gate  *	"w"	with fp as stdout of cmd (default stdout), cmd stdin returned
13667c478bd9Sstevel@tonic-gate  */
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate #define	CMDERR	((1<<8)-1)	/* command error exit code		*/
13697c478bd9Sstevel@tonic-gate #define	MAXCMDS	8		/* max # simultaneous cmdopen()'s	*/
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate static struct			/* info for each cmdopen()		*/
13727c478bd9Sstevel@tonic-gate {
13737c478bd9Sstevel@tonic-gate 	FILE	*fp;		/* returned by cmdopen()		*/
13747c478bd9Sstevel@tonic-gate 	pid_t	pid;		/* pid used by cmdopen()		*/
13757c478bd9Sstevel@tonic-gate } cmdproc[MAXCMDS];
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate static FILE *
13787c478bd9Sstevel@tonic-gate cmdopen(cmd, argv, mode, fp)
13797c478bd9Sstevel@tonic-gate char	*cmd;
13807c478bd9Sstevel@tonic-gate char	**argv;
13817c478bd9Sstevel@tonic-gate char	*mode;
13827c478bd9Sstevel@tonic-gate FILE	*fp;
13837c478bd9Sstevel@tonic-gate {
13847c478bd9Sstevel@tonic-gate 	int	proc;
13857c478bd9Sstevel@tonic-gate 	int	cmdfd;
13867c478bd9Sstevel@tonic-gate 	int	usrfd;
13877c478bd9Sstevel@tonic-gate 	int		pio[2];
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate 	switch (*mode) {
13907c478bd9Sstevel@tonic-gate 	case 'r':
13917c478bd9Sstevel@tonic-gate 		cmdfd = 1;
13927c478bd9Sstevel@tonic-gate 		usrfd = 0;
13937c478bd9Sstevel@tonic-gate 		break;
13947c478bd9Sstevel@tonic-gate 	case 'w':
13957c478bd9Sstevel@tonic-gate 		cmdfd = 0;
13967c478bd9Sstevel@tonic-gate 		usrfd = 1;
13977c478bd9Sstevel@tonic-gate 		break;
13987c478bd9Sstevel@tonic-gate 	default:
13997c478bd9Sstevel@tonic-gate 		return (0);
14007c478bd9Sstevel@tonic-gate 	}
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 	for (proc = 0; proc < MAXCMDS; proc++)
14037c478bd9Sstevel@tonic-gate 		if (!cmdproc[proc].fp)
14047c478bd9Sstevel@tonic-gate 			break;
14057c478bd9Sstevel@tonic-gate 	if (proc >= MAXCMDS)
14067c478bd9Sstevel@tonic-gate 		return (0);
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate 	if (pipe(pio))
14097c478bd9Sstevel@tonic-gate 		return (0);
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	switch (cmdproc[proc].pid = fork()) {
14127c478bd9Sstevel@tonic-gate 	case -1:
14137c478bd9Sstevel@tonic-gate 		return (0);
14147c478bd9Sstevel@tonic-gate 	case 0:
14157c478bd9Sstevel@tonic-gate 		if (fp && fileno(fp) != usrfd) {
14167c478bd9Sstevel@tonic-gate 			(void) close(usrfd);
14177c478bd9Sstevel@tonic-gate 			if (dup2(fileno(fp), usrfd) != usrfd)
14187c478bd9Sstevel@tonic-gate 				_exit(CMDERR);
14197c478bd9Sstevel@tonic-gate 			(void) close(fileno(fp));
14207c478bd9Sstevel@tonic-gate 		}
14217c478bd9Sstevel@tonic-gate 		(void) close(cmdfd);
14227c478bd9Sstevel@tonic-gate 		if (dup2(pio[cmdfd], cmdfd) != cmdfd)
14237c478bd9Sstevel@tonic-gate 			_exit(CMDERR);
14247c478bd9Sstevel@tonic-gate 		(void) close(pio[cmdfd]);
14257c478bd9Sstevel@tonic-gate 		(void) close(pio[usrfd]);
14267c478bd9Sstevel@tonic-gate 		(void) execvp(cmd, argv);
14277c478bd9Sstevel@tonic-gate 		if (errno == ENOEXEC) {
14287c478bd9Sstevel@tonic-gate 			char	**p;
14297c478bd9Sstevel@tonic-gate 			char		**v;
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 			/*
14327c478bd9Sstevel@tonic-gate 			 * assume cmd is a shell script
14337c478bd9Sstevel@tonic-gate 			 */
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 			p = argv;
14367c478bd9Sstevel@tonic-gate 			while (*p++);
14377c478bd9Sstevel@tonic-gate 			if (v = (char **)malloc((p - argv + 1) *
14387c478bd9Sstevel@tonic-gate 					sizeof (char **))) {
14397c478bd9Sstevel@tonic-gate 				p = v;
14407c478bd9Sstevel@tonic-gate 				*p++ = cmd;
14417c478bd9Sstevel@tonic-gate 				if (*argv) argv++;
14427c478bd9Sstevel@tonic-gate 				while (*p++ = *argv++);
14437c478bd9Sstevel@tonic-gate 				(void) execv(getshell(), v);
14447c478bd9Sstevel@tonic-gate 			}
14457c478bd9Sstevel@tonic-gate 		}
14467c478bd9Sstevel@tonic-gate 		_exit(CMDERR);
14477c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
14487c478bd9Sstevel@tonic-gate 	default:
14497c478bd9Sstevel@tonic-gate 		(void) close(pio[cmdfd]);
14507c478bd9Sstevel@tonic-gate 		return (cmdproc[proc].fp = fdopen(pio[usrfd], mode));
14517c478bd9Sstevel@tonic-gate 	}
14527c478bd9Sstevel@tonic-gate }
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate /*
14557c478bd9Sstevel@tonic-gate  * close a stream opened by cmdopen()
14567c478bd9Sstevel@tonic-gate  * -1 returned if cmdopen() had a problem
14577c478bd9Sstevel@tonic-gate  * otherwise exit() status of command is returned
14587c478bd9Sstevel@tonic-gate  */
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate static int
14617c478bd9Sstevel@tonic-gate cmdclose(fp)
14627c478bd9Sstevel@tonic-gate FILE	*fp;
14637c478bd9Sstevel@tonic-gate {
14647c478bd9Sstevel@tonic-gate 	int	i;
14657c478bd9Sstevel@tonic-gate 	pid_t	p, pid;
14667c478bd9Sstevel@tonic-gate 	int		status;
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAXCMDS; i++)
14697c478bd9Sstevel@tonic-gate 		if (fp == cmdproc[i].fp) break;
14707c478bd9Sstevel@tonic-gate 	if (i >= MAXCMDS)
14717c478bd9Sstevel@tonic-gate 		return (-1);
14727c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
14737c478bd9Sstevel@tonic-gate 	cmdproc[i].fp = 0;
14747c478bd9Sstevel@tonic-gate 	pid = cmdproc[i].pid;
14757c478bd9Sstevel@tonic-gate 	while ((p = wait(&status)) != pid && p != (pid_t)-1);
14767c478bd9Sstevel@tonic-gate 	if (p == pid) {
14777c478bd9Sstevel@tonic-gate 		status = (status >> 8) & CMDERR;
14787c478bd9Sstevel@tonic-gate 		if (status == CMDERR)
14797c478bd9Sstevel@tonic-gate 			status = -1;
14807c478bd9Sstevel@tonic-gate 	}
14817c478bd9Sstevel@tonic-gate 	else
14827c478bd9Sstevel@tonic-gate 		status = -1;
14837c478bd9Sstevel@tonic-gate 	return (status);
14847c478bd9Sstevel@tonic-gate }
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate /*
14877c478bd9Sstevel@tonic-gate  * return pointer to the full path name of the shell
14887c478bd9Sstevel@tonic-gate  *
14897c478bd9Sstevel@tonic-gate  * SHELL is read from the environment and must start with /
14907c478bd9Sstevel@tonic-gate  *
14917c478bd9Sstevel@tonic-gate  * if set-uid or set-gid then the executable and its containing
14927c478bd9Sstevel@tonic-gate  * directory must not be writable by the real user
14937c478bd9Sstevel@tonic-gate  *
14947c478bd9Sstevel@tonic-gate  * /usr/bin/sh is returned by default
14957c478bd9Sstevel@tonic-gate  */
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate char *
14987c478bd9Sstevel@tonic-gate getshell()
14997c478bd9Sstevel@tonic-gate {
15007c478bd9Sstevel@tonic-gate 	char	*s;
15017c478bd9Sstevel@tonic-gate 	char	*sh;
15027c478bd9Sstevel@tonic-gate 	uid_t	u;
15037c478bd9Sstevel@tonic-gate 	int	j;
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 	if (((sh = getenv("SHELL")) != 0) && *sh == '/') {
15067c478bd9Sstevel@tonic-gate 		if (u = getuid()) {
15077c478bd9Sstevel@tonic-gate 			if ((u != geteuid() || getgid() != getegid()) &&
15083d63ea05Sas145665 			    access(sh, 2) == 0)
15097c478bd9Sstevel@tonic-gate 				goto defshell;
15107c478bd9Sstevel@tonic-gate 			s = strrchr(sh, '/');
15117c478bd9Sstevel@tonic-gate 			*s = 0;
15127c478bd9Sstevel@tonic-gate 			j = access(sh, 2);
15137c478bd9Sstevel@tonic-gate 			*s = '/';
15147c478bd9Sstevel@tonic-gate 			if (!j) goto defshell;
15157c478bd9Sstevel@tonic-gate 		}
15167c478bd9Sstevel@tonic-gate 		return (sh);
15177c478bd9Sstevel@tonic-gate 	}
15187c478bd9Sstevel@tonic-gate defshell:
15197c478bd9Sstevel@tonic-gate 	return ("/usr/bin/sh");
15207c478bd9Sstevel@tonic-gate }
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate /*
15237c478bd9Sstevel@tonic-gate  * the following functions implement the added "-ls" option
15247c478bd9Sstevel@tonic-gate  */
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate #include <utmpx.h>
15277c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate struct		utmpx utmpx;
15307c478bd9Sstevel@tonic-gate #define	NMAX	(sizeof (utmpx.ut_name))
15317c478bd9Sstevel@tonic-gate #define	SCPYN(a, b)	(void) strncpy(a, b, NMAX)
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate #define	NUID	64
15347c478bd9Sstevel@tonic-gate #define	NGID	64
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate static struct ncache {
15377c478bd9Sstevel@tonic-gate 	int	id;
15387c478bd9Sstevel@tonic-gate 	char	name[NMAX+1];
15397c478bd9Sstevel@tonic-gate } nc[NUID], gc[NGID];
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate /*
15427c478bd9Sstevel@tonic-gate  * This function assumes that the password file is hashed
15437c478bd9Sstevel@tonic-gate  * (or some such) to allow fast access based on a name key.
15447c478bd9Sstevel@tonic-gate  */
15457c478bd9Sstevel@tonic-gate static char *
15467c478bd9Sstevel@tonic-gate getname(uid_t uid)
15477c478bd9Sstevel@tonic-gate {
15487c478bd9Sstevel@tonic-gate 	struct passwd *pw;
15497c478bd9Sstevel@tonic-gate 	int cp;
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate #if	(((NUID) & ((NUID) - 1)) != 0)
15527c478bd9Sstevel@tonic-gate 	cp = uid % (NUID);
15537c478bd9Sstevel@tonic-gate #else
15547c478bd9Sstevel@tonic-gate 	cp = uid & ((NUID) - 1);
15557c478bd9Sstevel@tonic-gate #endif
1556f48205beScasper 	if (nc[cp].id == uid && nc[cp].name[0])
15577c478bd9Sstevel@tonic-gate 		return (nc[cp].name);
15587c478bd9Sstevel@tonic-gate 	pw = getpwuid(uid);
15597c478bd9Sstevel@tonic-gate 	if (!pw)
15607c478bd9Sstevel@tonic-gate 		return (0);
15617c478bd9Sstevel@tonic-gate 	nc[cp].id = uid;
15627c478bd9Sstevel@tonic-gate 	SCPYN(nc[cp].name, pw->pw_name);
15637c478bd9Sstevel@tonic-gate 	return (nc[cp].name);
15647c478bd9Sstevel@tonic-gate }
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate /*
15677c478bd9Sstevel@tonic-gate  * This function assumes that the group file is hashed
15687c478bd9Sstevel@tonic-gate  * (or some such) to allow fast access based on a name key.
15697c478bd9Sstevel@tonic-gate  */
15707c478bd9Sstevel@tonic-gate static char *
15717c478bd9Sstevel@tonic-gate getgroup(gid_t gid)
15727c478bd9Sstevel@tonic-gate {
15737c478bd9Sstevel@tonic-gate 	struct group *gr;
15747c478bd9Sstevel@tonic-gate 	int cp;
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate #if	(((NGID) & ((NGID) - 1)) != 0)
15777c478bd9Sstevel@tonic-gate 	cp = gid % (NGID);
15787c478bd9Sstevel@tonic-gate #else
15797c478bd9Sstevel@tonic-gate 	cp = gid & ((NGID) - 1);
15807c478bd9Sstevel@tonic-gate #endif
1581f48205beScasper 	if (gc[cp].id == gid && gc[cp].name[0])
15827c478bd9Sstevel@tonic-gate 		return (gc[cp].name);
15837c478bd9Sstevel@tonic-gate 	gr = getgrgid(gid);
15847c478bd9Sstevel@tonic-gate 	if (!gr)
15857c478bd9Sstevel@tonic-gate 		return (0);
15867c478bd9Sstevel@tonic-gate 	gc[cp].id = gid;
15877c478bd9Sstevel@tonic-gate 	SCPYN(gc[cp].name, gr->gr_name);
15887c478bd9Sstevel@tonic-gate 	return (gc[cp].name);
15897c478bd9Sstevel@tonic-gate }
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate #define	permoffset(who)		((who) * 3)
15927c478bd9Sstevel@tonic-gate #define	permission(who, type)	((type) >> permoffset(who))
15937c478bd9Sstevel@tonic-gate #define	kbytes(bytes)		(((bytes) + 1023) / 1024)
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate static int
15967c478bd9Sstevel@tonic-gate list(file, stp)
15977c478bd9Sstevel@tonic-gate 	char *file;
15987c478bd9Sstevel@tonic-gate 	struct stat *stp;
15997c478bd9Sstevel@tonic-gate {
16007c478bd9Sstevel@tonic-gate 	char pmode[32], uname[32], gname[32], fsize[32], ftime[32];
1601fa9e4066Sahrens 	int trivial;
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate /*
16047c478bd9Sstevel@tonic-gate  * Each line below contains the relevant permission (column 1) and character
16057c478bd9Sstevel@tonic-gate  * shown when  the corresponding execute bit is either clear (column 2)
16067c478bd9Sstevel@tonic-gate  * or set (column 3)
16077c478bd9Sstevel@tonic-gate  * These permissions are as shown by ls(1b)
16087c478bd9Sstevel@tonic-gate  */
16097c478bd9Sstevel@tonic-gate 	static long special[] = {	S_ISUID, 'S', 's',
16107c478bd9Sstevel@tonic-gate 					S_ISGID, 'S', 's',
16117c478bd9Sstevel@tonic-gate 					S_ISVTX, 'T', 't' };
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	static time_t sixmonthsago = -1;
16147c478bd9Sstevel@tonic-gate #ifdef	S_IFLNK
16157c478bd9Sstevel@tonic-gate 	char flink[MAXPATHLEN + 1];
16167c478bd9Sstevel@tonic-gate #endif
16177c478bd9Sstevel@tonic-gate 	int who;
16187c478bd9Sstevel@tonic-gate 	char *cp;
16197c478bd9Sstevel@tonic-gate 	char *tailname;
16207c478bd9Sstevel@tonic-gate 	time_t now;
16217c478bd9Sstevel@tonic-gate 	long long ksize;
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	if (file == NULL || stp == NULL)
16247c478bd9Sstevel@tonic-gate 		return (-1);
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	(void) time(&now);
16277c478bd9Sstevel@tonic-gate 	if (sixmonthsago == -1)
16287c478bd9Sstevel@tonic-gate 		sixmonthsago = now - 6L*30L*24L*60L*60L;
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 	switch (stp->st_mode & S_IFMT) {
16317c478bd9Sstevel@tonic-gate #ifdef	S_IFDIR
16327c478bd9Sstevel@tonic-gate 	case S_IFDIR:	/* directory */
16337c478bd9Sstevel@tonic-gate 		pmode[0] = 'd';
16347c478bd9Sstevel@tonic-gate 		break;
16357c478bd9Sstevel@tonic-gate #endif
16367c478bd9Sstevel@tonic-gate #ifdef	S_IFCHR
16377c478bd9Sstevel@tonic-gate 	case S_IFCHR:	/* character special */
16387c478bd9Sstevel@tonic-gate 		pmode[0] = 'c';
16397c478bd9Sstevel@tonic-gate 		break;
16407c478bd9Sstevel@tonic-gate #endif
16417c478bd9Sstevel@tonic-gate #ifdef	S_IFBLK
16427c478bd9Sstevel@tonic-gate 	case S_IFBLK:	/* block special */
16437c478bd9Sstevel@tonic-gate 		pmode[0] = 'b';
16447c478bd9Sstevel@tonic-gate 		break;
16457c478bd9Sstevel@tonic-gate #endif
16467c478bd9Sstevel@tonic-gate #ifdef	S_IFIFO
16477c478bd9Sstevel@tonic-gate 	case S_IFIFO:	/* fifo special */
16487c478bd9Sstevel@tonic-gate 		pmode[0] = 'p';
16497c478bd9Sstevel@tonic-gate 		break;
16507c478bd9Sstevel@tonic-gate #endif
16517c478bd9Sstevel@tonic-gate #ifdef	S_IFLNK
16527c478bd9Sstevel@tonic-gate 	case S_IFLNK:	/* symbolic link */
16537c478bd9Sstevel@tonic-gate 		pmode[0] = 'l';
16547c478bd9Sstevel@tonic-gate 		break;
16557c478bd9Sstevel@tonic-gate #endif
16567c478bd9Sstevel@tonic-gate #ifdef	S_IFSOCK
16577c478bd9Sstevel@tonic-gate 	case S_IFSOCK:	/* socket */
16587c478bd9Sstevel@tonic-gate 		pmode[0] = 's';
16597c478bd9Sstevel@tonic-gate 		break;
16607c478bd9Sstevel@tonic-gate #endif
16617c478bd9Sstevel@tonic-gate #ifdef	S_IFDOOR
16627c478bd9Sstevel@tonic-gate 	case S_IFDOOR:	/* door */
16637c478bd9Sstevel@tonic-gate 		pmode[0] = 'D';
16647c478bd9Sstevel@tonic-gate 		break;
16657c478bd9Sstevel@tonic-gate #endif
16667c478bd9Sstevel@tonic-gate #ifdef	S_IFREG
16677c478bd9Sstevel@tonic-gate 	case S_IFREG:	/* regular */
16687c478bd9Sstevel@tonic-gate 		pmode[0] = '-';
16697c478bd9Sstevel@tonic-gate 		break;
16707c478bd9Sstevel@tonic-gate #endif
16717c478bd9Sstevel@tonic-gate 	default:
16727c478bd9Sstevel@tonic-gate 		pmode[0] = '?';
16737c478bd9Sstevel@tonic-gate 		break;
16747c478bd9Sstevel@tonic-gate 	}
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate 	for (who = 0; who < 3; who++) {
16777c478bd9Sstevel@tonic-gate 		int is_exec =  stp->st_mode & permission(who, S_IEXEC)? 1 : 0;
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 		if (stp->st_mode & permission(who, S_IREAD))
16807c478bd9Sstevel@tonic-gate 			pmode[permoffset(who) + 1] = 'r';
16817c478bd9Sstevel@tonic-gate 		else
16827c478bd9Sstevel@tonic-gate 			pmode[permoffset(who) + 1] = '-';
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 		if (stp->st_mode & permission(who, S_IWRITE))
16857c478bd9Sstevel@tonic-gate 			pmode[permoffset(who) + 2] = 'w';
16867c478bd9Sstevel@tonic-gate 		else
16877c478bd9Sstevel@tonic-gate 			pmode[permoffset(who) + 2] = '-';
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate 		if (stp->st_mode & special[who * 3])
16907c478bd9Sstevel@tonic-gate 			pmode[permoffset(who) + 3] =
16917c478bd9Sstevel@tonic-gate 				special[who * 3 + 1 + is_exec];
16927c478bd9Sstevel@tonic-gate 		else if (is_exec)
16937c478bd9Sstevel@tonic-gate 			pmode[permoffset(who) + 3] = 'x';
16947c478bd9Sstevel@tonic-gate 		else
16957c478bd9Sstevel@tonic-gate 			pmode[permoffset(who) + 3] = '-';
16967c478bd9Sstevel@tonic-gate 	}
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate 	/*
16997c478bd9Sstevel@tonic-gate 	 * Need to get the tail of the file name, since we have
17007c478bd9Sstevel@tonic-gate 	 * already chdir()ed into the directory of the file
17017c478bd9Sstevel@tonic-gate 	 */
17027c478bd9Sstevel@tonic-gate 
17037c478bd9Sstevel@tonic-gate 	tailname = gettail(file);
17047c478bd9Sstevel@tonic-gate 
1705fa9e4066Sahrens 	trivial = acl_trivial(tailname);
1706fa9e4066Sahrens 	if (trivial == -1)
1707fa9e4066Sahrens 		trivial =  0;
1708fa9e4066Sahrens 
1709fa9e4066Sahrens 	if (trivial == 1)
17107c478bd9Sstevel@tonic-gate 		pmode[permoffset(who) + 1] = '+';
17117c478bd9Sstevel@tonic-gate 	else
17127c478bd9Sstevel@tonic-gate 		pmode[permoffset(who) + 1] = ' ';
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 	pmode[permoffset(who) + 2] = '\0';
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	/*
17177c478bd9Sstevel@tonic-gate 	 * Prepare uname and gname.  Always add a space afterwards
17187c478bd9Sstevel@tonic-gate 	 * to keep columns from running together.
17197c478bd9Sstevel@tonic-gate 	 */
17207c478bd9Sstevel@tonic-gate 	cp = getname(stp->st_uid);
17217c478bd9Sstevel@tonic-gate 	if (cp != NULL)
17227c478bd9Sstevel@tonic-gate 		(void) sprintf(uname, "%-8s ", cp);
17237c478bd9Sstevel@tonic-gate 	else
1724f48205beScasper 		(void) sprintf(uname, "%-8u ", stp->st_uid);
17257c478bd9Sstevel@tonic-gate 
17267c478bd9Sstevel@tonic-gate 	cp = getgroup(stp->st_gid);
17277c478bd9Sstevel@tonic-gate 	if (cp != NULL)
17287c478bd9Sstevel@tonic-gate 		(void) sprintf(gname, "%-8s ", cp);
17297c478bd9Sstevel@tonic-gate 	else
1730f48205beScasper 		(void) sprintf(gname, "%-8u ", stp->st_gid);
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 	if (pmode[0] == 'b' || pmode[0] == 'c')
17337c478bd9Sstevel@tonic-gate 		(void) sprintf(fsize, "%3ld,%4ld",
17347c478bd9Sstevel@tonic-gate 			major(stp->st_rdev), minor(stp->st_rdev));
17357c478bd9Sstevel@tonic-gate 	else {
17367c478bd9Sstevel@tonic-gate 		(void) sprintf(fsize, (stp->st_size < 100000000) ?
17377c478bd9Sstevel@tonic-gate 			"%8lld" : "%lld", stp->st_size);
17387c478bd9Sstevel@tonic-gate #ifdef	S_IFLNK
17397c478bd9Sstevel@tonic-gate 		if (pmode[0] == 'l') {
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate 			who = readlink(tailname, flink, sizeof (flink) - 1);
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 			if (who >= 0)
17457c478bd9Sstevel@tonic-gate 				flink[who] = '\0';
17467c478bd9Sstevel@tonic-gate 			else
17477c478bd9Sstevel@tonic-gate 				flink[0] = '\0';
17487c478bd9Sstevel@tonic-gate 		}
17497c478bd9Sstevel@tonic-gate #endif
17507c478bd9Sstevel@tonic-gate 	}
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate 	cp = ctime(&stp->st_mtime);
17537c478bd9Sstevel@tonic-gate 	if (stp->st_mtime < sixmonthsago || stp->st_mtime > now)
17547c478bd9Sstevel@tonic-gate 		(void) sprintf(ftime, "%-7.7s %-4.4s", cp + 4, cp + 20);
17557c478bd9Sstevel@tonic-gate 	else
17567c478bd9Sstevel@tonic-gate 		(void) sprintf(ftime, "%-12.12s", cp + 4);
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 	(void) printf((stp->st_ino < 100000) ? "%5llu " :
17597c478bd9Sstevel@tonic-gate 		"%llu ", stp->st_ino);  /* inode #	*/
17607c478bd9Sstevel@tonic-gate #ifdef	S_IFSOCK
17617c478bd9Sstevel@tonic-gate 	ksize = (long long) kbytes(ldbtob(stp->st_blocks)); /* kbytes */
17627c478bd9Sstevel@tonic-gate #else
17637c478bd9Sstevel@tonic-gate 	ksize = (long long) kbytes(stp->st_size); /* kbytes */
17647c478bd9Sstevel@tonic-gate #endif
17657c478bd9Sstevel@tonic-gate 	(void) printf((ksize < 10000) ? "%4lld " : "%lld ", ksize);
17667c478bd9Sstevel@tonic-gate 	(void) printf("%s %2ld %s%s%s %s %s%s%s\n",
17677c478bd9Sstevel@tonic-gate 		pmode,					/* protection	*/
17687c478bd9Sstevel@tonic-gate 		stp->st_nlink,				/* # of links	*/
17697c478bd9Sstevel@tonic-gate 		uname,					/* owner	*/
17707c478bd9Sstevel@tonic-gate 		gname,					/* group	*/
17717c478bd9Sstevel@tonic-gate 		fsize,					/* # of bytes	*/
17727c478bd9Sstevel@tonic-gate 		ftime,					/* modify time	*/
17737c478bd9Sstevel@tonic-gate 		file,					/* name		*/
17747c478bd9Sstevel@tonic-gate #ifdef	S_IFLNK
17757c478bd9Sstevel@tonic-gate 		(pmode[0] == 'l') ? " -> " : "",
17767c478bd9Sstevel@tonic-gate 		(pmode[0] == 'l') ? flink  : ""		/* symlink	*/
17777c478bd9Sstevel@tonic-gate #else
17787c478bd9Sstevel@tonic-gate 		"",
17797c478bd9Sstevel@tonic-gate 		""
17807c478bd9Sstevel@tonic-gate #endif
17817c478bd9Sstevel@tonic-gate );
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate 	return (0);
17847c478bd9Sstevel@tonic-gate }
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate static char *
17877c478bd9Sstevel@tonic-gate new_string(char *s)
17887c478bd9Sstevel@tonic-gate {
17897c478bd9Sstevel@tonic-gate 	char *p = strdup(s);
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	if (p)
17927c478bd9Sstevel@tonic-gate 		return (p);
17937c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: out of memory\n"), cmdname);
17947c478bd9Sstevel@tonic-gate 	exit(1);
17957c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
17967c478bd9Sstevel@tonic-gate }
17977c478bd9Sstevel@tonic-gate 
17987c478bd9Sstevel@tonic-gate /*
17997c478bd9Sstevel@tonic-gate  * Read remote file system types from REMOTE_FS into the
18007c478bd9Sstevel@tonic-gate  * remote_fstypes array.
18017c478bd9Sstevel@tonic-gate  */
18027c478bd9Sstevel@tonic-gate static void
18037c478bd9Sstevel@tonic-gate init_remote_fs()
18047c478bd9Sstevel@tonic-gate {
18057c478bd9Sstevel@tonic-gate 	FILE    *fp;
18067c478bd9Sstevel@tonic-gate 	char    line_buf[LINEBUF_SIZE];
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	if ((fp = fopen(REMOTE_FS, "r")) == NULL) {
18097c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
18107c478bd9Sstevel@tonic-gate 		    gettext("%s: Warning: can't open %s, ignored\n"),
18117c478bd9Sstevel@tonic-gate 		    REMOTE_FS, cmdname);
18127c478bd9Sstevel@tonic-gate 		/* Use default string name for NFS */
18137c478bd9Sstevel@tonic-gate 		remote_fstypes[fstype_index++] = "nfs";
18147c478bd9Sstevel@tonic-gate 		return;
18157c478bd9Sstevel@tonic-gate 	}
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 	while (fgets(line_buf, sizeof (line_buf), fp) != NULL) {
18187c478bd9Sstevel@tonic-gate 		char buf[LINEBUF_SIZE];
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 		/* LINTED - unbounded string specifier */
18217c478bd9Sstevel@tonic-gate 		(void) sscanf(line_buf, "%s", buf);
18227c478bd9Sstevel@tonic-gate 		remote_fstypes[fstype_index++] = new_string(buf);
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 		if (fstype_index == N_FSTYPES)
18257c478bd9Sstevel@tonic-gate 			break;
18267c478bd9Sstevel@tonic-gate 	}
18277c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
18287c478bd9Sstevel@tonic-gate }
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate #define	NPERM	30			/* Largest machine */
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate /*
18337c478bd9Sstevel@tonic-gate  * The PERM struct is the machine that builds permissions.  The p_special
18347c478bd9Sstevel@tonic-gate  * field contains what permissions need to be checked at run-time in
18357c478bd9Sstevel@tonic-gate  * getmode().  This is one of 'X', 'u', 'g', or 'o'.  It contains '\0' to
18367c478bd9Sstevel@tonic-gate  * indicate normal processing.
18377c478bd9Sstevel@tonic-gate  */
18387c478bd9Sstevel@tonic-gate typedef	struct	PERMST	{
18397c478bd9Sstevel@tonic-gate 	ushort_t	p_who;		/* Range of permission (e.g. ugo) */
18407c478bd9Sstevel@tonic-gate 	ushort_t	p_perm;		/* Bits to turn on, off, assign */
18417c478bd9Sstevel@tonic-gate 	uchar_t		p_op;		/* Operation: + - = */
18427c478bd9Sstevel@tonic-gate 	uchar_t		p_special;	/* Special handling? */
18437c478bd9Sstevel@tonic-gate }	PERMST;
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate #ifndef	S_ISVTX
18467c478bd9Sstevel@tonic-gate #define	S_ISVTX	0			/* Not .1 */
18477c478bd9Sstevel@tonic-gate #endif
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate /* Mask values */
18507c478bd9Sstevel@tonic-gate #define	P_A	(S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) /* allbits */
18517c478bd9Sstevel@tonic-gate #define	P_U	(S_ISUID|S_ISVTX|S_IRWXU)		/* user */
18527c478bd9Sstevel@tonic-gate #define	P_G	(S_ISGID|S_ISVTX|S_IRWXG)		/* group */
18537c478bd9Sstevel@tonic-gate #define	P_O	(S_ISVTX|S_IRWXO)			/* other */
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate static	int	iswho(int c);
18567c478bd9Sstevel@tonic-gate static	int	isop(int c);
18577c478bd9Sstevel@tonic-gate static	int	isperm(PERMST *pp, int c);
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate static	PERMST	machine[NPERM];		/* Permission construction machine */
18607c478bd9Sstevel@tonic-gate static	PERMST	*endp;			/* Last used PERM structure */
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate static	uint_t	nowho;			/* No who for this mode (DOS kludge) */
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate /*
18657c478bd9Sstevel@tonic-gate  * Read an ASCII string containing the symbolic/octal mode and
18667c478bd9Sstevel@tonic-gate  * compile an automaton that recognizes it.  The return value
18677c478bd9Sstevel@tonic-gate  * is NULL if everything is OK, otherwise it is -1.
18687c478bd9Sstevel@tonic-gate  */
18697c478bd9Sstevel@tonic-gate static int
18707c478bd9Sstevel@tonic-gate readmode(ascmode)
18717c478bd9Sstevel@tonic-gate const char *ascmode;
18727c478bd9Sstevel@tonic-gate {
18737c478bd9Sstevel@tonic-gate 	const char *amode = ascmode;
18747c478bd9Sstevel@tonic-gate 	PERMST *pp;
18757c478bd9Sstevel@tonic-gate 	int seen_X;
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 	nowho = 0;
18787c478bd9Sstevel@tonic-gate 	seen_X = 0;
18797c478bd9Sstevel@tonic-gate 	pp = &machine[0];
18807c478bd9Sstevel@tonic-gate 	if (*amode >= '0' && *amode <= '7') {
18817c478bd9Sstevel@tonic-gate 		int mode;
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 		mode = 0;
18847c478bd9Sstevel@tonic-gate 		while (*amode >= '0' && *amode <= '7')
18857c478bd9Sstevel@tonic-gate 			mode = (mode<<3) + *amode++ - '0';
18867c478bd9Sstevel@tonic-gate 		if (*amode != '\0')
18877c478bd9Sstevel@tonic-gate 			return (-1);
18887c478bd9Sstevel@tonic-gate #if	S_ISUID != 04000 || S_ISGID != 02000 || \
18897c478bd9Sstevel@tonic-gate 	S_IRUSR != 0400 || S_IWUSR != 0200 || S_IXUSR != 0100 || \
18907c478bd9Sstevel@tonic-gate 	S_IRGRP != 0040 || S_IWGRP != 0020 || S_IXGRP != 0010 || \
18917c478bd9Sstevel@tonic-gate 	S_IROTH != 0004 || S_IWOTH != 0002 || S_IXOTH != 0001
18927c478bd9Sstevel@tonic-gate 		/*
18937c478bd9Sstevel@tonic-gate 		 * There is no requirement of the octal mode bits being
18947c478bd9Sstevel@tonic-gate 		 * the same as the S_ macros.
18957c478bd9Sstevel@tonic-gate 		 */
18967c478bd9Sstevel@tonic-gate 	{
18977c478bd9Sstevel@tonic-gate 		mode_t mapping[] = {
18987c478bd9Sstevel@tonic-gate 			S_IXOTH, S_IWOTH, S_IROTH,
18997c478bd9Sstevel@tonic-gate 			S_IXGRP, S_IWGRP, S_IRGRP,
19007c478bd9Sstevel@tonic-gate 			S_IXUSR, S_IWUSR, S_IRUSR,
19017c478bd9Sstevel@tonic-gate 			S_ISGID, S_ISUID,
19027c478bd9Sstevel@tonic-gate 			0
19037c478bd9Sstevel@tonic-gate 		};
19047c478bd9Sstevel@tonic-gate 		int i, newmode = 0;
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 		for (i = 0; mapping[i] != 0; i++)
19077c478bd9Sstevel@tonic-gate 			if (mode & (1<<i))
19087c478bd9Sstevel@tonic-gate 				newmode |= mapping[i];
19097c478bd9Sstevel@tonic-gate 		mode = newmode;
19107c478bd9Sstevel@tonic-gate 	}
19117c478bd9Sstevel@tonic-gate #endif
19127c478bd9Sstevel@tonic-gate 		pp->p_who = P_A;
19137c478bd9Sstevel@tonic-gate 		pp->p_perm = mode;
19147c478bd9Sstevel@tonic-gate 		pp->p_op = '=';
19157c478bd9Sstevel@tonic-gate 	} else	for (;;) {
19167c478bd9Sstevel@tonic-gate 		int t;
19177c478bd9Sstevel@tonic-gate 		int who = 0;
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 		while ((t = iswho(*amode)) != 0) {
19207c478bd9Sstevel@tonic-gate 			++amode;
19217c478bd9Sstevel@tonic-gate 			who |= t;
19227c478bd9Sstevel@tonic-gate 		}
19237c478bd9Sstevel@tonic-gate 		if (who == 0) {
19247c478bd9Sstevel@tonic-gate 			mode_t currmask;
19257c478bd9Sstevel@tonic-gate 			(void) umask(currmask = umask((mode_t)0));
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate 			/*
19287c478bd9Sstevel@tonic-gate 			 * If no who specified, must use contents of
19297c478bd9Sstevel@tonic-gate 			 * umask to determine which bits to flip.  This
19307c478bd9Sstevel@tonic-gate 			 * is POSIX/V7/BSD behaviour, but not SVID.
19317c478bd9Sstevel@tonic-gate 			 */
19327c478bd9Sstevel@tonic-gate 			who = (~currmask)&P_A;
19337c478bd9Sstevel@tonic-gate 			++nowho;
19347c478bd9Sstevel@tonic-gate 		} else
19357c478bd9Sstevel@tonic-gate 			nowho = 0;
19367c478bd9Sstevel@tonic-gate 	samewho:
19377c478bd9Sstevel@tonic-gate 		if (!isop(pp->p_op = *amode++))
19387c478bd9Sstevel@tonic-gate 			return (-1);
19397c478bd9Sstevel@tonic-gate 		pp->p_perm = 0;
19407c478bd9Sstevel@tonic-gate 		pp->p_special = 0;
19417c478bd9Sstevel@tonic-gate 		while ((t = isperm(pp, *amode)) != 0) {
19427c478bd9Sstevel@tonic-gate 			if (pp->p_special == 'X') {
19437c478bd9Sstevel@tonic-gate 				seen_X = 1;
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 				if (pp->p_perm != 0) {
19467c478bd9Sstevel@tonic-gate 					ushort_t op;
19477c478bd9Sstevel@tonic-gate 
19487c478bd9Sstevel@tonic-gate 					/*
19497c478bd9Sstevel@tonic-gate 					 * Remember the 'who' for the previous
19507c478bd9Sstevel@tonic-gate 					 * transformation.
19517c478bd9Sstevel@tonic-gate 					 */
19527c478bd9Sstevel@tonic-gate 					pp->p_who = who;
19537c478bd9Sstevel@tonic-gate 					pp->p_special = 0;
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 					op = pp->p_op;
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 					/* Keep 'X' separate */
19587c478bd9Sstevel@tonic-gate 					++pp;
19597c478bd9Sstevel@tonic-gate 					pp->p_special = 'X';
19607c478bd9Sstevel@tonic-gate 					pp->p_op = op;
19617c478bd9Sstevel@tonic-gate 				}
19627c478bd9Sstevel@tonic-gate 			} else if (seen_X) {
19637c478bd9Sstevel@tonic-gate 				ushort_t op;
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 				/* Remember the 'who' for the X */
19667c478bd9Sstevel@tonic-gate 				pp->p_who = who;
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate 				op = pp->p_op;
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate 				/* Keep 'X' separate */
19717c478bd9Sstevel@tonic-gate 				++pp;
19727c478bd9Sstevel@tonic-gate 				pp->p_perm = 0;
19737c478bd9Sstevel@tonic-gate 				pp->p_special = 0;
19747c478bd9Sstevel@tonic-gate 				pp->p_op = op;
19757c478bd9Sstevel@tonic-gate 			}
19767c478bd9Sstevel@tonic-gate 			++amode;
19777c478bd9Sstevel@tonic-gate 			pp->p_perm |= t;
19787c478bd9Sstevel@tonic-gate 		}
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 		/*
19817c478bd9Sstevel@tonic-gate 		 * These returned 0, but were actually parsed, so
19827c478bd9Sstevel@tonic-gate 		 * don't look at them again.
19837c478bd9Sstevel@tonic-gate 		 */
19847c478bd9Sstevel@tonic-gate 		switch (pp->p_special) {
19857c478bd9Sstevel@tonic-gate 		case 'u':
19867c478bd9Sstevel@tonic-gate 		case 'g':
19877c478bd9Sstevel@tonic-gate 		case 'o':
19887c478bd9Sstevel@tonic-gate 			++amode;
19897c478bd9Sstevel@tonic-gate 			break;
19907c478bd9Sstevel@tonic-gate 		}
19917c478bd9Sstevel@tonic-gate 		pp->p_who = who;
19927c478bd9Sstevel@tonic-gate 		switch (*amode) {
19937c478bd9Sstevel@tonic-gate 		case '\0':
19947c478bd9Sstevel@tonic-gate 			break;
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate 		case ',':
19977c478bd9Sstevel@tonic-gate 			++amode;
19987c478bd9Sstevel@tonic-gate 			++pp;
19997c478bd9Sstevel@tonic-gate 			continue;
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 		default:
20027c478bd9Sstevel@tonic-gate 			++pp;
20037c478bd9Sstevel@tonic-gate 			goto samewho;
20047c478bd9Sstevel@tonic-gate 		}
20057c478bd9Sstevel@tonic-gate 		break;
20067c478bd9Sstevel@tonic-gate 	}
20077c478bd9Sstevel@tonic-gate 	endp = pp;
20087c478bd9Sstevel@tonic-gate 	return (NULL);
20097c478bd9Sstevel@tonic-gate }
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate /*
20127c478bd9Sstevel@tonic-gate  * Given a character from the mode, return the associated
20137c478bd9Sstevel@tonic-gate  * value as who (user designation) mask or 0 if this isn't valid.
20147c478bd9Sstevel@tonic-gate  */
20157c478bd9Sstevel@tonic-gate static int
20167c478bd9Sstevel@tonic-gate iswho(c)
20177c478bd9Sstevel@tonic-gate int c;
20187c478bd9Sstevel@tonic-gate {
20197c478bd9Sstevel@tonic-gate 	switch (c) {
20207c478bd9Sstevel@tonic-gate 	case 'a':
20217c478bd9Sstevel@tonic-gate 		return (P_A);
20227c478bd9Sstevel@tonic-gate 
20237c478bd9Sstevel@tonic-gate 	case 'u':
20247c478bd9Sstevel@tonic-gate 		return (P_U);
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate 	case 'g':
20277c478bd9Sstevel@tonic-gate 		return (P_G);
20287c478bd9Sstevel@tonic-gate 
20297c478bd9Sstevel@tonic-gate 	case 'o':
20307c478bd9Sstevel@tonic-gate 		return (P_O);
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 	default:
20337c478bd9Sstevel@tonic-gate 		return (0);
20347c478bd9Sstevel@tonic-gate 	}
20357c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
20367c478bd9Sstevel@tonic-gate }
20377c478bd9Sstevel@tonic-gate 
20387c478bd9Sstevel@tonic-gate /*
20397c478bd9Sstevel@tonic-gate  * Return non-zero if this is a valid op code
20407c478bd9Sstevel@tonic-gate  * in a symbolic mode.
20417c478bd9Sstevel@tonic-gate  */
20427c478bd9Sstevel@tonic-gate static int
20437c478bd9Sstevel@tonic-gate isop(c)
20447c478bd9Sstevel@tonic-gate int c;
20457c478bd9Sstevel@tonic-gate {
20467c478bd9Sstevel@tonic-gate 	switch (c) {
20477c478bd9Sstevel@tonic-gate 	case '+':
20487c478bd9Sstevel@tonic-gate 	case '-':
20497c478bd9Sstevel@tonic-gate 	case '=':
20507c478bd9Sstevel@tonic-gate 		return (1);
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	default:
20537c478bd9Sstevel@tonic-gate 		return (0);
20547c478bd9Sstevel@tonic-gate 	}
20557c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
20567c478bd9Sstevel@tonic-gate }
20577c478bd9Sstevel@tonic-gate 
20587c478bd9Sstevel@tonic-gate /*
20597c478bd9Sstevel@tonic-gate  * Return the permission bits implied by this character or 0
20607c478bd9Sstevel@tonic-gate  * if it isn't valid.  Also returns 0 when the pseudo-permissions 'u', 'g', or
20617c478bd9Sstevel@tonic-gate  * 'o' are used, and sets pp->p_special to the one used.
20627c478bd9Sstevel@tonic-gate  */
20637c478bd9Sstevel@tonic-gate static int
20647c478bd9Sstevel@tonic-gate isperm(pp, c)
20657c478bd9Sstevel@tonic-gate PERMST *pp;
20667c478bd9Sstevel@tonic-gate int c;
20677c478bd9Sstevel@tonic-gate {
20687c478bd9Sstevel@tonic-gate 	switch (c) {
20697c478bd9Sstevel@tonic-gate 	case 'u':
20707c478bd9Sstevel@tonic-gate 	case 'g':
20717c478bd9Sstevel@tonic-gate 	case 'o':
20727c478bd9Sstevel@tonic-gate 		pp->p_special = c;
20737c478bd9Sstevel@tonic-gate 		return (0);
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate 	case 'r':
20767c478bd9Sstevel@tonic-gate 		return (S_IRUSR|S_IRGRP|S_IROTH);
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	case 'w':
20797c478bd9Sstevel@tonic-gate 		return (S_IWUSR|S_IWGRP|S_IWOTH);
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 	case 'x':
20827c478bd9Sstevel@tonic-gate 		return (S_IXUSR|S_IXGRP|S_IXOTH);
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate #if S_ISVTX != 0
20857c478bd9Sstevel@tonic-gate 	case 't':
20867c478bd9Sstevel@tonic-gate 		return (S_ISVTX);
20877c478bd9Sstevel@tonic-gate #endif
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 	case 'X':
20907c478bd9Sstevel@tonic-gate 		pp->p_special = 'X';
20917c478bd9Sstevel@tonic-gate 		return (S_IXUSR|S_IXGRP|S_IXOTH);
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate #if S_ISVTX != 0
20947c478bd9Sstevel@tonic-gate 	case 'a':
20957c478bd9Sstevel@tonic-gate 		return (S_ISVTX);
20967c478bd9Sstevel@tonic-gate #endif
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate 	case 'h':
20997c478bd9Sstevel@tonic-gate 		return (S_ISUID);
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 	/*
21027c478bd9Sstevel@tonic-gate 	 * This change makes:
21037c478bd9Sstevel@tonic-gate 	 *	chmod +s file
21047c478bd9Sstevel@tonic-gate 	 * set the system bit on dos but means that
21057c478bd9Sstevel@tonic-gate 	 *	chmod u+s file
21067c478bd9Sstevel@tonic-gate 	 *	chmod g+s file
21077c478bd9Sstevel@tonic-gate 	 *	chmod a+s file
21087c478bd9Sstevel@tonic-gate 	 * are all like UNIX.
21097c478bd9Sstevel@tonic-gate 	 */
21107c478bd9Sstevel@tonic-gate 	case 's':
21117c478bd9Sstevel@tonic-gate 		return (nowho ? S_ISGID : S_ISGID|S_ISUID);
21127c478bd9Sstevel@tonic-gate 
21137c478bd9Sstevel@tonic-gate 	default:
21147c478bd9Sstevel@tonic-gate 		return (0);
21157c478bd9Sstevel@tonic-gate 	}
21167c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
21177c478bd9Sstevel@tonic-gate }
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate /*
21207c478bd9Sstevel@tonic-gate  * Execute the automaton that is created by readmode()
21217c478bd9Sstevel@tonic-gate  * to generate the final mode that will be used.  This
21227c478bd9Sstevel@tonic-gate  * code is passed a starting mode that is usually the original
21237c478bd9Sstevel@tonic-gate  * mode of the file being changed (or 0).  Note that this mode must contain
21247c478bd9Sstevel@tonic-gate  * the file-type bits as well, so that S_ISDIR will succeed on directories.
21257c478bd9Sstevel@tonic-gate  */
21267c478bd9Sstevel@tonic-gate static mode_t
21277c478bd9Sstevel@tonic-gate getmode(mode_t startmode)
21287c478bd9Sstevel@tonic-gate {
21297c478bd9Sstevel@tonic-gate 	PERMST *pp;
21307c478bd9Sstevel@tonic-gate 	mode_t temp;
21317c478bd9Sstevel@tonic-gate 	mode_t perm;
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate 	for (pp = &machine[0]; pp <= endp; ++pp) {
21347c478bd9Sstevel@tonic-gate 		perm = (mode_t)0;
21357c478bd9Sstevel@tonic-gate 		/*
21367c478bd9Sstevel@tonic-gate 		 * For the special modes 'u', 'g' and 'o', the named portion
21377c478bd9Sstevel@tonic-gate 		 * of the mode refers to after the previous clause has been
21387c478bd9Sstevel@tonic-gate 		 * processed, while the 'X' mode refers to the contents of the
21397c478bd9Sstevel@tonic-gate 		 * mode before any clauses have been processed.
21407c478bd9Sstevel@tonic-gate 		 *
21417c478bd9Sstevel@tonic-gate 		 * References: P1003.2/D11.2, Section 4.7.7,
21427c478bd9Sstevel@tonic-gate 		 *  lines 2568-2570, 2578-2583
21437c478bd9Sstevel@tonic-gate 		 */
21447c478bd9Sstevel@tonic-gate 		switch (pp->p_special) {
21457c478bd9Sstevel@tonic-gate 		case 'u':
21467c478bd9Sstevel@tonic-gate 			temp = startmode & S_IRWXU;
21477c478bd9Sstevel@tonic-gate 			if (temp & (S_IRUSR|S_IRGRP|S_IROTH))
21487c478bd9Sstevel@tonic-gate 				perm |= ((S_IRUSR|S_IRGRP|S_IROTH) &
21497c478bd9Sstevel@tonic-gate 				    pp->p_who);
21507c478bd9Sstevel@tonic-gate 			if (temp & (S_IWUSR|S_IWGRP|S_IWOTH))
21517c478bd9Sstevel@tonic-gate 				perm |= ((S_IWUSR|S_IWGRP|S_IWOTH) & pp->p_who);
21527c478bd9Sstevel@tonic-gate 			if (temp & (S_IXUSR|S_IXGRP|S_IXOTH))
21537c478bd9Sstevel@tonic-gate 				perm |= ((S_IXUSR|S_IXGRP|S_IXOTH) & pp->p_who);
21547c478bd9Sstevel@tonic-gate 			break;
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate 		case 'g':
21577c478bd9Sstevel@tonic-gate 			temp = startmode & S_IRWXG;
21587c478bd9Sstevel@tonic-gate 			if (temp & (S_IRUSR|S_IRGRP|S_IROTH))
21597c478bd9Sstevel@tonic-gate 				perm |= ((S_IRUSR|S_IRGRP|S_IROTH) & pp->p_who);
21607c478bd9Sstevel@tonic-gate 			if (temp & (S_IWUSR|S_IWGRP|S_IWOTH))
21617c478bd9Sstevel@tonic-gate 				perm |= ((S_IWUSR|S_IWGRP|S_IWOTH) & pp->p_who);
21627c478bd9Sstevel@tonic-gate 			if (temp & (S_IXUSR|S_IXGRP|S_IXOTH))
21637c478bd9Sstevel@tonic-gate 				perm |= ((S_IXUSR|S_IXGRP|S_IXOTH) & pp->p_who);
21647c478bd9Sstevel@tonic-gate 			break;
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate 		case 'o':
21677c478bd9Sstevel@tonic-gate 			temp = startmode & S_IRWXO;
21687c478bd9Sstevel@tonic-gate 			if (temp & (S_IRUSR|S_IRGRP|S_IROTH))
21697c478bd9Sstevel@tonic-gate 				perm |= ((S_IRUSR|S_IRGRP|S_IROTH) & pp->p_who);
21707c478bd9Sstevel@tonic-gate 			if (temp & (S_IWUSR|S_IWGRP|S_IWOTH))
21717c478bd9Sstevel@tonic-gate 				perm |= ((S_IWUSR|S_IWGRP|S_IWOTH) & pp->p_who);
21727c478bd9Sstevel@tonic-gate 			if (temp & (S_IXUSR|S_IXGRP|S_IXOTH))
21737c478bd9Sstevel@tonic-gate 				perm |= ((S_IXUSR|S_IXGRP|S_IXOTH) & pp->p_who);
21747c478bd9Sstevel@tonic-gate 			break;
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate 		case 'X':
21777c478bd9Sstevel@tonic-gate 			perm = pp->p_perm;
21787c478bd9Sstevel@tonic-gate 			break;
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate 		default:
21817c478bd9Sstevel@tonic-gate 			perm = pp->p_perm;
21827c478bd9Sstevel@tonic-gate 			break;
21837c478bd9Sstevel@tonic-gate 		}
21847c478bd9Sstevel@tonic-gate 		switch (pp->p_op) {
21857c478bd9Sstevel@tonic-gate 		case '-':
21867c478bd9Sstevel@tonic-gate 			startmode &= ~(perm & pp->p_who);
21877c478bd9Sstevel@tonic-gate 			break;
21887c478bd9Sstevel@tonic-gate 
21897c478bd9Sstevel@tonic-gate 		case '=':
21907c478bd9Sstevel@tonic-gate 			startmode &= ~pp->p_who;
21917c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
21927c478bd9Sstevel@tonic-gate 		case '+':
21937c478bd9Sstevel@tonic-gate 			startmode |= (perm & pp->p_who);
21947c478bd9Sstevel@tonic-gate 			break;
21957c478bd9Sstevel@tonic-gate 		}
21967c478bd9Sstevel@tonic-gate 	}
21977c478bd9Sstevel@tonic-gate 	return (startmode);
21987c478bd9Sstevel@tonic-gate }
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate /*
22017c478bd9Sstevel@tonic-gate  * Returns the last component of a path name, unless it is
22027c478bd9Sstevel@tonic-gate  * an absolute path, in which case it returns the whole path
22037c478bd9Sstevel@tonic-gate  */
22047c478bd9Sstevel@tonic-gate static char
22057c478bd9Sstevel@tonic-gate *gettail(char *fname)
22067c478bd9Sstevel@tonic-gate {
22077c478bd9Sstevel@tonic-gate 	char	*base = fname;
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	if (*fname != '/') {
22107c478bd9Sstevel@tonic-gate 		if ((base = strrchr(fname, '/')) != NULL)
22117c478bd9Sstevel@tonic-gate 			base++;
22127c478bd9Sstevel@tonic-gate 		else
22137c478bd9Sstevel@tonic-gate 			base = fname;
22147c478bd9Sstevel@tonic-gate 	}
22157c478bd9Sstevel@tonic-gate 	return (base);
22167c478bd9Sstevel@tonic-gate }
2217