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