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.
2303f45afcSYuri Pankov * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
2405f32410SAndy Stormont * Copyright (c) 2013 Andrew Stormont. All rights reserved.
25f3a525d9SJohn Levon * Copyright 2020 Joyent, Inc.
26*ba5b88a2SBill Sommerfeld * Copyright 2023 Bill Sommerfeld <sommerfeld@alum.mit.edu>
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate
29da1a9cbeSjonb
307c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
317c478bd9Sstevel@tonic-gate /* All Rights Reserved */
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate /* Parts of this product may be derived from */
357c478bd9Sstevel@tonic-gate /* Mortice Kern Systems Inc. and Berkeley 4.3 BSD systems. */
367c478bd9Sstevel@tonic-gate /* licensed from Mortice Kern Systems Inc. and */
377c478bd9Sstevel@tonic-gate /* the University of California. */
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate * Copyright 1985, 1990 by Mortice Kern Systems Inc. All rights reserved.
417c478bd9Sstevel@tonic-gate */
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate #include <stdio.h>
447c478bd9Sstevel@tonic-gate #include <errno.h>
457c478bd9Sstevel@tonic-gate #include <pwd.h>
467c478bd9Sstevel@tonic-gate #include <grp.h>
477c478bd9Sstevel@tonic-gate #include <sys/types.h>
487c478bd9Sstevel@tonic-gate #include <sys/stat.h>
497c478bd9Sstevel@tonic-gate #include <sys/param.h>
507c478bd9Sstevel@tonic-gate #include <sys/acl.h>
517c478bd9Sstevel@tonic-gate #include <limits.h>
527c478bd9Sstevel@tonic-gate #include <unistd.h>
537c478bd9Sstevel@tonic-gate #include <stdlib.h>
547c478bd9Sstevel@tonic-gate #include <locale.h>
557c478bd9Sstevel@tonic-gate #include <string.h>
567c478bd9Sstevel@tonic-gate #include <strings.h>
577c478bd9Sstevel@tonic-gate #include <ctype.h>
587c478bd9Sstevel@tonic-gate #include <wait.h>
597c478bd9Sstevel@tonic-gate #include <fnmatch.h>
607c478bd9Sstevel@tonic-gate #include <langinfo.h>
617c478bd9Sstevel@tonic-gate #include <ftw.h>
629ab6dc39Schin #include <libgen.h>
63b34cd89aSYuri Pankov #include <err.h>
64b34cd89aSYuri Pankov #include <regex.h>
653d63ea05Sas145665 #include "getresponse.h"
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate #define A_DAY (long)(60*60*24) /* a day full of seconds */
68da1a9cbeSjonb #define A_MIN (long)(60)
697c478bd9Sstevel@tonic-gate #define BLKSIZ 512
707c478bd9Sstevel@tonic-gate #define round(x, s) (((x)+(s)-1)&~((s)-1))
717c478bd9Sstevel@tonic-gate #ifndef FTW_SLN
727c478bd9Sstevel@tonic-gate #define FTW_SLN 7
737c478bd9Sstevel@tonic-gate #endif
747c478bd9Sstevel@tonic-gate #define LINEBUF_SIZE LINE_MAX /* input or output lines */
757c478bd9Sstevel@tonic-gate #define REMOTE_FS "/etc/dfs/fstypes"
767c478bd9Sstevel@tonic-gate #define N_FSTYPES 20
77d35170d6Srm88369 #define SHELL_MAXARGS 253 /* see doexec() for description */
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate * This is the list of operations
817c478bd9Sstevel@tonic-gate * F_USER and F_GROUP are named to avoid conflict with USER and GROUP defined
827c478bd9Sstevel@tonic-gate * in sys/acl.h
837c478bd9Sstevel@tonic-gate */
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate enum Command
867c478bd9Sstevel@tonic-gate {
87b34cd89aSYuri Pankov PRINT,
88b34cd89aSYuri Pankov ACL, AMIN, AND, ATIME, CMIN, CPIO, CSIZE, CTIME, DEPTH, EXEC, F_GROUP,
8905f32410SAndy Stormont F_GROUPACL, F_USER, F_USERACL, FOLLOW, FSTYPE, INAME, INUM, IPATH,
9005f32410SAndy Stormont IREGEX, LINKS, LOCAL, LPAREN, LS, MAXDEPTH, MINDEPTH, MMIN, MOUNT,
9105f32410SAndy Stormont MTIME, NAME, NCPIO, NEWER, NOGRP, NOT, NOUSER, OK, OR, PATH, PERM,
92ab823b7fSPrasad Joshi PRINT0, PRUNE, REGEX, RPAREN, SIZE, TYPE, VARARGS, XATTR, DELETE
937c478bd9Sstevel@tonic-gate };
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate enum Type
967c478bd9Sstevel@tonic-gate {
977c478bd9Sstevel@tonic-gate Unary, Id, Num, Str, Exec, Cpio, Op
987c478bd9Sstevel@tonic-gate };
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate struct Args
1017c478bd9Sstevel@tonic-gate {
1027c478bd9Sstevel@tonic-gate char name[10];
1037c478bd9Sstevel@tonic-gate enum Command action;
1047c478bd9Sstevel@tonic-gate enum Type type;
1057c478bd9Sstevel@tonic-gate };
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate * Except for pathnames, these are the only legal arguments
1097c478bd9Sstevel@tonic-gate */
1107c478bd9Sstevel@tonic-gate static struct Args commands[] =
1117c478bd9Sstevel@tonic-gate {
1127c478bd9Sstevel@tonic-gate "!", NOT, Op,
1137c478bd9Sstevel@tonic-gate "(", LPAREN, Unary,
1147c478bd9Sstevel@tonic-gate ")", RPAREN, Unary,
1157c478bd9Sstevel@tonic-gate "-a", AND, Op,
116b34cd89aSYuri Pankov "-acl", ACL, Unary,
117da1a9cbeSjonb "-amin", AMIN, Num,
118b34cd89aSYuri Pankov "-and", AND, Op,
1197c478bd9Sstevel@tonic-gate "-atime", ATIME, Num,
120da1a9cbeSjonb "-cmin", CMIN, Num,
121b34cd89aSYuri Pankov "-cpio", CPIO, Cpio,
1227c478bd9Sstevel@tonic-gate "-ctime", CTIME, Num,
1237c478bd9Sstevel@tonic-gate "-depth", DEPTH, Unary,
124ab823b7fSPrasad Joshi "-delete", DELETE, Unary,
1257c478bd9Sstevel@tonic-gate "-exec", EXEC, Exec,
1267c478bd9Sstevel@tonic-gate "-follow", FOLLOW, Unary,
127b34cd89aSYuri Pankov "-fstype", FSTYPE, Str,
1287c478bd9Sstevel@tonic-gate "-group", F_GROUP, Num,
129b34cd89aSYuri Pankov "-groupacl", F_GROUPACL, Num,
130b34cd89aSYuri Pankov "-iname", INAME, Str,
1317c478bd9Sstevel@tonic-gate "-inum", INUM, Num,
13205f32410SAndy Stormont "-ipath", IPATH, Str,
133b34cd89aSYuri Pankov "-iregex", IREGEX, Str,
13403f45afcSYuri Pankov "-links", LINKS, Num,
13503f45afcSYuri Pankov "-local", LOCAL, Unary,
136b34cd89aSYuri Pankov "-ls", LS, Unary,
137b34cd89aSYuri Pankov "-maxdepth", MAXDEPTH, Num,
138b34cd89aSYuri Pankov "-mindepth", MINDEPTH, Num,
139da1a9cbeSjonb "-mmin", MMIN, Num,
140b34cd89aSYuri Pankov "-mount", MOUNT, Unary,
1417c478bd9Sstevel@tonic-gate "-mtime", MTIME, Num,
1427c478bd9Sstevel@tonic-gate "-name", NAME, Str,
1437c478bd9Sstevel@tonic-gate "-ncpio", NCPIO, Cpio,
1447c478bd9Sstevel@tonic-gate "-newer", NEWER, Str,
145b34cd89aSYuri Pankov "-nogroup", NOGRP, Unary,
146b34cd89aSYuri Pankov "-not", NOT, Op,
147b34cd89aSYuri Pankov "-nouser", NOUSER, Unary,
1487c478bd9Sstevel@tonic-gate "-o", OR, Op,
1497c478bd9Sstevel@tonic-gate "-ok", OK, Exec,
150b34cd89aSYuri Pankov "-or", OR, Op,
15105f32410SAndy Stormont "-path", PATH, Str,
1527c478bd9Sstevel@tonic-gate "-perm", PERM, Num,
1537c478bd9Sstevel@tonic-gate "-print", PRINT, Unary,
154b34cd89aSYuri Pankov "-print0", PRINT0, Unary,
155b34cd89aSYuri Pankov "-prune", PRUNE, Unary,
156b34cd89aSYuri Pankov "-regex", REGEX, Str,
1577c478bd9Sstevel@tonic-gate "-size", SIZE, Num,
1587c478bd9Sstevel@tonic-gate "-type", TYPE, Num,
1597c478bd9Sstevel@tonic-gate "-user", F_USER, Num,
160b34cd89aSYuri Pankov "-useracl", F_USERACL, Num,
1617c478bd9Sstevel@tonic-gate "-xattr", XATTR, Unary,
162b34cd89aSYuri Pankov "-xdev", MOUNT, Unary,
16327d3a169SToomas Soome 0, 0, 0
1647c478bd9Sstevel@tonic-gate };
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate union Item
1677c478bd9Sstevel@tonic-gate {
1687c478bd9Sstevel@tonic-gate struct Node *np;
1697c478bd9Sstevel@tonic-gate struct Arglist *vp;
1707c478bd9Sstevel@tonic-gate time_t t;
1717c478bd9Sstevel@tonic-gate char *cp;
1727c478bd9Sstevel@tonic-gate char **ap;
1737c478bd9Sstevel@tonic-gate long l;
1747c478bd9Sstevel@tonic-gate int i;
1757c478bd9Sstevel@tonic-gate long long ll;
1767c478bd9Sstevel@tonic-gate };
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate struct Node
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate struct Node *next;
1817c478bd9Sstevel@tonic-gate enum Command action;
1827c478bd9Sstevel@tonic-gate enum Type type;
1837c478bd9Sstevel@tonic-gate union Item first;
1847c478bd9Sstevel@tonic-gate union Item second;
1857c478bd9Sstevel@tonic-gate };
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate /* if no -print, -exec or -ok replace "expression" with "(expression) -print" */
1887c478bd9Sstevel@tonic-gate static struct Node PRINT_NODE = { 0, PRINT, 0, 0};
1897c478bd9Sstevel@tonic-gate static struct Node LPAREN_NODE = { 0, LPAREN, 0, 0};
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate /*
1937c478bd9Sstevel@tonic-gate * Prototype variable size arglist buffer
1947c478bd9Sstevel@tonic-gate */
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate struct Arglist
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate struct Arglist *next;
1997c478bd9Sstevel@tonic-gate char *end;
2007c478bd9Sstevel@tonic-gate char *nextstr;
2017c478bd9Sstevel@tonic-gate char **firstvar;
2027c478bd9Sstevel@tonic-gate char **nextvar;
2037c478bd9Sstevel@tonic-gate char *arglist[1];
2047c478bd9Sstevel@tonic-gate };
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate
20727d3a169SToomas Soome static int compile(char **, struct Node *, int *);
20827d3a169SToomas Soome static int execute(const char *, const struct stat *, int,
20927d3a169SToomas Soome struct FTW *);
21027d3a169SToomas Soome static int doexec(const char *, char **, int *);
21127d3a169SToomas Soome static int dodelete(const char *, const struct stat *,
21227d3a169SToomas Soome struct FTW *);
21327d3a169SToomas Soome static struct Args *lookup(char *);
21427d3a169SToomas Soome static int ok(const char *, char *[]);
2156c83d09fSrobbin static void usage(void) __NORETURN;
21627d3a169SToomas Soome static struct Arglist *varargs(char **);
21727d3a169SToomas Soome static int list(const char *, const struct stat *);
21827d3a169SToomas Soome static char *getgroup(gid_t);
21927d3a169SToomas Soome static FILE *cmdopen(char *, char **, char *, FILE *);
22027d3a169SToomas Soome static int cmdclose(FILE *);
22127d3a169SToomas Soome static char *getshell(void);
22227d3a169SToomas Soome static void init_remote_fs(void);
22327d3a169SToomas Soome static char *getname(uid_t);
22427d3a169SToomas Soome static int readmode(const char *);
22527d3a169SToomas Soome static mode_t getmode(mode_t);
22627d3a169SToomas Soome static const char *gettail(const char *);
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate
22968a94df1Scf46844 static int walkflags = FTW_CHDIR|FTW_PHYS|FTW_ANYERR|FTW_NOLOOP;
2307c478bd9Sstevel@tonic-gate static struct Node *topnode;
2317c478bd9Sstevel@tonic-gate static struct Node *freenode; /* next free node we may use later */
2327c478bd9Sstevel@tonic-gate static char *cpio[] = { "cpio", "-o", 0 };
2337c478bd9Sstevel@tonic-gate static char *ncpio[] = { "cpio", "-oc", 0 };
2347c478bd9Sstevel@tonic-gate static char *cpiol[] = { "cpio", "-oL", 0 };
2357c478bd9Sstevel@tonic-gate static char *ncpiol[] = { "cpio", "-ocL", 0 };
2367c478bd9Sstevel@tonic-gate static time_t now;
2377c478bd9Sstevel@tonic-gate static FILE *output;
2387c478bd9Sstevel@tonic-gate static char *dummyarg = (char *)-1;
2397c478bd9Sstevel@tonic-gate static int lastval;
2407c478bd9Sstevel@tonic-gate static int varsize;
2417c478bd9Sstevel@tonic-gate static struct Arglist *lastlist;
2427c478bd9Sstevel@tonic-gate static char *cmdname;
2437c478bd9Sstevel@tonic-gate static char *remote_fstypes[N_FSTYPES+1];
2447c478bd9Sstevel@tonic-gate static int fstype_index = 0;
2457c478bd9Sstevel@tonic-gate static int action_expression = 0; /* -print, -exec, or -ok */
2467c478bd9Sstevel@tonic-gate static int error = 0;
2477c478bd9Sstevel@tonic-gate static int paren_cnt = 0; /* keeps track of parentheses */
248b34cd89aSYuri Pankov static int Eflag = 0;
2497c478bd9Sstevel@tonic-gate static int hflag = 0;
2507c478bd9Sstevel@tonic-gate static int lflag = 0;
251d35170d6Srm88369 /* set when doexec()-invoked utility returns non-zero */
252d35170d6Srm88369 static int exec_exitcode = 0;
253b34cd89aSYuri Pankov static regex_t *preg = NULL;
254b34cd89aSYuri Pankov static int npreg = 0;
255b34cd89aSYuri Pankov static int mindepth = -1, maxdepth = -1;
2567c478bd9Sstevel@tonic-gate extern char **environ;
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)2597c478bd9Sstevel@tonic-gate main(int argc, char **argv)
2607c478bd9Sstevel@tonic-gate {
2617c478bd9Sstevel@tonic-gate char *cp;
2627c478bd9Sstevel@tonic-gate int c;
2637c478bd9Sstevel@tonic-gate int paths;
2647c478bd9Sstevel@tonic-gate char *cwdpath;
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
2677c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
2687c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
2697c478bd9Sstevel@tonic-gate #endif
2707c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate cmdname = argv[0];
2737c478bd9Sstevel@tonic-gate if (time(&now) == (time_t)(-1)) {
2747c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: time() %s\n"),
2757c478bd9Sstevel@tonic-gate cmdname, strerror(errno));
2767c478bd9Sstevel@tonic-gate exit(1);
2777c478bd9Sstevel@tonic-gate }
278b34cd89aSYuri Pankov while ((c = getopt(argc, argv, "EHL")) != -1) {
2797c478bd9Sstevel@tonic-gate switch (c) {
280b34cd89aSYuri Pankov case 'E':
281b34cd89aSYuri Pankov Eflag = 1;
282b34cd89aSYuri Pankov break;
2837c478bd9Sstevel@tonic-gate case 'H':
2847c478bd9Sstevel@tonic-gate hflag = 1;
2857c478bd9Sstevel@tonic-gate lflag = 0;
2867c478bd9Sstevel@tonic-gate break;
2877c478bd9Sstevel@tonic-gate case 'L':
2887c478bd9Sstevel@tonic-gate hflag = 0;
2897c478bd9Sstevel@tonic-gate lflag = 1;
2907c478bd9Sstevel@tonic-gate break;
2917c478bd9Sstevel@tonic-gate case '?':
2927c478bd9Sstevel@tonic-gate usage();
2937c478bd9Sstevel@tonic-gate break;
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate argc -= optind;
2987c478bd9Sstevel@tonic-gate argv += optind;
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate if (argc < 1) {
3017c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
3027c478bd9Sstevel@tonic-gate gettext("%s: insufficient number of arguments\n"), cmdname);
3037c478bd9Sstevel@tonic-gate usage();
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate for (paths = 0; (cp = argv[paths]) != 0; ++paths) {
3077c478bd9Sstevel@tonic-gate if (*cp == '-')
3087c478bd9Sstevel@tonic-gate break;
3097c478bd9Sstevel@tonic-gate else if ((*cp == '!' || *cp == '(') && *(cp+1) == 0)
3107c478bd9Sstevel@tonic-gate break;
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate if (paths == 0) /* no path-list */
3147c478bd9Sstevel@tonic-gate usage();
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate output = stdout;
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate /* lflag is the same as -follow */
3197c478bd9Sstevel@tonic-gate if (lflag)
3207c478bd9Sstevel@tonic-gate walkflags &= ~FTW_PHYS;
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate /* allocate enough space for the compiler */
3237c478bd9Sstevel@tonic-gate topnode = malloc((argc + 1) * sizeof (struct Node));
3247c478bd9Sstevel@tonic-gate (void) memset(topnode, 0, (argc + 1) * sizeof (struct Node));
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate if (compile(argv + paths, topnode, &action_expression) == 0) {
3277c478bd9Sstevel@tonic-gate /* no expression, default to -print */
3287c478bd9Sstevel@tonic-gate (void) memcpy(topnode, &PRINT_NODE, sizeof (struct Node));
3297c478bd9Sstevel@tonic-gate } else if (!action_expression) {
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate * if no action expression, insert an LPAREN node above topnode,
3327c478bd9Sstevel@tonic-gate * with a PRINT node as its next node
3337c478bd9Sstevel@tonic-gate */
3347c478bd9Sstevel@tonic-gate struct Node *savenode;
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate if (freenode == NULL) {
3377c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: can't append -print"
3387c478bd9Sstevel@tonic-gate " implicitly; try explicit -print option\n"),
3397c478bd9Sstevel@tonic-gate cmdname);
3407c478bd9Sstevel@tonic-gate exit(1);
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate savenode = topnode;
3437c478bd9Sstevel@tonic-gate topnode = freenode++;
3447c478bd9Sstevel@tonic-gate (void) memcpy(topnode, &LPAREN_NODE, sizeof (struct Node));
3457c478bd9Sstevel@tonic-gate topnode->next = freenode;
3467c478bd9Sstevel@tonic-gate topnode->first.np = savenode;
3477c478bd9Sstevel@tonic-gate (void) memcpy(topnode->next, &PRINT_NODE, sizeof (struct Node));
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate while (paths--) {
3517c478bd9Sstevel@tonic-gate char *curpath;
3527c478bd9Sstevel@tonic-gate struct stat sb;
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate curpath = *(argv++);
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate /*
3577c478bd9Sstevel@tonic-gate * If -H is specified, it means we walk the first
3587c478bd9Sstevel@tonic-gate * level (pathname on command line) logically, following
3597c478bd9Sstevel@tonic-gate * symlinks, but lower levels are walked physically.
3607c478bd9Sstevel@tonic-gate * We use our own secret interface to nftw() to change
3617c478bd9Sstevel@tonic-gate * the from stat to lstat after the top level is walked.
3627c478bd9Sstevel@tonic-gate */
3637c478bd9Sstevel@tonic-gate if (hflag) {
3647c478bd9Sstevel@tonic-gate if (stat(curpath, &sb) < 0 && errno == ENOENT)
3657c478bd9Sstevel@tonic-gate walkflags &= ~FTW_HOPTION;
3667c478bd9Sstevel@tonic-gate else
3677c478bd9Sstevel@tonic-gate walkflags |= FTW_HOPTION;
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate /*
3717c478bd9Sstevel@tonic-gate * We need this check as nftw needs a CWD and we have no
3727c478bd9Sstevel@tonic-gate * way of returning back from that code with a meaningful
3737c478bd9Sstevel@tonic-gate * error related to this
3747c478bd9Sstevel@tonic-gate */
3757c478bd9Sstevel@tonic-gate if ((cwdpath = getcwd(NULL, PATH_MAX)) == NULL) {
3764b808d43SRich Burridge if ((errno == EACCES) && (walkflags & FTW_CHDIR)) {
3774b808d43SRich Burridge /*
3784b808d43SRich Burridge * A directory above cwd is inaccessible,
3794b808d43SRich Burridge * so don't do chdir(2)s. Slower, but at least
3804b808d43SRich Burridge * it works.
3814b808d43SRich Burridge */
3824b808d43SRich Burridge walkflags &= ~FTW_CHDIR;
3834b808d43SRich Burridge free(cwdpath);
3844b808d43SRich Burridge } else {
3857c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
3864b808d43SRich Burridge gettext("%s : cannot get the current "
3874b808d43SRich Burridge "working directory\n"), cmdname);
3887c478bd9Sstevel@tonic-gate exit(1);
3894b808d43SRich Burridge }
3907c478bd9Sstevel@tonic-gate } else
3917c478bd9Sstevel@tonic-gate free(cwdpath);
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate if (nftw(curpath, execute, 1000, walkflags)) {
3957c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
3967c478bd9Sstevel@tonic-gate gettext("%s: cannot open %s: %s\n"),
3977c478bd9Sstevel@tonic-gate cmdname, curpath, strerror(errno));
3987c478bd9Sstevel@tonic-gate error = 1;
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate /* execute any remaining variable length lists */
4047c478bd9Sstevel@tonic-gate while (lastlist) {
4057c478bd9Sstevel@tonic-gate if (lastlist->end != lastlist->nextstr) {
4067c478bd9Sstevel@tonic-gate *lastlist->nextvar = 0;
40727d3a169SToomas Soome (void) doexec(NULL, lastlist->arglist,
408d35170d6Srm88369 &exec_exitcode);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate lastlist = lastlist->next;
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate if (output != stdout)
4137c478bd9Sstevel@tonic-gate return (cmdclose(output));
414d35170d6Srm88369 return ((exec_exitcode != 0) ? exec_exitcode : error);
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate /*
4187c478bd9Sstevel@tonic-gate * compile the arguments
4197c478bd9Sstevel@tonic-gate */
4207c478bd9Sstevel@tonic-gate
4217c478bd9Sstevel@tonic-gate static int
compile(char ** argv,struct Node * np,int * actionp)42227d3a169SToomas Soome compile(char **argv, struct Node *np, int *actionp)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate char *b;
4257c478bd9Sstevel@tonic-gate char **av;
4267c478bd9Sstevel@tonic-gate struct Node *oldnp = topnode;
4277c478bd9Sstevel@tonic-gate struct Args *argp;
4287c478bd9Sstevel@tonic-gate char **com;
4297c478bd9Sstevel@tonic-gate int i;
4307c478bd9Sstevel@tonic-gate enum Command wasop = PRINT;
4317c478bd9Sstevel@tonic-gate
4323d63ea05Sas145665 if (init_yes() < 0) {
4333d63ea05Sas145665 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
4343d63ea05Sas145665 strerror(errno));
4353d63ea05Sas145665 exit(1);
4363d63ea05Sas145665 }
4373d63ea05Sas145665
4387c478bd9Sstevel@tonic-gate for (av = argv; *av && (argp = lookup(*av)); av++) {
4397c478bd9Sstevel@tonic-gate np->next = 0;
4407c478bd9Sstevel@tonic-gate np->action = argp->action;
4417c478bd9Sstevel@tonic-gate np->type = argp->type;
4427c478bd9Sstevel@tonic-gate np->second.i = 0;
4437c478bd9Sstevel@tonic-gate if (argp->type == Op) {
4447c478bd9Sstevel@tonic-gate if (wasop == NOT || (wasop && np->action != NOT)) {
4457c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
4467c478bd9Sstevel@tonic-gate gettext("%s: operand follows operand\n"),
4477c478bd9Sstevel@tonic-gate cmdname);
4487c478bd9Sstevel@tonic-gate exit(1);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate if (np->action != NOT && oldnp == 0)
4517c478bd9Sstevel@tonic-gate goto err;
4527c478bd9Sstevel@tonic-gate wasop = argp->action;
4537c478bd9Sstevel@tonic-gate } else {
4547c478bd9Sstevel@tonic-gate wasop = PRINT;
4557c478bd9Sstevel@tonic-gate if (argp->type != Unary) {
4567c478bd9Sstevel@tonic-gate if (!(b = *++av)) {
45727d3a169SToomas Soome (void) fprintf(stderr, gettext(
45827d3a169SToomas Soome "%s: incomplete statement\n"),
4597c478bd9Sstevel@tonic-gate cmdname);
4607c478bd9Sstevel@tonic-gate exit(1);
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate if (argp->type == Num) {
463b34cd89aSYuri Pankov if (((argp->action == MAXDEPTH) ||
464b34cd89aSYuri Pankov (argp->action == MINDEPTH)) &&
465b34cd89aSYuri Pankov ((int)strtol(b, (char **)NULL,
466b34cd89aSYuri Pankov 10) < 0))
46727d3a169SToomas Soome errx(1, gettext(
46827d3a169SToomas Soome "%s: value must be "
46927d3a169SToomas Soome "positive"),
470b34cd89aSYuri Pankov (argp->action == MAXDEPTH) ?
471b34cd89aSYuri Pankov "maxdepth" : "mindepth");
4727c478bd9Sstevel@tonic-gate if ((argp->action != PERM) ||
4737c478bd9Sstevel@tonic-gate (*b != '+')) {
4747c478bd9Sstevel@tonic-gate if (*b == '+' || *b == '-') {
4757c478bd9Sstevel@tonic-gate np->second.i = *b;
4767c478bd9Sstevel@tonic-gate b++;
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate switch (argp->action) {
4837c478bd9Sstevel@tonic-gate case AND:
4847c478bd9Sstevel@tonic-gate break;
4857c478bd9Sstevel@tonic-gate case NOT:
4867c478bd9Sstevel@tonic-gate break;
4877c478bd9Sstevel@tonic-gate case OR:
4887c478bd9Sstevel@tonic-gate np->first.np = topnode;
4897c478bd9Sstevel@tonic-gate topnode = np;
4907c478bd9Sstevel@tonic-gate oldnp->next = 0;
4917c478bd9Sstevel@tonic-gate break;
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate case LPAREN: {
4947c478bd9Sstevel@tonic-gate struct Node *save = topnode;
4957c478bd9Sstevel@tonic-gate topnode = np+1;
4967c478bd9Sstevel@tonic-gate paren_cnt++;
4977c478bd9Sstevel@tonic-gate i = compile(++av, topnode, actionp);
4987c478bd9Sstevel@tonic-gate np->first.np = topnode;
4997c478bd9Sstevel@tonic-gate topnode = save;
5007c478bd9Sstevel@tonic-gate av += i;
5017c478bd9Sstevel@tonic-gate oldnp = np;
5027c478bd9Sstevel@tonic-gate np += i + 1;
5037c478bd9Sstevel@tonic-gate oldnp->next = np;
5047c478bd9Sstevel@tonic-gate continue;
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate
5077c478bd9Sstevel@tonic-gate case RPAREN:
5087c478bd9Sstevel@tonic-gate if (paren_cnt <= 0) {
5097c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
5107c478bd9Sstevel@tonic-gate gettext("%s: unmatched ')'\n"),
5117c478bd9Sstevel@tonic-gate cmdname);
5127c478bd9Sstevel@tonic-gate exit(1);
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate paren_cnt--;
5157c478bd9Sstevel@tonic-gate if (oldnp == 0)
5167c478bd9Sstevel@tonic-gate goto err;
5177c478bd9Sstevel@tonic-gate if (oldnp->type == Op) {
5187c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
5197c478bd9Sstevel@tonic-gate gettext("%s: cannot immediately"
5207c478bd9Sstevel@tonic-gate " follow an operand with ')'\n"),
5217c478bd9Sstevel@tonic-gate cmdname);
5227c478bd9Sstevel@tonic-gate exit(1);
5237c478bd9Sstevel@tonic-gate }
5247c478bd9Sstevel@tonic-gate oldnp->next = 0;
5257c478bd9Sstevel@tonic-gate return (av-argv);
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate case FOLLOW:
5287c478bd9Sstevel@tonic-gate walkflags &= ~FTW_PHYS;
5297c478bd9Sstevel@tonic-gate break;
5307c478bd9Sstevel@tonic-gate case MOUNT:
5317c478bd9Sstevel@tonic-gate walkflags |= FTW_MOUNT;
5327c478bd9Sstevel@tonic-gate break;
5337c478bd9Sstevel@tonic-gate case DEPTH:
5347c478bd9Sstevel@tonic-gate walkflags |= FTW_DEPTH;
5357c478bd9Sstevel@tonic-gate break;
536ab823b7fSPrasad Joshi case DELETE:
537ab823b7fSPrasad Joshi walkflags |= (FTW_DEPTH | FTW_PHYS);
538ab823b7fSPrasad Joshi walkflags &= ~FTW_CHDIR;
539ab823b7fSPrasad Joshi (*actionp)++;
540ab823b7fSPrasad Joshi break;
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate case LOCAL:
5437c478bd9Sstevel@tonic-gate np->first.l = 0L;
5447c478bd9Sstevel@tonic-gate np->first.ll = 0LL;
5457c478bd9Sstevel@tonic-gate np->second.i = '+';
5467c478bd9Sstevel@tonic-gate /*
5477c478bd9Sstevel@tonic-gate * Make it compatible to df -l for
5487c478bd9Sstevel@tonic-gate * future enhancement. So, anything
5497c478bd9Sstevel@tonic-gate * that is not remote, then it is
5507c478bd9Sstevel@tonic-gate * local.
5517c478bd9Sstevel@tonic-gate */
5527c478bd9Sstevel@tonic-gate init_remote_fs();
5537c478bd9Sstevel@tonic-gate break;
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate case SIZE:
5567c478bd9Sstevel@tonic-gate if (b[strlen(b)-1] == 'c')
5577c478bd9Sstevel@tonic-gate np->action = CSIZE;
5587c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
5597c478bd9Sstevel@tonic-gate case INUM:
5607c478bd9Sstevel@tonic-gate np->first.ll = atoll(b);
5617c478bd9Sstevel@tonic-gate break;
5627c478bd9Sstevel@tonic-gate
563da1a9cbeSjonb case CMIN:
5647c478bd9Sstevel@tonic-gate case CTIME:
565da1a9cbeSjonb case MMIN:
5667c478bd9Sstevel@tonic-gate case MTIME:
567da1a9cbeSjonb case AMIN:
5687c478bd9Sstevel@tonic-gate case ATIME:
5697c478bd9Sstevel@tonic-gate case LINKS:
5707c478bd9Sstevel@tonic-gate np->first.l = atol(b);
5717c478bd9Sstevel@tonic-gate break;
5727c478bd9Sstevel@tonic-gate
5737c478bd9Sstevel@tonic-gate case F_USER:
574b34cd89aSYuri Pankov case F_GROUP:
575b34cd89aSYuri Pankov case F_USERACL:
576b34cd89aSYuri Pankov case F_GROUPACL: {
5777c478bd9Sstevel@tonic-gate struct passwd *pw;
5787c478bd9Sstevel@tonic-gate struct group *gr;
579ef497ae3SRich Burridge long value;
580ef497ae3SRich Burridge char *q;
581ef497ae3SRich Burridge
582ef497ae3SRich Burridge value = -1;
583b34cd89aSYuri Pankov if (argp->action == F_USER ||
584b34cd89aSYuri Pankov argp->action == F_USERACL) {
5857c478bd9Sstevel@tonic-gate if ((pw = getpwnam(b)) != 0)
586ef497ae3SRich Burridge value = (long)pw->pw_uid;
5877c478bd9Sstevel@tonic-gate } else {
5887c478bd9Sstevel@tonic-gate if ((gr = getgrnam(b)) != 0)
589ef497ae3SRich Burridge value = (long)gr->gr_gid;
5907c478bd9Sstevel@tonic-gate }
591ef497ae3SRich Burridge if (value == -1) {
592ef497ae3SRich Burridge errno = 0;
593ef497ae3SRich Burridge value = strtol(b, &q, 10);
594ef497ae3SRich Burridge if (errno != 0 || q == b || *q != '\0') {
5957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
5967c478bd9Sstevel@tonic-gate "%s: cannot find %s name\n"),
5977c478bd9Sstevel@tonic-gate cmdname, *av);
5987c478bd9Sstevel@tonic-gate exit(1);
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate }
601ef497ae3SRich Burridge np->first.l = value;
6027c478bd9Sstevel@tonic-gate break;
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate case EXEC:
6067c478bd9Sstevel@tonic-gate case OK:
6077c478bd9Sstevel@tonic-gate walkflags &= ~FTW_CHDIR;
6087c478bd9Sstevel@tonic-gate np->first.ap = av;
6097c478bd9Sstevel@tonic-gate (*actionp)++;
6107c478bd9Sstevel@tonic-gate for (;;) {
6117c478bd9Sstevel@tonic-gate if ((b = *av) == 0) {
61227d3a169SToomas Soome (void) fprintf(stderr, gettext(
61327d3a169SToomas Soome "%s: incomplete statement\n"),
6147c478bd9Sstevel@tonic-gate cmdname);
6157c478bd9Sstevel@tonic-gate exit(1);
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate if (strcmp(b, ";") == 0) {
6187c478bd9Sstevel@tonic-gate *av = 0;
6197c478bd9Sstevel@tonic-gate break;
6207c478bd9Sstevel@tonic-gate } else if (strcmp(b, "{}") == 0)
6217c478bd9Sstevel@tonic-gate *av = dummyarg;
6227c478bd9Sstevel@tonic-gate else if (strcmp(b, "+") == 0 &&
62327d3a169SToomas Soome av[-1] == dummyarg && np->action == EXEC) {
6247c478bd9Sstevel@tonic-gate av[-1] = 0;
6257c478bd9Sstevel@tonic-gate np->first.vp = varargs(np->first.ap);
6267c478bd9Sstevel@tonic-gate np->action = VARARGS;
6277c478bd9Sstevel@tonic-gate break;
6287c478bd9Sstevel@tonic-gate }
6297c478bd9Sstevel@tonic-gate av++;
6307c478bd9Sstevel@tonic-gate }
6317c478bd9Sstevel@tonic-gate break;
6327c478bd9Sstevel@tonic-gate
6337c478bd9Sstevel@tonic-gate case NAME:
634b34cd89aSYuri Pankov case INAME:
63505f32410SAndy Stormont case PATH:
63605f32410SAndy Stormont case IPATH:
6377c478bd9Sstevel@tonic-gate np->first.cp = b;
6387c478bd9Sstevel@tonic-gate break;
639b34cd89aSYuri Pankov case REGEX:
640b34cd89aSYuri Pankov case IREGEX: {
641b34cd89aSYuri Pankov int error;
642b34cd89aSYuri Pankov size_t errlen;
643b34cd89aSYuri Pankov char *errmsg;
644b34cd89aSYuri Pankov
645b34cd89aSYuri Pankov if ((preg = realloc(preg, (npreg + 1) *
646b34cd89aSYuri Pankov sizeof (regex_t))) == NULL)
647b34cd89aSYuri Pankov err(1, "realloc");
648b34cd89aSYuri Pankov if ((error = regcomp(&preg[npreg], b,
649b34cd89aSYuri Pankov ((np->action == IREGEX) ? REG_ICASE : 0) |
650b34cd89aSYuri Pankov ((Eflag) ? REG_EXTENDED : 0))) != 0) {
651b34cd89aSYuri Pankov errlen = regerror(error, &preg[npreg], NULL, 0);
652b34cd89aSYuri Pankov if ((errmsg = malloc(errlen)) == NULL)
653b34cd89aSYuri Pankov err(1, "malloc");
654b34cd89aSYuri Pankov (void) regerror(error, &preg[npreg], errmsg,
655b34cd89aSYuri Pankov errlen);
656b34cd89aSYuri Pankov errx(1, gettext("RE error: %s"), errmsg);
657b34cd89aSYuri Pankov }
658b34cd89aSYuri Pankov npreg++;
659b34cd89aSYuri Pankov break;
660b34cd89aSYuri Pankov }
6617c478bd9Sstevel@tonic-gate case PERM:
6627c478bd9Sstevel@tonic-gate if (*b == '-')
6637c478bd9Sstevel@tonic-gate ++b;
6647c478bd9Sstevel@tonic-gate
66527d3a169SToomas Soome if (readmode(b) != 0) {
6667c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
6677c478bd9Sstevel@tonic-gate "find: -perm: Bad permission string\n"));
6687c478bd9Sstevel@tonic-gate usage();
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate np->first.l = (long)getmode((mode_t)0);
6717c478bd9Sstevel@tonic-gate break;
6727c478bd9Sstevel@tonic-gate case TYPE:
6737c478bd9Sstevel@tonic-gate i = *b;
6747c478bd9Sstevel@tonic-gate np->first.l =
6757c478bd9Sstevel@tonic-gate i == 'd' ? S_IFDIR :
6767c478bd9Sstevel@tonic-gate i == 'b' ? S_IFBLK :
6777c478bd9Sstevel@tonic-gate i == 'c' ? S_IFCHR :
6787c478bd9Sstevel@tonic-gate #ifdef S_IFIFO
6797c478bd9Sstevel@tonic-gate i == 'p' ? S_IFIFO :
6807c478bd9Sstevel@tonic-gate #endif
6817c478bd9Sstevel@tonic-gate i == 'f' ? S_IFREG :
6827c478bd9Sstevel@tonic-gate #ifdef S_IFLNK
6837c478bd9Sstevel@tonic-gate i == 'l' ? S_IFLNK :
6847c478bd9Sstevel@tonic-gate #endif
6857c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK
6867c478bd9Sstevel@tonic-gate i == 's' ? S_IFSOCK :
6877c478bd9Sstevel@tonic-gate #endif
6887c478bd9Sstevel@tonic-gate #ifdef S_IFDOOR
6897c478bd9Sstevel@tonic-gate i == 'D' ? S_IFDOOR :
6907c478bd9Sstevel@tonic-gate #endif
6917c478bd9Sstevel@tonic-gate 0;
6927c478bd9Sstevel@tonic-gate break;
6937c478bd9Sstevel@tonic-gate
6947c478bd9Sstevel@tonic-gate case CPIO:
6957c478bd9Sstevel@tonic-gate if (walkflags & FTW_PHYS)
6967c478bd9Sstevel@tonic-gate com = cpio;
6977c478bd9Sstevel@tonic-gate else
6987c478bd9Sstevel@tonic-gate com = cpiol;
6997c478bd9Sstevel@tonic-gate goto common;
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate case NCPIO: {
7027c478bd9Sstevel@tonic-gate FILE *fd;
7037c478bd9Sstevel@tonic-gate
7047c478bd9Sstevel@tonic-gate if (walkflags & FTW_PHYS)
7057c478bd9Sstevel@tonic-gate com = ncpio;
7067c478bd9Sstevel@tonic-gate else
7077c478bd9Sstevel@tonic-gate com = ncpiol;
7087c478bd9Sstevel@tonic-gate common:
7097c478bd9Sstevel@tonic-gate /* set up cpio */
7107c478bd9Sstevel@tonic-gate if ((fd = fopen(b, "w")) == NULL) {
7117c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7127c478bd9Sstevel@tonic-gate gettext("%s: cannot create %s\n"),
7137c478bd9Sstevel@tonic-gate cmdname, b);
7147c478bd9Sstevel@tonic-gate exit(1);
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate
7177c478bd9Sstevel@tonic-gate np->first.l = (long)cmdopen("cpio", com, "w", fd);
7187c478bd9Sstevel@tonic-gate (void) fclose(fd);
7197c478bd9Sstevel@tonic-gate walkflags |= FTW_DEPTH;
7207c478bd9Sstevel@tonic-gate np->action = CPIO;
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/
7237c478bd9Sstevel@tonic-gate case PRINT:
724b34cd89aSYuri Pankov case PRINT0:
7257c478bd9Sstevel@tonic-gate (*actionp)++;
7267c478bd9Sstevel@tonic-gate break;
7277c478bd9Sstevel@tonic-gate
7287c478bd9Sstevel@tonic-gate case NEWER: {
7297c478bd9Sstevel@tonic-gate struct stat statb;
7307c478bd9Sstevel@tonic-gate if (stat(b, &statb) < 0) {
7317c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7327c478bd9Sstevel@tonic-gate gettext("%s: cannot access %s\n"),
7337c478bd9Sstevel@tonic-gate cmdname, b);
7347c478bd9Sstevel@tonic-gate exit(1);
7357c478bd9Sstevel@tonic-gate }
7367c478bd9Sstevel@tonic-gate np->first.l = statb.st_mtime;
7377c478bd9Sstevel@tonic-gate np->second.i = '+';
7387c478bd9Sstevel@tonic-gate break;
7397c478bd9Sstevel@tonic-gate }
7407c478bd9Sstevel@tonic-gate
7417c478bd9Sstevel@tonic-gate case PRUNE:
7427c478bd9Sstevel@tonic-gate case NOUSER:
7437c478bd9Sstevel@tonic-gate case NOGRP:
7447c478bd9Sstevel@tonic-gate break;
7457c478bd9Sstevel@tonic-gate case FSTYPE:
7467c478bd9Sstevel@tonic-gate np->first.cp = b;
7477c478bd9Sstevel@tonic-gate break;
7487c478bd9Sstevel@tonic-gate case LS:
7497c478bd9Sstevel@tonic-gate (*actionp)++;
7507c478bd9Sstevel@tonic-gate break;
7517c478bd9Sstevel@tonic-gate case XATTR:
7527c478bd9Sstevel@tonic-gate break;
7537c478bd9Sstevel@tonic-gate case ACL:
7547c478bd9Sstevel@tonic-gate break;
755b34cd89aSYuri Pankov case MAXDEPTH:
75627d3a169SToomas Soome maxdepth = (int)strtol(b, NULL, 10);
757b34cd89aSYuri Pankov break;
758b34cd89aSYuri Pankov case MINDEPTH:
75927d3a169SToomas Soome mindepth = (int)strtol(b, NULL, 10);
760b34cd89aSYuri Pankov break;
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate
7637c478bd9Sstevel@tonic-gate oldnp = np++;
7647c478bd9Sstevel@tonic-gate oldnp->next = np;
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate
7677c478bd9Sstevel@tonic-gate if ((*av) || (wasop))
7687c478bd9Sstevel@tonic-gate goto err;
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate if (paren_cnt != 0) {
77127d3a169SToomas Soome (void) fprintf(stderr, gettext("%s: unmatched '('\n"), cmdname);
7727c478bd9Sstevel@tonic-gate exit(1);
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate /* just before returning, save next free node from the list */
7767c478bd9Sstevel@tonic-gate freenode = oldnp->next;
7777c478bd9Sstevel@tonic-gate oldnp->next = 0;
7787c478bd9Sstevel@tonic-gate return (av-argv);
7797c478bd9Sstevel@tonic-gate err:
7807c478bd9Sstevel@tonic-gate if (*av)
7817c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7827c478bd9Sstevel@tonic-gate gettext("%s: bad option %s\n"), cmdname, *av);
7837c478bd9Sstevel@tonic-gate else
7847c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: bad option\n"), cmdname);
7857c478bd9Sstevel@tonic-gate usage();
7867c478bd9Sstevel@tonic-gate /*NOTREACHED*/
7877c478bd9Sstevel@tonic-gate }
7887c478bd9Sstevel@tonic-gate
7897c478bd9Sstevel@tonic-gate /*
7907c478bd9Sstevel@tonic-gate * print out a usage message
7917c478bd9Sstevel@tonic-gate */
7927c478bd9Sstevel@tonic-gate
7937c478bd9Sstevel@tonic-gate static void
usage(void)7946c83d09fSrobbin usage(void)
7957c478bd9Sstevel@tonic-gate {
7967c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
797b34cd89aSYuri Pankov gettext("%s: [-E] [-H | -L] path-list predicate-list\n"), cmdname);
7987c478bd9Sstevel@tonic-gate exit(1);
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate
8017c478bd9Sstevel@tonic-gate /*
802*ba5b88a2SBill Sommerfeld * ACL matching is complex enough to warrant its own function.
803*ba5b88a2SBill Sommerfeld */
804*ba5b88a2SBill Sommerfeld static int
aclmatch(struct Node * np,const char * filename)805*ba5b88a2SBill Sommerfeld aclmatch(struct Node *np, const char *filename)
806*ba5b88a2SBill Sommerfeld {
807*ba5b88a2SBill Sommerfeld int i, t1, t2;
808*ba5b88a2SBill Sommerfeld acl_t *acl;
809*ba5b88a2SBill Sommerfeld void *acl_entry;
810*ba5b88a2SBill Sommerfeld aclent_t *p1;
811*ba5b88a2SBill Sommerfeld ace_t *p2;
812*ba5b88a2SBill Sommerfeld
813*ba5b88a2SBill Sommerfeld if (np->action == F_USERACL) {
814*ba5b88a2SBill Sommerfeld t1 = USER;
815*ba5b88a2SBill Sommerfeld t2 = 0;
816*ba5b88a2SBill Sommerfeld } else {
817*ba5b88a2SBill Sommerfeld t1 = GROUP;
818*ba5b88a2SBill Sommerfeld t2 = ACE_IDENTIFIER_GROUP;
819*ba5b88a2SBill Sommerfeld }
820*ba5b88a2SBill Sommerfeld
821*ba5b88a2SBill Sommerfeld if (acl_get(filename, 0, &acl) != 0)
822*ba5b88a2SBill Sommerfeld return (0);
823*ba5b88a2SBill Sommerfeld
824*ba5b88a2SBill Sommerfeld for (i = 0, acl_entry = acl->acl_aclp;
825*ba5b88a2SBill Sommerfeld i != acl->acl_cnt; i++) {
826*ba5b88a2SBill Sommerfeld if (acl->acl_type == ACLENT_T) {
827*ba5b88a2SBill Sommerfeld p1 = (aclent_t *)acl_entry;
828*ba5b88a2SBill Sommerfeld if (p1->a_id == np->first.l && p1->a_type == t1) {
829*ba5b88a2SBill Sommerfeld acl_free(acl);
830*ba5b88a2SBill Sommerfeld return (1);
831*ba5b88a2SBill Sommerfeld }
832*ba5b88a2SBill Sommerfeld } else {
833*ba5b88a2SBill Sommerfeld p2 = (ace_t *)acl_entry;
834*ba5b88a2SBill Sommerfeld if (p2->a_who == np->first.l &&
835*ba5b88a2SBill Sommerfeld ((p2->a_flags & ACE_TYPE_FLAGS) == t2)) {
836*ba5b88a2SBill Sommerfeld acl_free(acl);
837*ba5b88a2SBill Sommerfeld return (1);
838*ba5b88a2SBill Sommerfeld }
839*ba5b88a2SBill Sommerfeld }
840*ba5b88a2SBill Sommerfeld acl_entry = ((char *)acl_entry + acl->acl_entry_size);
841*ba5b88a2SBill Sommerfeld }
842*ba5b88a2SBill Sommerfeld acl_free(acl);
843*ba5b88a2SBill Sommerfeld return (0);
844*ba5b88a2SBill Sommerfeld }
845*ba5b88a2SBill Sommerfeld
846*ba5b88a2SBill Sommerfeld /*
8477c478bd9Sstevel@tonic-gate * This is the function that gets executed at each node
8487c478bd9Sstevel@tonic-gate */
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate static int
execute(const char * name,const struct stat * statb,int type,struct FTW * state)85127d3a169SToomas Soome execute(const char *name, const struct stat *statb, int type, struct FTW *state)
8527c478bd9Sstevel@tonic-gate {
8537c478bd9Sstevel@tonic-gate struct Node *np = topnode;
8547c478bd9Sstevel@tonic-gate int val;
8557c478bd9Sstevel@tonic-gate time_t t;
8567c478bd9Sstevel@tonic-gate long l;
8577c478bd9Sstevel@tonic-gate long long ll;
8587c478bd9Sstevel@tonic-gate int not = 1;
85927d3a169SToomas Soome const char *filename;
860b34cd89aSYuri Pankov int cnpreg = 0;
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate if (type == FTW_NS) {
8637c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: stat() error %s: %s\n"),
8647c478bd9Sstevel@tonic-gate cmdname, name, strerror(errno));
8657c478bd9Sstevel@tonic-gate error = 1;
8667c478bd9Sstevel@tonic-gate return (0);
8677c478bd9Sstevel@tonic-gate } else if (type == FTW_DNR) {
8687c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: cannot read dir %s: %s\n"),
8697c478bd9Sstevel@tonic-gate cmdname, name, strerror(errno));
8707c478bd9Sstevel@tonic-gate error = 1;
8710729abfeSRich Burridge } else if (type == FTW_SLN && lflag == 1) {
8727c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
8737c478bd9Sstevel@tonic-gate gettext("%s: cannot follow symbolic link %s: %s\n"),
8747c478bd9Sstevel@tonic-gate cmdname, name, strerror(errno));
8757c478bd9Sstevel@tonic-gate error = 1;
87668a94df1Scf46844 } else if (type == FTW_DL) {
87768a94df1Scf46844 (void) fprintf(stderr, gettext("%s: cycle detected for %s\n"),
87868a94df1Scf46844 cmdname, name);
87968a94df1Scf46844 error = 1;
88068a94df1Scf46844 return (0);
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate
883b34cd89aSYuri Pankov if ((maxdepth != -1 && state->level > maxdepth) ||
884b34cd89aSYuri Pankov (mindepth != -1 && state->level < mindepth))
885b34cd89aSYuri Pankov return (0);
886b34cd89aSYuri Pankov
8877c478bd9Sstevel@tonic-gate while (np) {
8887c478bd9Sstevel@tonic-gate switch (np->action) {
8897c478bd9Sstevel@tonic-gate case NOT:
8907c478bd9Sstevel@tonic-gate not = !not;
8917c478bd9Sstevel@tonic-gate np = np->next;
8927c478bd9Sstevel@tonic-gate continue;
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate case AND:
8957c478bd9Sstevel@tonic-gate np = np->next;
8967c478bd9Sstevel@tonic-gate continue;
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate case OR:
8997c478bd9Sstevel@tonic-gate if (np->first.np == np) {
9007c478bd9Sstevel@tonic-gate /*
9017c478bd9Sstevel@tonic-gate * handle naked OR (no term on left hand side)
9027c478bd9Sstevel@tonic-gate */
9037c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
9047c478bd9Sstevel@tonic-gate gettext("%s: invalid -o construction\n"),
9057c478bd9Sstevel@tonic-gate cmdname);
9067c478bd9Sstevel@tonic-gate exit(2);
9077c478bd9Sstevel@tonic-gate }
9087c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
9097c478bd9Sstevel@tonic-gate case LPAREN: {
9107c478bd9Sstevel@tonic-gate struct Node *save = topnode;
9117c478bd9Sstevel@tonic-gate topnode = np->first.np;
9127c478bd9Sstevel@tonic-gate (void) execute(name, statb, type, state);
9137c478bd9Sstevel@tonic-gate val = lastval;
9147c478bd9Sstevel@tonic-gate topnode = save;
9157c478bd9Sstevel@tonic-gate if (np->action == OR) {
9167c478bd9Sstevel@tonic-gate if (val)
9177c478bd9Sstevel@tonic-gate return (0);
9187c478bd9Sstevel@tonic-gate val = 1;
9197c478bd9Sstevel@tonic-gate }
9207c478bd9Sstevel@tonic-gate break;
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate
9237c478bd9Sstevel@tonic-gate case LOCAL: {
9247c478bd9Sstevel@tonic-gate int nremfs;
9257c478bd9Sstevel@tonic-gate val = 1;
9267c478bd9Sstevel@tonic-gate /*
9277c478bd9Sstevel@tonic-gate * If file system type matches the remote
9287c478bd9Sstevel@tonic-gate * file system type, then it is not local.
9297c478bd9Sstevel@tonic-gate */
9307c478bd9Sstevel@tonic-gate for (nremfs = 0; nremfs < fstype_index; nremfs++) {
9317c478bd9Sstevel@tonic-gate if (strcmp(remote_fstypes[nremfs],
9327c478bd9Sstevel@tonic-gate statb->st_fstype) == 0) {
9337c478bd9Sstevel@tonic-gate val = 0;
9347c478bd9Sstevel@tonic-gate break;
9357c478bd9Sstevel@tonic-gate }
9367c478bd9Sstevel@tonic-gate }
9377c478bd9Sstevel@tonic-gate break;
9387c478bd9Sstevel@tonic-gate }
9397c478bd9Sstevel@tonic-gate
9407c478bd9Sstevel@tonic-gate case TYPE:
9417c478bd9Sstevel@tonic-gate l = (long)statb->st_mode&S_IFMT;
9427c478bd9Sstevel@tonic-gate goto num;
9437c478bd9Sstevel@tonic-gate
9447c478bd9Sstevel@tonic-gate case PERM:
9457c478bd9Sstevel@tonic-gate l = (long)statb->st_mode&07777;
9467c478bd9Sstevel@tonic-gate if (np->second.i == '-')
9477c478bd9Sstevel@tonic-gate val = ((l&np->first.l) == np->first.l);
9487c478bd9Sstevel@tonic-gate else
9497c478bd9Sstevel@tonic-gate val = (l == np->first.l);
9507c478bd9Sstevel@tonic-gate break;
9517c478bd9Sstevel@tonic-gate
9527c478bd9Sstevel@tonic-gate case INUM:
9537c478bd9Sstevel@tonic-gate ll = (long long)statb->st_ino;
9547c478bd9Sstevel@tonic-gate goto llnum;
9557c478bd9Sstevel@tonic-gate case NEWER:
9567c478bd9Sstevel@tonic-gate l = statb->st_mtime;
9577c478bd9Sstevel@tonic-gate goto num;
9587c478bd9Sstevel@tonic-gate case ATIME:
9597c478bd9Sstevel@tonic-gate t = statb->st_atime;
9607c478bd9Sstevel@tonic-gate goto days;
9617c478bd9Sstevel@tonic-gate case CTIME:
9627c478bd9Sstevel@tonic-gate t = statb->st_ctime;
9637c478bd9Sstevel@tonic-gate goto days;
9647c478bd9Sstevel@tonic-gate case MTIME:
9657c478bd9Sstevel@tonic-gate t = statb->st_mtime;
9667c478bd9Sstevel@tonic-gate days:
9677c478bd9Sstevel@tonic-gate l = (now-t)/A_DAY;
9687c478bd9Sstevel@tonic-gate goto num;
969da1a9cbeSjonb case MMIN:
970da1a9cbeSjonb t = statb->st_mtime;
971da1a9cbeSjonb goto mins;
972da1a9cbeSjonb case AMIN:
973da1a9cbeSjonb t = statb->st_atime;
974da1a9cbeSjonb goto mins;
975da1a9cbeSjonb case CMIN:
976da1a9cbeSjonb t = statb->st_ctime;
977da1a9cbeSjonb goto mins;
978da1a9cbeSjonb mins:
979da1a9cbeSjonb l = (now-t)/A_MIN;
980da1a9cbeSjonb goto num;
9817c478bd9Sstevel@tonic-gate case CSIZE:
9827c478bd9Sstevel@tonic-gate ll = (long long)statb->st_size;
9837c478bd9Sstevel@tonic-gate goto llnum;
9847c478bd9Sstevel@tonic-gate case SIZE:
9857c478bd9Sstevel@tonic-gate ll = (long long)round(statb->st_size, BLKSIZ)/BLKSIZ;
9867c478bd9Sstevel@tonic-gate goto llnum;
9877c478bd9Sstevel@tonic-gate case F_USER:
9887c478bd9Sstevel@tonic-gate l = (long)statb->st_uid;
9897c478bd9Sstevel@tonic-gate goto num;
9907c478bd9Sstevel@tonic-gate case F_GROUP:
9917c478bd9Sstevel@tonic-gate l = (long)statb->st_gid;
9927c478bd9Sstevel@tonic-gate goto num;
9937c478bd9Sstevel@tonic-gate case LINKS:
9947c478bd9Sstevel@tonic-gate l = (long)statb->st_nlink;
9957c478bd9Sstevel@tonic-gate goto num;
9967c478bd9Sstevel@tonic-gate llnum:
9977c478bd9Sstevel@tonic-gate if (np->second.i == '+')
9987c478bd9Sstevel@tonic-gate val = (ll > np->first.ll);
9997c478bd9Sstevel@tonic-gate else if (np->second.i == '-')
10007c478bd9Sstevel@tonic-gate val = (ll < np->first.ll);
10017c478bd9Sstevel@tonic-gate else
10027c478bd9Sstevel@tonic-gate val = (ll == np->first.ll);
10037c478bd9Sstevel@tonic-gate break;
10047c478bd9Sstevel@tonic-gate num:
10057c478bd9Sstevel@tonic-gate if (np->second.i == '+')
10067c478bd9Sstevel@tonic-gate val = (l > np->first.l);
10077c478bd9Sstevel@tonic-gate else if (np->second.i == '-')
10087c478bd9Sstevel@tonic-gate val = (l < np->first.l);
10097c478bd9Sstevel@tonic-gate else
10107c478bd9Sstevel@tonic-gate val = (l == np->first.l);
10117c478bd9Sstevel@tonic-gate break;
10127c478bd9Sstevel@tonic-gate case OK:
10137c478bd9Sstevel@tonic-gate val = ok(name, np->first.ap);
10147c478bd9Sstevel@tonic-gate break;
10157c478bd9Sstevel@tonic-gate case EXEC:
1016d35170d6Srm88369 val = doexec(name, np->first.ap, NULL);
10177c478bd9Sstevel@tonic-gate break;
1018ab823b7fSPrasad Joshi case DELETE:
1019ab823b7fSPrasad Joshi val = dodelete(name, statb, state);
1020ab823b7fSPrasad Joshi break;
10217c478bd9Sstevel@tonic-gate
10227c478bd9Sstevel@tonic-gate case VARARGS: {
10237c478bd9Sstevel@tonic-gate struct Arglist *ap = np->first.vp;
10247c478bd9Sstevel@tonic-gate char *cp;
10257c478bd9Sstevel@tonic-gate cp = ap->nextstr - (strlen(name)+1);
10267c478bd9Sstevel@tonic-gate if (cp >= (char *)(ap->nextvar+3)) {
10277c478bd9Sstevel@tonic-gate /* there is room just copy the name */
10287c478bd9Sstevel@tonic-gate val = 1;
10297c478bd9Sstevel@tonic-gate (void) strcpy(cp, name);
10307c478bd9Sstevel@tonic-gate *ap->nextvar++ = cp;
10317c478bd9Sstevel@tonic-gate ap->nextstr = cp;
10327c478bd9Sstevel@tonic-gate } else {
10337c478bd9Sstevel@tonic-gate /* no more room, exec command */
103427d3a169SToomas Soome *ap->nextvar++ = (char *)name;
10357c478bd9Sstevel@tonic-gate *ap->nextvar = 0;
10367c478bd9Sstevel@tonic-gate val = 1;
103727d3a169SToomas Soome (void) doexec(NULL, ap->arglist,
1038d35170d6Srm88369 &exec_exitcode);
10397c478bd9Sstevel@tonic-gate ap->nextstr = ap->end;
10407c478bd9Sstevel@tonic-gate ap->nextvar = ap->firstvar;
10417c478bd9Sstevel@tonic-gate }
10427c478bd9Sstevel@tonic-gate break;
10437c478bd9Sstevel@tonic-gate }
10447c478bd9Sstevel@tonic-gate
10457c478bd9Sstevel@tonic-gate case DEPTH:
10467c478bd9Sstevel@tonic-gate case MOUNT:
10477c478bd9Sstevel@tonic-gate case FOLLOW:
10487c478bd9Sstevel@tonic-gate val = 1;
10497c478bd9Sstevel@tonic-gate break;
10507c478bd9Sstevel@tonic-gate
1051b34cd89aSYuri Pankov case NAME:
105205f32410SAndy Stormont case INAME:
105305f32410SAndy Stormont case PATH:
105405f32410SAndy Stormont case IPATH: {
105505f32410SAndy Stormont char *path;
105605f32410SAndy Stormont int fnmflags = 0;
105705f32410SAndy Stormont
105805f32410SAndy Stormont if (np->action == INAME || np->action == IPATH)
105905f32410SAndy Stormont fnmflags = FNM_IGNORECASE;
10609ab6dc39Schin
10619ab6dc39Schin /*
10629ab6dc39Schin * basename(3c) may modify name, so
10639ab6dc39Schin * we need to pass another string
10649ab6dc39Schin */
106505f32410SAndy Stormont if ((path = strdup(name)) == NULL) {
10669ab6dc39Schin (void) fprintf(stderr,
10679ab6dc39Schin gettext("%s: cannot strdup() %s: %s\n"),
10686b238a5aSchin cmdname, name, strerror(errno));
10699ab6dc39Schin exit(2);
10709ab6dc39Schin }
10717c478bd9Sstevel@tonic-gate /*
10727c478bd9Sstevel@tonic-gate * XPG4 find should not treat a leading '.' in a
10737c478bd9Sstevel@tonic-gate * filename specially for pattern matching.
10747c478bd9Sstevel@tonic-gate * /usr/bin/find will not pattern match a leading
10757c478bd9Sstevel@tonic-gate * '.' in a filename, unless '.' is explicitly
10767c478bd9Sstevel@tonic-gate * specified.
1077f3a525d9SJohn Levon *
1078f3a525d9SJohn Levon * The legacy behavior makes no sense for PATH.
10797c478bd9Sstevel@tonic-gate */
1080b34cd89aSYuri Pankov #ifndef XPG4
1081f3a525d9SJohn Levon if (np->action == NAME || np->action == INAME)
1082b34cd89aSYuri Pankov fnmflags |= FNM_PERIOD;
10837c478bd9Sstevel@tonic-gate #endif
108405f32410SAndy Stormont
108505f32410SAndy Stormont val = !fnmatch(np->first.cp,
108627d3a169SToomas Soome (np->action == NAME || np->action == INAME) ?
108727d3a169SToomas Soome basename(path) : path, fnmflags);
108805f32410SAndy Stormont free(path);
10897c478bd9Sstevel@tonic-gate break;
10907c478bd9Sstevel@tonic-gate }
10917c478bd9Sstevel@tonic-gate
10927c478bd9Sstevel@tonic-gate case PRUNE:
10937c478bd9Sstevel@tonic-gate if (type == FTW_D)
10947c478bd9Sstevel@tonic-gate state->quit = FTW_PRUNE;
10957c478bd9Sstevel@tonic-gate val = 1;
10967c478bd9Sstevel@tonic-gate break;
10977c478bd9Sstevel@tonic-gate case NOUSER:
10987c478bd9Sstevel@tonic-gate val = ((getpwuid(statb->st_uid)) == 0);
10997c478bd9Sstevel@tonic-gate break;
11007c478bd9Sstevel@tonic-gate case NOGRP:
11017c478bd9Sstevel@tonic-gate val = ((getgrgid(statb->st_gid)) == 0);
11027c478bd9Sstevel@tonic-gate break;
11037c478bd9Sstevel@tonic-gate case FSTYPE:
11047c478bd9Sstevel@tonic-gate val = (strcmp(np->first.cp, statb->st_fstype) == 0);
11057c478bd9Sstevel@tonic-gate break;
11067c478bd9Sstevel@tonic-gate case CPIO:
11077c478bd9Sstevel@tonic-gate output = (FILE *)np->first.l;
11087c478bd9Sstevel@tonic-gate (void) fprintf(output, "%s\n", name);
11097c478bd9Sstevel@tonic-gate val = 1;
11107c478bd9Sstevel@tonic-gate break;
11117c478bd9Sstevel@tonic-gate case PRINT:
1112b34cd89aSYuri Pankov case PRINT0:
1113b34cd89aSYuri Pankov (void) fprintf(stdout, "%s%c", name,
1114b34cd89aSYuri Pankov (np->action == PRINT) ? '\n' : '\0');
11157c478bd9Sstevel@tonic-gate val = 1;
11167c478bd9Sstevel@tonic-gate break;
11177c478bd9Sstevel@tonic-gate case LS:
11187c478bd9Sstevel@tonic-gate (void) list(name, statb);
11197c478bd9Sstevel@tonic-gate val = 1;
11207c478bd9Sstevel@tonic-gate break;
11217c478bd9Sstevel@tonic-gate case XATTR:
1122f467e6fbSJohn Sonnenschein filename = (walkflags & FTW_CHDIR) ?
1123f467e6fbSJohn Sonnenschein gettail(name) : name;
11247c478bd9Sstevel@tonic-gate val = (pathconf(filename, _PC_XATTR_EXISTS) == 1);
11257c478bd9Sstevel@tonic-gate break;
11267c478bd9Sstevel@tonic-gate case ACL:
11277c478bd9Sstevel@tonic-gate /*
11287c478bd9Sstevel@tonic-gate * Need to get the tail of the file name, since we have
11297c478bd9Sstevel@tonic-gate * already chdir()ed into the directory (performed in
11307c478bd9Sstevel@tonic-gate * nftw()) of the file
11317c478bd9Sstevel@tonic-gate */
1132f467e6fbSJohn Sonnenschein filename = (walkflags & FTW_CHDIR) ?
1133f467e6fbSJohn Sonnenschein gettail(name) : name;
1134f467e6fbSJohn Sonnenschein val = acl_trivial(filename);
11357c478bd9Sstevel@tonic-gate break;
1136b34cd89aSYuri Pankov case F_USERACL:
1137b34cd89aSYuri Pankov case F_GROUPACL: {
1138b34cd89aSYuri Pankov filename = (walkflags & FTW_CHDIR) ?
1139b34cd89aSYuri Pankov gettail(name) : name;
1140*ba5b88a2SBill Sommerfeld val = aclmatch(np, filename);
1141b34cd89aSYuri Pankov break;
1142b34cd89aSYuri Pankov }
1143b34cd89aSYuri Pankov case IREGEX:
1144b34cd89aSYuri Pankov case REGEX: {
1145b34cd89aSYuri Pankov regmatch_t pmatch;
1146b34cd89aSYuri Pankov
1147b34cd89aSYuri Pankov val = 0;
114827d3a169SToomas Soome if (regexec(&preg[cnpreg], name, 1, &pmatch, 0) == 0)
1149b34cd89aSYuri Pankov val = ((pmatch.rm_so == 0) &&
1150b34cd89aSYuri Pankov (pmatch.rm_eo == strlen(name)));
1151b34cd89aSYuri Pankov cnpreg++;
1152b34cd89aSYuri Pankov break;
1153b34cd89aSYuri Pankov }
1154b34cd89aSYuri Pankov case MAXDEPTH:
1155b34cd89aSYuri Pankov if (state->level == maxdepth && type == FTW_D)
1156b34cd89aSYuri Pankov state->quit = FTW_PRUNE;
1157b34cd89aSYuri Pankov /* FALLTHROUGH */
1158b34cd89aSYuri Pankov case MINDEPTH:
1159b34cd89aSYuri Pankov val = 1;
1160b34cd89aSYuri Pankov break;
11617c478bd9Sstevel@tonic-gate }
11627c478bd9Sstevel@tonic-gate /*
11637c478bd9Sstevel@tonic-gate * evaluate 'val' and 'not' (exclusive-or)
11647c478bd9Sstevel@tonic-gate * if no inversion (not == 1), return only when val == 0
11657c478bd9Sstevel@tonic-gate * (primary not true). Otherwise, invert the primary
11667c478bd9Sstevel@tonic-gate * and return when the primary is true.
11677c478bd9Sstevel@tonic-gate * 'Lastval' saves the last result (fail or pass) when
11687c478bd9Sstevel@tonic-gate * returning back to the calling routine.
11697c478bd9Sstevel@tonic-gate */
11707c478bd9Sstevel@tonic-gate if (val ^ not) {
11717c478bd9Sstevel@tonic-gate lastval = 0;
11727c478bd9Sstevel@tonic-gate return (0);
11737c478bd9Sstevel@tonic-gate }
11747c478bd9Sstevel@tonic-gate lastval = 1;
11757c478bd9Sstevel@tonic-gate not = 1;
11767c478bd9Sstevel@tonic-gate np = np->next;
11777c478bd9Sstevel@tonic-gate }
11787c478bd9Sstevel@tonic-gate return (0);
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gate /*
11827c478bd9Sstevel@tonic-gate * code for the -ok option
11837c478bd9Sstevel@tonic-gate */
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gate static int
ok(const char * name,char * argv[])118627d3a169SToomas Soome ok(const char *name, char *argv[])
11877c478bd9Sstevel@tonic-gate {
11883d63ea05Sas145665 int c;
11893d63ea05Sas145665 int i = 0;
11903d63ea05Sas145665 char resp[LINE_MAX + 1];
11917c478bd9Sstevel@tonic-gate
11927c478bd9Sstevel@tonic-gate (void) fflush(stdout); /* to flush possible `-print' */
11937c478bd9Sstevel@tonic-gate
11947c478bd9Sstevel@tonic-gate if ((*argv != dummyarg) && (strcmp(*argv, name)))
11957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "< %s ... %s >? ", *argv, name);
11967c478bd9Sstevel@tonic-gate else
11977c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "< {} ... %s >? ", name);
11987c478bd9Sstevel@tonic-gate
11997c478bd9Sstevel@tonic-gate (void) fflush(stderr);
12003d63ea05Sas145665
12013d63ea05Sas145665 while ((c = getchar()) != '\n') {
12027c478bd9Sstevel@tonic-gate if (c == EOF)
12037c478bd9Sstevel@tonic-gate exit(2);
12043d63ea05Sas145665 if (i < LINE_MAX)
12053d63ea05Sas145665 resp[i++] = c;
12063d63ea05Sas145665 }
12073d63ea05Sas145665 resp[i] = '\0';
12083d63ea05Sas145665
12093d63ea05Sas145665 if (yes_check(resp))
12103d63ea05Sas145665 return (doexec(name, argv, NULL));
12117c478bd9Sstevel@tonic-gate else
12123d63ea05Sas145665 return (0);
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate
12157c478bd9Sstevel@tonic-gate /*
12167c478bd9Sstevel@tonic-gate * execute argv with {} replaced by name
1217d35170d6Srm88369 *
1218d35170d6Srm88369 * Per XPG6, find must exit non-zero if an invocation through
1219d35170d6Srm88369 * -exec, punctuated by a plus sign, exits non-zero, so set
1220d35170d6Srm88369 * exitcode if we see a non-zero exit.
1221d35170d6Srm88369 * exitcode should be NULL when -exec or -ok is not punctuated
1222d35170d6Srm88369 * by a plus sign.
12237c478bd9Sstevel@tonic-gate */
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate static int
doexec(const char * name,char * argv[],int * exitcode)122627d3a169SToomas Soome doexec(const char *name, char *argv[], int *exitcode)
12277c478bd9Sstevel@tonic-gate {
12287c478bd9Sstevel@tonic-gate char *cp;
12297c478bd9Sstevel@tonic-gate char **av = argv;
1230d35170d6Srm88369 char *newargs[1 + SHELL_MAXARGS + 1];
12317c478bd9Sstevel@tonic-gate int dummyseen = 0;
1232d35170d6Srm88369 int i, j, status, rc, r = 0;
1233d35170d6Srm88369 int exit_status = 0;
1234d35170d6Srm88369 pid_t pid, pid1;
12357c478bd9Sstevel@tonic-gate
12367c478bd9Sstevel@tonic-gate (void) fflush(stdout); /* to flush possible `-print' */
12377c478bd9Sstevel@tonic-gate if (name) {
12387c478bd9Sstevel@tonic-gate while (cp = *av++) {
12397c478bd9Sstevel@tonic-gate if (cp == dummyarg) {
12407c478bd9Sstevel@tonic-gate dummyseen = 1;
124127d3a169SToomas Soome av[-1] = (char *)name;
12427c478bd9Sstevel@tonic-gate }
12437c478bd9Sstevel@tonic-gate
12447c478bd9Sstevel@tonic-gate }
12457c478bd9Sstevel@tonic-gate }
12467c478bd9Sstevel@tonic-gate if (argv[0] == NULL) /* null command line */
12477c478bd9Sstevel@tonic-gate return (r);
12487c478bd9Sstevel@tonic-gate
1249d35170d6Srm88369 if ((pid = fork()) == -1) {
1250d35170d6Srm88369 /* fork failed */
1251d35170d6Srm88369 if (exitcode != NULL)
1252d35170d6Srm88369 *exitcode = 1;
1253d35170d6Srm88369 return (0);
1254d35170d6Srm88369 }
1255d35170d6Srm88369 if (pid != 0) {
1256d35170d6Srm88369 /* parent */
1257d35170d6Srm88369 do {
1258d35170d6Srm88369 /* wait for child to exit */
1259d35170d6Srm88369 if ((rc = wait(&r)) == -1 && errno != EINTR) {
1260d35170d6Srm88369 (void) fprintf(stderr,
1261d35170d6Srm88369 gettext("wait failed %s"), strerror(errno));
1262d35170d6Srm88369
1263d35170d6Srm88369 if (exitcode != NULL)
1264d35170d6Srm88369 *exitcode = 1;
1265d35170d6Srm88369 return (0);
1266d35170d6Srm88369 }
1267d35170d6Srm88369 } while (rc != pid);
1268d35170d6Srm88369 } else {
1269d35170d6Srm88369 /* child */
12707c478bd9Sstevel@tonic-gate (void) execvp(argv[0], argv);
1271d35170d6Srm88369 if (errno != E2BIG)
1272d35170d6Srm88369 exit(1);
1273d35170d6Srm88369
1274d35170d6Srm88369 /*
1275d35170d6Srm88369 * We are in a situation where argv[0] points to a
1276d35170d6Srm88369 * script without the interpreter line, e.g. #!/bin/sh.
1277d35170d6Srm88369 * execvp() will execute either /usr/bin/sh or
1278d35170d6Srm88369 * /usr/xpg4/bin/sh against the script, and you will be
1279d35170d6Srm88369 * limited to SHELL_MAXARGS arguments. If you try to
1280d35170d6Srm88369 * pass more than SHELL_MAXARGS arguments, execvp()
1281d35170d6Srm88369 * fails with E2BIG.
1282d35170d6Srm88369 * See usr/src/lib/libc/port/gen/execvp.c.
1283d35170d6Srm88369 *
1284d35170d6Srm88369 * In this situation, process the argument list by
1285d35170d6Srm88369 * packets of SHELL_MAXARGS arguments with respect of
1286d35170d6Srm88369 * the following rules:
1287d35170d6Srm88369 * 1. the invocations have to complete before find exits
1288d35170d6Srm88369 * 2. only one invocation can be running at a time
1289d35170d6Srm88369 */
1290d35170d6Srm88369
1291d35170d6Srm88369 i = 1;
1292d35170d6Srm88369 newargs[0] = argv[0];
1293d35170d6Srm88369
1294d35170d6Srm88369 while (argv[i]) {
1295d35170d6Srm88369 j = 1;
1296d35170d6Srm88369 while (j <= SHELL_MAXARGS && argv[i]) {
1297d35170d6Srm88369 newargs[j++] = argv[i++];
1298d35170d6Srm88369 }
1299d35170d6Srm88369 newargs[j] = NULL;
1300d35170d6Srm88369
1301d35170d6Srm88369 if ((pid1 = fork()) == -1) {
1302d35170d6Srm88369 /* fork failed */
13037c478bd9Sstevel@tonic-gate exit(1);
13047c478bd9Sstevel@tonic-gate }
1305d35170d6Srm88369 if (pid1 == 0) {
1306d35170d6Srm88369 /* child */
1307d35170d6Srm88369 (void) execvp(newargs[0], newargs);
1308d35170d6Srm88369 exit(1);
1309d35170d6Srm88369 }
1310d35170d6Srm88369
1311d35170d6Srm88369 status = 0;
1312d35170d6Srm88369
1313d35170d6Srm88369 do {
1314d35170d6Srm88369 /* wait for the child to exit */
1315d35170d6Srm88369 if ((rc = wait(&status)) == -1 &&
1316d35170d6Srm88369 errno != EINTR) {
1317d35170d6Srm88369 (void) fprintf(stderr,
1318d35170d6Srm88369 gettext("wait failed %s"),
1319d35170d6Srm88369 strerror(errno));
1320d35170d6Srm88369 exit(1);
1321d35170d6Srm88369 }
1322d35170d6Srm88369 } while (rc != pid1);
1323d35170d6Srm88369
1324d35170d6Srm88369 if (status)
1325d35170d6Srm88369 exit_status = 1;
1326d35170d6Srm88369 }
1327d35170d6Srm88369 /* all the invocations have completed */
1328d35170d6Srm88369 exit(exit_status);
1329d35170d6Srm88369 }
1330d35170d6Srm88369
13317c478bd9Sstevel@tonic-gate if (name && dummyseen) {
13327c478bd9Sstevel@tonic-gate for (av = argv; cp = *av++; ) {
13337c478bd9Sstevel@tonic-gate if (cp == name)
13347c478bd9Sstevel@tonic-gate av[-1] = dummyarg;
13357c478bd9Sstevel@tonic-gate }
13367c478bd9Sstevel@tonic-gate }
13377c478bd9Sstevel@tonic-gate
1338d35170d6Srm88369 if (r && exitcode != NULL)
1339d35170d6Srm88369 *exitcode = 3; /* use to indicate error in cmd invocation */
1340d35170d6Srm88369
13417c478bd9Sstevel@tonic-gate return (!r);
13427c478bd9Sstevel@tonic-gate }
13437c478bd9Sstevel@tonic-gate
1344ab823b7fSPrasad Joshi static int
dodelete(const char * name,const struct stat * statb,struct FTW * state)134527d3a169SToomas Soome dodelete(const char *name, const struct stat *statb, struct FTW *state)
1346ab823b7fSPrasad Joshi {
134727d3a169SToomas Soome const char *fn;
1348ab823b7fSPrasad Joshi int rc = 0;
1349ab823b7fSPrasad Joshi
1350ab823b7fSPrasad Joshi /* restrict symlinks */
1351ab823b7fSPrasad Joshi if ((walkflags & FTW_PHYS) == 0) {
1352ab823b7fSPrasad Joshi (void) fprintf(stderr,
1353ab823b7fSPrasad Joshi gettext("-delete is not allowed when symlinks are "
1354ab823b7fSPrasad Joshi "followed.\n"));
1355ab823b7fSPrasad Joshi return (1);
1356ab823b7fSPrasad Joshi }
1357ab823b7fSPrasad Joshi
1358ab823b7fSPrasad Joshi fn = name + state->base;
1359ab823b7fSPrasad Joshi if (strcmp(fn, ".") == 0) {
1360ab823b7fSPrasad Joshi /* nothing to do */
1361ab823b7fSPrasad Joshi return (1);
1362ab823b7fSPrasad Joshi }
1363ab823b7fSPrasad Joshi
1364ab823b7fSPrasad Joshi if (strchr(fn, '/') != NULL) {
1365ab823b7fSPrasad Joshi (void) fprintf(stderr,
1366ab823b7fSPrasad Joshi gettext("-delete with relative path is unsafe."));
1367ab823b7fSPrasad Joshi return (1);
1368ab823b7fSPrasad Joshi }
1369ab823b7fSPrasad Joshi
1370ab823b7fSPrasad Joshi if (S_ISDIR(statb->st_mode)) {
1371ab823b7fSPrasad Joshi /* delete directory */
1372ab823b7fSPrasad Joshi rc = rmdir(name);
1373ab823b7fSPrasad Joshi } else {
1374ab823b7fSPrasad Joshi /* delete file */
1375ab823b7fSPrasad Joshi rc = unlink(name);
1376ab823b7fSPrasad Joshi }
1377ab823b7fSPrasad Joshi
1378ab823b7fSPrasad Joshi if (rc < 0) {
1379ab823b7fSPrasad Joshi /* operation failed */
1380ab823b7fSPrasad Joshi (void) fprintf(stderr, gettext("delete failed %s: %s\n"),
1381ab823b7fSPrasad Joshi name, strerror(errno));
1382ab823b7fSPrasad Joshi return (1);
1383ab823b7fSPrasad Joshi }
1384ab823b7fSPrasad Joshi
1385ab823b7fSPrasad Joshi return (1);
1386ab823b7fSPrasad Joshi }
13877c478bd9Sstevel@tonic-gate
13887c478bd9Sstevel@tonic-gate /*
13897c478bd9Sstevel@tonic-gate * Table lookup routine
13907c478bd9Sstevel@tonic-gate */
13917c478bd9Sstevel@tonic-gate static struct Args *
lookup(char * word)139227d3a169SToomas Soome lookup(char *word)
13937c478bd9Sstevel@tonic-gate {
13947c478bd9Sstevel@tonic-gate struct Args *argp = commands;
13957c478bd9Sstevel@tonic-gate int second;
13967c478bd9Sstevel@tonic-gate if (word == 0 || *word == 0)
13977c478bd9Sstevel@tonic-gate return (0);
13987c478bd9Sstevel@tonic-gate second = word[1];
13997c478bd9Sstevel@tonic-gate while (*argp->name) {
14007c478bd9Sstevel@tonic-gate if (second == argp->name[1] && strcmp(word, argp->name) == 0)
14017c478bd9Sstevel@tonic-gate return (argp);
14027c478bd9Sstevel@tonic-gate argp++;
14037c478bd9Sstevel@tonic-gate }
14047c478bd9Sstevel@tonic-gate return (0);
14057c478bd9Sstevel@tonic-gate }
14067c478bd9Sstevel@tonic-gate
14077c478bd9Sstevel@tonic-gate
14087c478bd9Sstevel@tonic-gate /*
14097c478bd9Sstevel@tonic-gate * Get space for variable length argument list
14107c478bd9Sstevel@tonic-gate */
14117c478bd9Sstevel@tonic-gate
14127c478bd9Sstevel@tonic-gate static struct Arglist *
varargs(char ** com)141327d3a169SToomas Soome varargs(char **com)
14147c478bd9Sstevel@tonic-gate {
14157c478bd9Sstevel@tonic-gate struct Arglist *ap;
14167c478bd9Sstevel@tonic-gate int n;
14177c478bd9Sstevel@tonic-gate char **ep;
14187c478bd9Sstevel@tonic-gate if (varsize == 0) {
14197c478bd9Sstevel@tonic-gate n = 2*sizeof (char **);
14207c478bd9Sstevel@tonic-gate for (ep = environ; *ep; ep++)
14217c478bd9Sstevel@tonic-gate n += (strlen(*ep)+sizeof (ep) + 1);
14227c478bd9Sstevel@tonic-gate varsize = sizeof (struct Arglist)+ARG_MAX-PATH_MAX-n-1;
14237c478bd9Sstevel@tonic-gate }
14247c478bd9Sstevel@tonic-gate ap = (struct Arglist *)malloc(varsize+1);
14257c478bd9Sstevel@tonic-gate ap->end = (char *)ap + varsize;
14267c478bd9Sstevel@tonic-gate ap->nextstr = ap->end;
14277c478bd9Sstevel@tonic-gate ap->nextvar = ap->arglist;
142827d3a169SToomas Soome while (*ap->nextvar++ = *com++)
142927d3a169SToomas Soome ;
14307c478bd9Sstevel@tonic-gate ap->nextvar--;
14317c478bd9Sstevel@tonic-gate ap->firstvar = ap->nextvar;
14327c478bd9Sstevel@tonic-gate ap->next = lastlist;
14337c478bd9Sstevel@tonic-gate lastlist = ap;
14347c478bd9Sstevel@tonic-gate return (ap);
14357c478bd9Sstevel@tonic-gate }
14367c478bd9Sstevel@tonic-gate
14377c478bd9Sstevel@tonic-gate /*
14387c478bd9Sstevel@tonic-gate * filter command support
14397c478bd9Sstevel@tonic-gate * fork and exec cmd(argv) according to mode:
14407c478bd9Sstevel@tonic-gate *
14417c478bd9Sstevel@tonic-gate * "r" with fp as stdin of cmd (default stdin), cmd stdout returned
14427c478bd9Sstevel@tonic-gate * "w" with fp as stdout of cmd (default stdout), cmd stdin returned
14437c478bd9Sstevel@tonic-gate */
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate #define CMDERR ((1<<8)-1) /* command error exit code */
14467c478bd9Sstevel@tonic-gate #define MAXCMDS 8 /* max # simultaneous cmdopen()'s */
14477c478bd9Sstevel@tonic-gate
14487c478bd9Sstevel@tonic-gate static struct /* info for each cmdopen() */
14497c478bd9Sstevel@tonic-gate {
14507c478bd9Sstevel@tonic-gate FILE *fp; /* returned by cmdopen() */
14517c478bd9Sstevel@tonic-gate pid_t pid; /* pid used by cmdopen() */
14527c478bd9Sstevel@tonic-gate } cmdproc[MAXCMDS];
14537c478bd9Sstevel@tonic-gate
14547c478bd9Sstevel@tonic-gate static FILE *
cmdopen(char * cmd,char ** argv,char * mode,FILE * fp)145527d3a169SToomas Soome cmdopen(char *cmd, char **argv, char *mode, FILE *fp)
14567c478bd9Sstevel@tonic-gate {
14577c478bd9Sstevel@tonic-gate int proc;
14587c478bd9Sstevel@tonic-gate int cmdfd;
14597c478bd9Sstevel@tonic-gate int usrfd;
14607c478bd9Sstevel@tonic-gate int pio[2];
14617c478bd9Sstevel@tonic-gate
14627c478bd9Sstevel@tonic-gate switch (*mode) {
14637c478bd9Sstevel@tonic-gate case 'r':
14647c478bd9Sstevel@tonic-gate cmdfd = 1;
14657c478bd9Sstevel@tonic-gate usrfd = 0;
14667c478bd9Sstevel@tonic-gate break;
14677c478bd9Sstevel@tonic-gate case 'w':
14687c478bd9Sstevel@tonic-gate cmdfd = 0;
14697c478bd9Sstevel@tonic-gate usrfd = 1;
14707c478bd9Sstevel@tonic-gate break;
14717c478bd9Sstevel@tonic-gate default:
14727c478bd9Sstevel@tonic-gate return (0);
14737c478bd9Sstevel@tonic-gate }
14747c478bd9Sstevel@tonic-gate
14757c478bd9Sstevel@tonic-gate for (proc = 0; proc < MAXCMDS; proc++)
14767c478bd9Sstevel@tonic-gate if (!cmdproc[proc].fp)
14777c478bd9Sstevel@tonic-gate break;
14787c478bd9Sstevel@tonic-gate if (proc >= MAXCMDS)
14797c478bd9Sstevel@tonic-gate return (0);
14807c478bd9Sstevel@tonic-gate
14817c478bd9Sstevel@tonic-gate if (pipe(pio))
14827c478bd9Sstevel@tonic-gate return (0);
14837c478bd9Sstevel@tonic-gate
14847c478bd9Sstevel@tonic-gate switch (cmdproc[proc].pid = fork()) {
14857c478bd9Sstevel@tonic-gate case -1:
14867c478bd9Sstevel@tonic-gate return (0);
14877c478bd9Sstevel@tonic-gate case 0:
14887c478bd9Sstevel@tonic-gate if (fp && fileno(fp) != usrfd) {
14897c478bd9Sstevel@tonic-gate (void) close(usrfd);
14907c478bd9Sstevel@tonic-gate if (dup2(fileno(fp), usrfd) != usrfd)
14917c478bd9Sstevel@tonic-gate _exit(CMDERR);
14927c478bd9Sstevel@tonic-gate (void) close(fileno(fp));
14937c478bd9Sstevel@tonic-gate }
14947c478bd9Sstevel@tonic-gate (void) close(cmdfd);
14957c478bd9Sstevel@tonic-gate if (dup2(pio[cmdfd], cmdfd) != cmdfd)
14967c478bd9Sstevel@tonic-gate _exit(CMDERR);
14977c478bd9Sstevel@tonic-gate (void) close(pio[cmdfd]);
14987c478bd9Sstevel@tonic-gate (void) close(pio[usrfd]);
14997c478bd9Sstevel@tonic-gate (void) execvp(cmd, argv);
15007c478bd9Sstevel@tonic-gate if (errno == ENOEXEC) {
15017c478bd9Sstevel@tonic-gate char **p;
15027c478bd9Sstevel@tonic-gate char **v;
15037c478bd9Sstevel@tonic-gate
15047c478bd9Sstevel@tonic-gate /*
15057c478bd9Sstevel@tonic-gate * assume cmd is a shell script
15067c478bd9Sstevel@tonic-gate */
15077c478bd9Sstevel@tonic-gate
15087c478bd9Sstevel@tonic-gate p = argv;
150927d3a169SToomas Soome while (*p++)
151027d3a169SToomas Soome ;
151127d3a169SToomas Soome if (v = malloc((p - argv + 1) * sizeof (char **))) {
15127c478bd9Sstevel@tonic-gate p = v;
15137c478bd9Sstevel@tonic-gate *p++ = cmd;
151427d3a169SToomas Soome if (*argv)
151527d3a169SToomas Soome argv++;
151627d3a169SToomas Soome while (*p++ = *argv++)
151727d3a169SToomas Soome ;
15187c478bd9Sstevel@tonic-gate (void) execv(getshell(), v);
15197c478bd9Sstevel@tonic-gate }
15207c478bd9Sstevel@tonic-gate }
15217c478bd9Sstevel@tonic-gate _exit(CMDERR);
15227c478bd9Sstevel@tonic-gate /*NOTREACHED*/
15237c478bd9Sstevel@tonic-gate default:
15247c478bd9Sstevel@tonic-gate (void) close(pio[cmdfd]);
15257c478bd9Sstevel@tonic-gate return (cmdproc[proc].fp = fdopen(pio[usrfd], mode));
15267c478bd9Sstevel@tonic-gate }
15277c478bd9Sstevel@tonic-gate }
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate /*
15307c478bd9Sstevel@tonic-gate * close a stream opened by cmdopen()
15317c478bd9Sstevel@tonic-gate * -1 returned if cmdopen() had a problem
15327c478bd9Sstevel@tonic-gate * otherwise exit() status of command is returned
15337c478bd9Sstevel@tonic-gate */
15347c478bd9Sstevel@tonic-gate
15357c478bd9Sstevel@tonic-gate static int
cmdclose(FILE * fp)153627d3a169SToomas Soome cmdclose(FILE *fp)
15377c478bd9Sstevel@tonic-gate {
15387c478bd9Sstevel@tonic-gate int i;
15397c478bd9Sstevel@tonic-gate pid_t p, pid;
15407c478bd9Sstevel@tonic-gate int status;
15417c478bd9Sstevel@tonic-gate
15427c478bd9Sstevel@tonic-gate for (i = 0; i < MAXCMDS; i++)
15437c478bd9Sstevel@tonic-gate if (fp == cmdproc[i].fp) break;
15447c478bd9Sstevel@tonic-gate if (i >= MAXCMDS)
15457c478bd9Sstevel@tonic-gate return (-1);
15467c478bd9Sstevel@tonic-gate (void) fclose(fp);
15477c478bd9Sstevel@tonic-gate cmdproc[i].fp = 0;
15487c478bd9Sstevel@tonic-gate pid = cmdproc[i].pid;
154927d3a169SToomas Soome while ((p = wait(&status)) != pid && p != (pid_t)-1)
155027d3a169SToomas Soome ;
15517c478bd9Sstevel@tonic-gate if (p == pid) {
15527c478bd9Sstevel@tonic-gate status = (status >> 8) & CMDERR;
15537c478bd9Sstevel@tonic-gate if (status == CMDERR)
15547c478bd9Sstevel@tonic-gate status = -1;
15557c478bd9Sstevel@tonic-gate }
15567c478bd9Sstevel@tonic-gate else
15577c478bd9Sstevel@tonic-gate status = -1;
15587c478bd9Sstevel@tonic-gate return (status);
15597c478bd9Sstevel@tonic-gate }
15607c478bd9Sstevel@tonic-gate
15617c478bd9Sstevel@tonic-gate /*
15627c478bd9Sstevel@tonic-gate * return pointer to the full path name of the shell
15637c478bd9Sstevel@tonic-gate *
15647c478bd9Sstevel@tonic-gate * SHELL is read from the environment and must start with /
15657c478bd9Sstevel@tonic-gate *
15667c478bd9Sstevel@tonic-gate * if set-uid or set-gid then the executable and its containing
15677c478bd9Sstevel@tonic-gate * directory must not be writable by the real user
15687c478bd9Sstevel@tonic-gate *
15697c478bd9Sstevel@tonic-gate * /usr/bin/sh is returned by default
15707c478bd9Sstevel@tonic-gate */
15717c478bd9Sstevel@tonic-gate
15727c478bd9Sstevel@tonic-gate char *
getshell(void)157327d3a169SToomas Soome getshell(void)
15747c478bd9Sstevel@tonic-gate {
15757c478bd9Sstevel@tonic-gate char *s;
15767c478bd9Sstevel@tonic-gate char *sh;
15777c478bd9Sstevel@tonic-gate uid_t u;
15787c478bd9Sstevel@tonic-gate int j;
15797c478bd9Sstevel@tonic-gate
15807c478bd9Sstevel@tonic-gate if (((sh = getenv("SHELL")) != 0) && *sh == '/') {
15817c478bd9Sstevel@tonic-gate if (u = getuid()) {
15827c478bd9Sstevel@tonic-gate if ((u != geteuid() || getgid() != getegid()) &&
15833d63ea05Sas145665 access(sh, 2) == 0)
15847c478bd9Sstevel@tonic-gate goto defshell;
15857c478bd9Sstevel@tonic-gate s = strrchr(sh, '/');
15867c478bd9Sstevel@tonic-gate *s = 0;
15877c478bd9Sstevel@tonic-gate j = access(sh, 2);
15887c478bd9Sstevel@tonic-gate *s = '/';
15897c478bd9Sstevel@tonic-gate if (!j) goto defshell;
15907c478bd9Sstevel@tonic-gate }
15917c478bd9Sstevel@tonic-gate return (sh);
15927c478bd9Sstevel@tonic-gate }
15937c478bd9Sstevel@tonic-gate defshell:
15947c478bd9Sstevel@tonic-gate return ("/usr/bin/sh");
15957c478bd9Sstevel@tonic-gate }
15967c478bd9Sstevel@tonic-gate
15977c478bd9Sstevel@tonic-gate /*
15987c478bd9Sstevel@tonic-gate * the following functions implement the added "-ls" option
15997c478bd9Sstevel@tonic-gate */
16007c478bd9Sstevel@tonic-gate
16017c478bd9Sstevel@tonic-gate #include <utmpx.h>
16027c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
16037c478bd9Sstevel@tonic-gate
16047c478bd9Sstevel@tonic-gate struct utmpx utmpx;
16057c478bd9Sstevel@tonic-gate #define NMAX (sizeof (utmpx.ut_name))
16067c478bd9Sstevel@tonic-gate #define SCPYN(a, b) (void) strncpy(a, b, NMAX)
16077c478bd9Sstevel@tonic-gate
16087c478bd9Sstevel@tonic-gate #define NUID 64
16097c478bd9Sstevel@tonic-gate #define NGID 64
16107c478bd9Sstevel@tonic-gate
16117c478bd9Sstevel@tonic-gate static struct ncache {
16127c478bd9Sstevel@tonic-gate int id;
16137c478bd9Sstevel@tonic-gate char name[NMAX+1];
16147c478bd9Sstevel@tonic-gate } nc[NUID], gc[NGID];
16157c478bd9Sstevel@tonic-gate
16167c478bd9Sstevel@tonic-gate /*
16177c478bd9Sstevel@tonic-gate * This function assumes that the password file is hashed
16187c478bd9Sstevel@tonic-gate * (or some such) to allow fast access based on a name key.
16197c478bd9Sstevel@tonic-gate */
16207c478bd9Sstevel@tonic-gate static char *
getname(uid_t uid)16217c478bd9Sstevel@tonic-gate getname(uid_t uid)
16227c478bd9Sstevel@tonic-gate {
16237c478bd9Sstevel@tonic-gate struct passwd *pw;
16247c478bd9Sstevel@tonic-gate int cp;
16257c478bd9Sstevel@tonic-gate
16267c478bd9Sstevel@tonic-gate #if (((NUID) & ((NUID) - 1)) != 0)
16277c478bd9Sstevel@tonic-gate cp = uid % (NUID);
16287c478bd9Sstevel@tonic-gate #else
16297c478bd9Sstevel@tonic-gate cp = uid & ((NUID) - 1);
16307c478bd9Sstevel@tonic-gate #endif
1631f48205beScasper if (nc[cp].id == uid && nc[cp].name[0])
16327c478bd9Sstevel@tonic-gate return (nc[cp].name);
16337c478bd9Sstevel@tonic-gate pw = getpwuid(uid);
16347c478bd9Sstevel@tonic-gate if (!pw)
16357c478bd9Sstevel@tonic-gate return (0);
16367c478bd9Sstevel@tonic-gate nc[cp].id = uid;
16377c478bd9Sstevel@tonic-gate SCPYN(nc[cp].name, pw->pw_name);
16387c478bd9Sstevel@tonic-gate return (nc[cp].name);
16397c478bd9Sstevel@tonic-gate }
16407c478bd9Sstevel@tonic-gate
16417c478bd9Sstevel@tonic-gate /*
16427c478bd9Sstevel@tonic-gate * This function assumes that the group file is hashed
16437c478bd9Sstevel@tonic-gate * (or some such) to allow fast access based on a name key.
16447c478bd9Sstevel@tonic-gate */
16457c478bd9Sstevel@tonic-gate static char *
getgroup(gid_t gid)16467c478bd9Sstevel@tonic-gate getgroup(gid_t gid)
16477c478bd9Sstevel@tonic-gate {
16487c478bd9Sstevel@tonic-gate struct group *gr;
16497c478bd9Sstevel@tonic-gate int cp;
16507c478bd9Sstevel@tonic-gate
16517c478bd9Sstevel@tonic-gate #if (((NGID) & ((NGID) - 1)) != 0)
16527c478bd9Sstevel@tonic-gate cp = gid % (NGID);
16537c478bd9Sstevel@tonic-gate #else
16547c478bd9Sstevel@tonic-gate cp = gid & ((NGID) - 1);
16557c478bd9Sstevel@tonic-gate #endif
1656f48205beScasper if (gc[cp].id == gid && gc[cp].name[0])
16577c478bd9Sstevel@tonic-gate return (gc[cp].name);
16587c478bd9Sstevel@tonic-gate gr = getgrgid(gid);
16597c478bd9Sstevel@tonic-gate if (!gr)
16607c478bd9Sstevel@tonic-gate return (0);
16617c478bd9Sstevel@tonic-gate gc[cp].id = gid;
16627c478bd9Sstevel@tonic-gate SCPYN(gc[cp].name, gr->gr_name);
16637c478bd9Sstevel@tonic-gate return (gc[cp].name);
16647c478bd9Sstevel@tonic-gate }
16657c478bd9Sstevel@tonic-gate
16667c478bd9Sstevel@tonic-gate #define permoffset(who) ((who) * 3)
16677c478bd9Sstevel@tonic-gate #define permission(who, type) ((type) >> permoffset(who))
16687c478bd9Sstevel@tonic-gate #define kbytes(bytes) (((bytes) + 1023) / 1024)
16697c478bd9Sstevel@tonic-gate
16707c478bd9Sstevel@tonic-gate static int
list(const char * file,const struct stat * stp)167127d3a169SToomas Soome list(const char *file, const struct stat *stp)
16727c478bd9Sstevel@tonic-gate {
16737c478bd9Sstevel@tonic-gate char pmode[32], uname[32], gname[32], fsize[32], ftime[32];
1674fa9e4066Sahrens int trivial;
16757c478bd9Sstevel@tonic-gate
16767c478bd9Sstevel@tonic-gate /*
16777c478bd9Sstevel@tonic-gate * Each line below contains the relevant permission (column 1) and character
16787c478bd9Sstevel@tonic-gate * shown when the corresponding execute bit is either clear (column 2)
16797c478bd9Sstevel@tonic-gate * or set (column 3)
16807c478bd9Sstevel@tonic-gate * These permissions are as shown by ls(1b)
16817c478bd9Sstevel@tonic-gate */
16827c478bd9Sstevel@tonic-gate static long special[] = { S_ISUID, 'S', 's',
16837c478bd9Sstevel@tonic-gate S_ISGID, 'S', 's',
16847c478bd9Sstevel@tonic-gate S_ISVTX, 'T', 't' };
16857c478bd9Sstevel@tonic-gate
16867c478bd9Sstevel@tonic-gate static time_t sixmonthsago = -1;
16877c478bd9Sstevel@tonic-gate #ifdef S_IFLNK
16887c478bd9Sstevel@tonic-gate char flink[MAXPATHLEN + 1];
16897c478bd9Sstevel@tonic-gate #endif
16907c478bd9Sstevel@tonic-gate int who;
16917c478bd9Sstevel@tonic-gate char *cp;
169227d3a169SToomas Soome const char *tailname;
16937c478bd9Sstevel@tonic-gate time_t now;
16947c478bd9Sstevel@tonic-gate long long ksize;
16957c478bd9Sstevel@tonic-gate
16967c478bd9Sstevel@tonic-gate if (file == NULL || stp == NULL)
16977c478bd9Sstevel@tonic-gate return (-1);
16987c478bd9Sstevel@tonic-gate
16997c478bd9Sstevel@tonic-gate (void) time(&now);
17007c478bd9Sstevel@tonic-gate if (sixmonthsago == -1)
17017c478bd9Sstevel@tonic-gate sixmonthsago = now - 6L*30L*24L*60L*60L;
17027c478bd9Sstevel@tonic-gate
17037c478bd9Sstevel@tonic-gate switch (stp->st_mode & S_IFMT) {
17047c478bd9Sstevel@tonic-gate #ifdef S_IFDIR
17057c478bd9Sstevel@tonic-gate case S_IFDIR: /* directory */
17067c478bd9Sstevel@tonic-gate pmode[0] = 'd';
17077c478bd9Sstevel@tonic-gate break;
17087c478bd9Sstevel@tonic-gate #endif
17097c478bd9Sstevel@tonic-gate #ifdef S_IFCHR
17107c478bd9Sstevel@tonic-gate case S_IFCHR: /* character special */
17117c478bd9Sstevel@tonic-gate pmode[0] = 'c';
17127c478bd9Sstevel@tonic-gate break;
17137c478bd9Sstevel@tonic-gate #endif
17147c478bd9Sstevel@tonic-gate #ifdef S_IFBLK
17157c478bd9Sstevel@tonic-gate case S_IFBLK: /* block special */
17167c478bd9Sstevel@tonic-gate pmode[0] = 'b';
17177c478bd9Sstevel@tonic-gate break;
17187c478bd9Sstevel@tonic-gate #endif
17197c478bd9Sstevel@tonic-gate #ifdef S_IFIFO
17207c478bd9Sstevel@tonic-gate case S_IFIFO: /* fifo special */
17217c478bd9Sstevel@tonic-gate pmode[0] = 'p';
17227c478bd9Sstevel@tonic-gate break;
17237c478bd9Sstevel@tonic-gate #endif
17247c478bd9Sstevel@tonic-gate #ifdef S_IFLNK
17257c478bd9Sstevel@tonic-gate case S_IFLNK: /* symbolic link */
17267c478bd9Sstevel@tonic-gate pmode[0] = 'l';
17277c478bd9Sstevel@tonic-gate break;
17287c478bd9Sstevel@tonic-gate #endif
17297c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK
17307c478bd9Sstevel@tonic-gate case S_IFSOCK: /* socket */
17317c478bd9Sstevel@tonic-gate pmode[0] = 's';
17327c478bd9Sstevel@tonic-gate break;
17337c478bd9Sstevel@tonic-gate #endif
17347c478bd9Sstevel@tonic-gate #ifdef S_IFDOOR
17357c478bd9Sstevel@tonic-gate case S_IFDOOR: /* door */
17367c478bd9Sstevel@tonic-gate pmode[0] = 'D';
17377c478bd9Sstevel@tonic-gate break;
17387c478bd9Sstevel@tonic-gate #endif
17397c478bd9Sstevel@tonic-gate #ifdef S_IFREG
17407c478bd9Sstevel@tonic-gate case S_IFREG: /* regular */
17417c478bd9Sstevel@tonic-gate pmode[0] = '-';
17427c478bd9Sstevel@tonic-gate break;
17437c478bd9Sstevel@tonic-gate #endif
17447c478bd9Sstevel@tonic-gate default:
17457c478bd9Sstevel@tonic-gate pmode[0] = '?';
17467c478bd9Sstevel@tonic-gate break;
17477c478bd9Sstevel@tonic-gate }
17487c478bd9Sstevel@tonic-gate
17497c478bd9Sstevel@tonic-gate for (who = 0; who < 3; who++) {
17507c478bd9Sstevel@tonic-gate int is_exec = stp->st_mode & permission(who, S_IEXEC)? 1 : 0;
17517c478bd9Sstevel@tonic-gate
17527c478bd9Sstevel@tonic-gate if (stp->st_mode & permission(who, S_IREAD))
17537c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 1] = 'r';
17547c478bd9Sstevel@tonic-gate else
17557c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 1] = '-';
17567c478bd9Sstevel@tonic-gate
17577c478bd9Sstevel@tonic-gate if (stp->st_mode & permission(who, S_IWRITE))
17587c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 2] = 'w';
17597c478bd9Sstevel@tonic-gate else
17607c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 2] = '-';
17617c478bd9Sstevel@tonic-gate
17627c478bd9Sstevel@tonic-gate if (stp->st_mode & special[who * 3])
17637c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 3] =
17647c478bd9Sstevel@tonic-gate special[who * 3 + 1 + is_exec];
17657c478bd9Sstevel@tonic-gate else if (is_exec)
17667c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 3] = 'x';
17677c478bd9Sstevel@tonic-gate else
17687c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 3] = '-';
17697c478bd9Sstevel@tonic-gate }
17707c478bd9Sstevel@tonic-gate
17717c478bd9Sstevel@tonic-gate /*
17727c478bd9Sstevel@tonic-gate * Need to get the tail of the file name, since we have
17737c478bd9Sstevel@tonic-gate * already chdir()ed into the directory of the file
17747c478bd9Sstevel@tonic-gate */
17757c478bd9Sstevel@tonic-gate
17767c478bd9Sstevel@tonic-gate tailname = gettail(file);
17777c478bd9Sstevel@tonic-gate
1778fa9e4066Sahrens trivial = acl_trivial(tailname);
1779fa9e4066Sahrens if (trivial == -1)
1780fa9e4066Sahrens trivial = 0;
1781fa9e4066Sahrens
1782fa9e4066Sahrens if (trivial == 1)
17837c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 1] = '+';
17847c478bd9Sstevel@tonic-gate else
17857c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 1] = ' ';
17867c478bd9Sstevel@tonic-gate
17877c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 2] = '\0';
17887c478bd9Sstevel@tonic-gate
17897c478bd9Sstevel@tonic-gate /*
17907c478bd9Sstevel@tonic-gate * Prepare uname and gname. Always add a space afterwards
17917c478bd9Sstevel@tonic-gate * to keep columns from running together.
17927c478bd9Sstevel@tonic-gate */
17937c478bd9Sstevel@tonic-gate cp = getname(stp->st_uid);
17947c478bd9Sstevel@tonic-gate if (cp != NULL)
17957c478bd9Sstevel@tonic-gate (void) sprintf(uname, "%-8s ", cp);
17967c478bd9Sstevel@tonic-gate else
1797f48205beScasper (void) sprintf(uname, "%-8u ", stp->st_uid);
17987c478bd9Sstevel@tonic-gate
17997c478bd9Sstevel@tonic-gate cp = getgroup(stp->st_gid);
18007c478bd9Sstevel@tonic-gate if (cp != NULL)
18017c478bd9Sstevel@tonic-gate (void) sprintf(gname, "%-8s ", cp);
18027c478bd9Sstevel@tonic-gate else
1803f48205beScasper (void) sprintf(gname, "%-8u ", stp->st_gid);
18047c478bd9Sstevel@tonic-gate
18057c478bd9Sstevel@tonic-gate if (pmode[0] == 'b' || pmode[0] == 'c')
18067c478bd9Sstevel@tonic-gate (void) sprintf(fsize, "%3ld,%4ld",
18077c478bd9Sstevel@tonic-gate major(stp->st_rdev), minor(stp->st_rdev));
18087c478bd9Sstevel@tonic-gate else {
18097c478bd9Sstevel@tonic-gate (void) sprintf(fsize, (stp->st_size < 100000000) ?
18107c478bd9Sstevel@tonic-gate "%8lld" : "%lld", stp->st_size);
18117c478bd9Sstevel@tonic-gate #ifdef S_IFLNK
18127c478bd9Sstevel@tonic-gate if (pmode[0] == 'l') {
18137c478bd9Sstevel@tonic-gate who = readlink(tailname, flink, sizeof (flink) - 1);
18147c478bd9Sstevel@tonic-gate
18157c478bd9Sstevel@tonic-gate if (who >= 0)
18167c478bd9Sstevel@tonic-gate flink[who] = '\0';
18177c478bd9Sstevel@tonic-gate else
18187c478bd9Sstevel@tonic-gate flink[0] = '\0';
18197c478bd9Sstevel@tonic-gate }
18207c478bd9Sstevel@tonic-gate #endif
18217c478bd9Sstevel@tonic-gate }
18227c478bd9Sstevel@tonic-gate
18237c478bd9Sstevel@tonic-gate cp = ctime(&stp->st_mtime);
18247c478bd9Sstevel@tonic-gate if (stp->st_mtime < sixmonthsago || stp->st_mtime > now)
18257c478bd9Sstevel@tonic-gate (void) sprintf(ftime, "%-7.7s %-4.4s", cp + 4, cp + 20);
18267c478bd9Sstevel@tonic-gate else
18277c478bd9Sstevel@tonic-gate (void) sprintf(ftime, "%-12.12s", cp + 4);
18287c478bd9Sstevel@tonic-gate
18297c478bd9Sstevel@tonic-gate (void) printf((stp->st_ino < 100000) ? "%5llu " :
18307c478bd9Sstevel@tonic-gate "%llu ", stp->st_ino); /* inode # */
18317c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK
18327c478bd9Sstevel@tonic-gate ksize = (long long) kbytes(ldbtob(stp->st_blocks)); /* kbytes */
18337c478bd9Sstevel@tonic-gate #else
18347c478bd9Sstevel@tonic-gate ksize = (long long) kbytes(stp->st_size); /* kbytes */
18357c478bd9Sstevel@tonic-gate #endif
18367c478bd9Sstevel@tonic-gate (void) printf((ksize < 10000) ? "%4lld " : "%lld ", ksize);
183727d3a169SToomas Soome #ifdef S_IFLNK
18387c478bd9Sstevel@tonic-gate (void) printf("%s %2ld %s%s%s %s %s%s%s\n",
18397c478bd9Sstevel@tonic-gate pmode, /* protection */
18407c478bd9Sstevel@tonic-gate stp->st_nlink, /* # of links */
18417c478bd9Sstevel@tonic-gate uname, /* owner */
18427c478bd9Sstevel@tonic-gate gname, /* group */
18437c478bd9Sstevel@tonic-gate fsize, /* # of bytes */
18447c478bd9Sstevel@tonic-gate ftime, /* modify time */
18457c478bd9Sstevel@tonic-gate file, /* name */
18467c478bd9Sstevel@tonic-gate (pmode[0] == 'l') ? " -> " : "",
184727d3a169SToomas Soome (pmode[0] == 'l') ? flink : ""); /* symlink */
18487c478bd9Sstevel@tonic-gate #else
184927d3a169SToomas Soome (void) printf("%s %2ld %s%s%s %s %s\n",
185027d3a169SToomas Soome pmode, /* protection */
185127d3a169SToomas Soome stp->st_nlink, /* # of links */
185227d3a169SToomas Soome uname, /* owner */
185327d3a169SToomas Soome gname, /* group */
185427d3a169SToomas Soome fsize, /* # of bytes */
185527d3a169SToomas Soome ftime, /* modify time */
185627d3a169SToomas Soome file); /* name */
18577c478bd9Sstevel@tonic-gate #endif
18587c478bd9Sstevel@tonic-gate
18597c478bd9Sstevel@tonic-gate return (0);
18607c478bd9Sstevel@tonic-gate }
18617c478bd9Sstevel@tonic-gate
18627c478bd9Sstevel@tonic-gate static char *
new_string(char * s)18637c478bd9Sstevel@tonic-gate new_string(char *s)
18647c478bd9Sstevel@tonic-gate {
18657c478bd9Sstevel@tonic-gate char *p = strdup(s);
18667c478bd9Sstevel@tonic-gate
18677c478bd9Sstevel@tonic-gate if (p)
18687c478bd9Sstevel@tonic-gate return (p);
18697c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: out of memory\n"), cmdname);
18707c478bd9Sstevel@tonic-gate exit(1);
18717c478bd9Sstevel@tonic-gate /*NOTREACHED*/
18727c478bd9Sstevel@tonic-gate }
18737c478bd9Sstevel@tonic-gate
18747c478bd9Sstevel@tonic-gate /*
18757c478bd9Sstevel@tonic-gate * Read remote file system types from REMOTE_FS into the
18767c478bd9Sstevel@tonic-gate * remote_fstypes array.
18777c478bd9Sstevel@tonic-gate */
18787c478bd9Sstevel@tonic-gate static void
init_remote_fs(void)187927d3a169SToomas Soome init_remote_fs(void)
18807c478bd9Sstevel@tonic-gate {
18817c478bd9Sstevel@tonic-gate FILE *fp;
18827c478bd9Sstevel@tonic-gate char line_buf[LINEBUF_SIZE];
18837c478bd9Sstevel@tonic-gate
18847c478bd9Sstevel@tonic-gate if ((fp = fopen(REMOTE_FS, "r")) == NULL) {
18857c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
18867c478bd9Sstevel@tonic-gate gettext("%s: Warning: can't open %s, ignored\n"),
18877c478bd9Sstevel@tonic-gate REMOTE_FS, cmdname);
18887c478bd9Sstevel@tonic-gate /* Use default string name for NFS */
18897c478bd9Sstevel@tonic-gate remote_fstypes[fstype_index++] = "nfs";
18907c478bd9Sstevel@tonic-gate return;
18917c478bd9Sstevel@tonic-gate }
18927c478bd9Sstevel@tonic-gate
18937c478bd9Sstevel@tonic-gate while (fgets(line_buf, sizeof (line_buf), fp) != NULL) {
18947c478bd9Sstevel@tonic-gate char buf[LINEBUF_SIZE];
18957c478bd9Sstevel@tonic-gate
18967c478bd9Sstevel@tonic-gate /* LINTED - unbounded string specifier */
18977c478bd9Sstevel@tonic-gate (void) sscanf(line_buf, "%s", buf);
18987c478bd9Sstevel@tonic-gate remote_fstypes[fstype_index++] = new_string(buf);
18997c478bd9Sstevel@tonic-gate
19007c478bd9Sstevel@tonic-gate if (fstype_index == N_FSTYPES)
19017c478bd9Sstevel@tonic-gate break;
19027c478bd9Sstevel@tonic-gate }
19037c478bd9Sstevel@tonic-gate (void) fclose(fp);
19047c478bd9Sstevel@tonic-gate }
19057c478bd9Sstevel@tonic-gate
19067c478bd9Sstevel@tonic-gate #define NPERM 30 /* Largest machine */
19077c478bd9Sstevel@tonic-gate
19087c478bd9Sstevel@tonic-gate /*
19097c478bd9Sstevel@tonic-gate * The PERM struct is the machine that builds permissions. The p_special
19107c478bd9Sstevel@tonic-gate * field contains what permissions need to be checked at run-time in
19117c478bd9Sstevel@tonic-gate * getmode(). This is one of 'X', 'u', 'g', or 'o'. It contains '\0' to
19127c478bd9Sstevel@tonic-gate * indicate normal processing.
19137c478bd9Sstevel@tonic-gate */
19147c478bd9Sstevel@tonic-gate typedef struct PERMST {
19157c478bd9Sstevel@tonic-gate ushort_t p_who; /* Range of permission (e.g. ugo) */
19167c478bd9Sstevel@tonic-gate ushort_t p_perm; /* Bits to turn on, off, assign */
19177c478bd9Sstevel@tonic-gate uchar_t p_op; /* Operation: + - = */
19187c478bd9Sstevel@tonic-gate uchar_t p_special; /* Special handling? */
19197c478bd9Sstevel@tonic-gate } PERMST;
19207c478bd9Sstevel@tonic-gate
19217c478bd9Sstevel@tonic-gate #ifndef S_ISVTX
19227c478bd9Sstevel@tonic-gate #define S_ISVTX 0 /* Not .1 */
19237c478bd9Sstevel@tonic-gate #endif
19247c478bd9Sstevel@tonic-gate
19257c478bd9Sstevel@tonic-gate /* Mask values */
19267c478bd9Sstevel@tonic-gate #define P_A (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) /* allbits */
19277c478bd9Sstevel@tonic-gate #define P_U (S_ISUID|S_ISVTX|S_IRWXU) /* user */
19287c478bd9Sstevel@tonic-gate #define P_G (S_ISGID|S_ISVTX|S_IRWXG) /* group */
19297c478bd9Sstevel@tonic-gate #define P_O (S_ISVTX|S_IRWXO) /* other */
19307c478bd9Sstevel@tonic-gate
19317c478bd9Sstevel@tonic-gate static int iswho(int c);
19327c478bd9Sstevel@tonic-gate static int isop(int c);
19337c478bd9Sstevel@tonic-gate static int isperm(PERMST *pp, int c);
19347c478bd9Sstevel@tonic-gate
19357c478bd9Sstevel@tonic-gate static PERMST machine[NPERM]; /* Permission construction machine */
19367c478bd9Sstevel@tonic-gate static PERMST *endp; /* Last used PERM structure */
19377c478bd9Sstevel@tonic-gate
19387c478bd9Sstevel@tonic-gate static uint_t nowho; /* No who for this mode (DOS kludge) */
19397c478bd9Sstevel@tonic-gate
19407c478bd9Sstevel@tonic-gate /*
19417c478bd9Sstevel@tonic-gate * Read an ASCII string containing the symbolic/octal mode and
19427c478bd9Sstevel@tonic-gate * compile an automaton that recognizes it. The return value
19437c478bd9Sstevel@tonic-gate * is NULL if everything is OK, otherwise it is -1.
19447c478bd9Sstevel@tonic-gate */
19457c478bd9Sstevel@tonic-gate static int
readmode(const char * ascmode)194627d3a169SToomas Soome readmode(const char *ascmode)
19477c478bd9Sstevel@tonic-gate {
19487c478bd9Sstevel@tonic-gate const char *amode = ascmode;
19497c478bd9Sstevel@tonic-gate PERMST *pp;
19507c478bd9Sstevel@tonic-gate int seen_X;
19517c478bd9Sstevel@tonic-gate
19527c478bd9Sstevel@tonic-gate nowho = 0;
19537c478bd9Sstevel@tonic-gate seen_X = 0;
19547c478bd9Sstevel@tonic-gate pp = &machine[0];
19557c478bd9Sstevel@tonic-gate if (*amode >= '0' && *amode <= '7') {
19567c478bd9Sstevel@tonic-gate int mode;
19577c478bd9Sstevel@tonic-gate
19587c478bd9Sstevel@tonic-gate mode = 0;
19597c478bd9Sstevel@tonic-gate while (*amode >= '0' && *amode <= '7')
19607c478bd9Sstevel@tonic-gate mode = (mode<<3) + *amode++ - '0';
19617c478bd9Sstevel@tonic-gate if (*amode != '\0')
19627c478bd9Sstevel@tonic-gate return (-1);
19637c478bd9Sstevel@tonic-gate #if S_ISUID != 04000 || S_ISGID != 02000 || \
19647c478bd9Sstevel@tonic-gate S_IRUSR != 0400 || S_IWUSR != 0200 || S_IXUSR != 0100 || \
19657c478bd9Sstevel@tonic-gate S_IRGRP != 0040 || S_IWGRP != 0020 || S_IXGRP != 0010 || \
19667c478bd9Sstevel@tonic-gate S_IROTH != 0004 || S_IWOTH != 0002 || S_IXOTH != 0001
19677c478bd9Sstevel@tonic-gate /*
19687c478bd9Sstevel@tonic-gate * There is no requirement of the octal mode bits being
19697c478bd9Sstevel@tonic-gate * the same as the S_ macros.
19707c478bd9Sstevel@tonic-gate */
19717c478bd9Sstevel@tonic-gate {
19727c478bd9Sstevel@tonic-gate mode_t mapping[] = {
19737c478bd9Sstevel@tonic-gate S_IXOTH, S_IWOTH, S_IROTH,
19747c478bd9Sstevel@tonic-gate S_IXGRP, S_IWGRP, S_IRGRP,
19757c478bd9Sstevel@tonic-gate S_IXUSR, S_IWUSR, S_IRUSR,
19767c478bd9Sstevel@tonic-gate S_ISGID, S_ISUID,
19777c478bd9Sstevel@tonic-gate 0
19787c478bd9Sstevel@tonic-gate };
19797c478bd9Sstevel@tonic-gate int i, newmode = 0;
19807c478bd9Sstevel@tonic-gate
19817c478bd9Sstevel@tonic-gate for (i = 0; mapping[i] != 0; i++)
19827c478bd9Sstevel@tonic-gate if (mode & (1<<i))
19837c478bd9Sstevel@tonic-gate newmode |= mapping[i];
19847c478bd9Sstevel@tonic-gate mode = newmode;
19857c478bd9Sstevel@tonic-gate }
19867c478bd9Sstevel@tonic-gate #endif
19877c478bd9Sstevel@tonic-gate pp->p_who = P_A;
19887c478bd9Sstevel@tonic-gate pp->p_perm = mode;
19897c478bd9Sstevel@tonic-gate pp->p_op = '=';
19907c478bd9Sstevel@tonic-gate } else for (;;) {
19917c478bd9Sstevel@tonic-gate int t;
19927c478bd9Sstevel@tonic-gate int who = 0;
19937c478bd9Sstevel@tonic-gate
19947c478bd9Sstevel@tonic-gate while ((t = iswho(*amode)) != 0) {
19957c478bd9Sstevel@tonic-gate ++amode;
19967c478bd9Sstevel@tonic-gate who |= t;
19977c478bd9Sstevel@tonic-gate }
19987c478bd9Sstevel@tonic-gate if (who == 0) {
19997c478bd9Sstevel@tonic-gate mode_t currmask;
20007c478bd9Sstevel@tonic-gate (void) umask(currmask = umask((mode_t)0));
20017c478bd9Sstevel@tonic-gate
20027c478bd9Sstevel@tonic-gate /*
20037c478bd9Sstevel@tonic-gate * If no who specified, must use contents of
20047c478bd9Sstevel@tonic-gate * umask to determine which bits to flip. This
20057c478bd9Sstevel@tonic-gate * is POSIX/V7/BSD behaviour, but not SVID.
20067c478bd9Sstevel@tonic-gate */
20077c478bd9Sstevel@tonic-gate who = (~currmask)&P_A;
20087c478bd9Sstevel@tonic-gate ++nowho;
20097c478bd9Sstevel@tonic-gate } else
20107c478bd9Sstevel@tonic-gate nowho = 0;
20117c478bd9Sstevel@tonic-gate samewho:
20127c478bd9Sstevel@tonic-gate if (!isop(pp->p_op = *amode++))
20137c478bd9Sstevel@tonic-gate return (-1);
20147c478bd9Sstevel@tonic-gate pp->p_perm = 0;
20157c478bd9Sstevel@tonic-gate pp->p_special = 0;
20167c478bd9Sstevel@tonic-gate while ((t = isperm(pp, *amode)) != 0) {
20177c478bd9Sstevel@tonic-gate if (pp->p_special == 'X') {
20187c478bd9Sstevel@tonic-gate seen_X = 1;
20197c478bd9Sstevel@tonic-gate
20207c478bd9Sstevel@tonic-gate if (pp->p_perm != 0) {
20217c478bd9Sstevel@tonic-gate ushort_t op;
20227c478bd9Sstevel@tonic-gate
20237c478bd9Sstevel@tonic-gate /*
20247c478bd9Sstevel@tonic-gate * Remember the 'who' for the previous
20257c478bd9Sstevel@tonic-gate * transformation.
20267c478bd9Sstevel@tonic-gate */
20277c478bd9Sstevel@tonic-gate pp->p_who = who;
20287c478bd9Sstevel@tonic-gate pp->p_special = 0;
20297c478bd9Sstevel@tonic-gate
20307c478bd9Sstevel@tonic-gate op = pp->p_op;
20317c478bd9Sstevel@tonic-gate
20327c478bd9Sstevel@tonic-gate /* Keep 'X' separate */
20337c478bd9Sstevel@tonic-gate ++pp;
20347c478bd9Sstevel@tonic-gate pp->p_special = 'X';
20357c478bd9Sstevel@tonic-gate pp->p_op = op;
20367c478bd9Sstevel@tonic-gate }
20377c478bd9Sstevel@tonic-gate } else if (seen_X) {
20387c478bd9Sstevel@tonic-gate ushort_t op;
20397c478bd9Sstevel@tonic-gate
20407c478bd9Sstevel@tonic-gate /* Remember the 'who' for the X */
20417c478bd9Sstevel@tonic-gate pp->p_who = who;
20427c478bd9Sstevel@tonic-gate
20437c478bd9Sstevel@tonic-gate op = pp->p_op;
20447c478bd9Sstevel@tonic-gate
20457c478bd9Sstevel@tonic-gate /* Keep 'X' separate */
20467c478bd9Sstevel@tonic-gate ++pp;
20477c478bd9Sstevel@tonic-gate pp->p_perm = 0;
20487c478bd9Sstevel@tonic-gate pp->p_special = 0;
20497c478bd9Sstevel@tonic-gate pp->p_op = op;
20507c478bd9Sstevel@tonic-gate }
20517c478bd9Sstevel@tonic-gate ++amode;
20527c478bd9Sstevel@tonic-gate pp->p_perm |= t;
20537c478bd9Sstevel@tonic-gate }
20547c478bd9Sstevel@tonic-gate
20557c478bd9Sstevel@tonic-gate /*
20567c478bd9Sstevel@tonic-gate * These returned 0, but were actually parsed, so
20577c478bd9Sstevel@tonic-gate * don't look at them again.
20587c478bd9Sstevel@tonic-gate */
20597c478bd9Sstevel@tonic-gate switch (pp->p_special) {
20607c478bd9Sstevel@tonic-gate case 'u':
20617c478bd9Sstevel@tonic-gate case 'g':
20627c478bd9Sstevel@tonic-gate case 'o':
20637c478bd9Sstevel@tonic-gate ++amode;
20647c478bd9Sstevel@tonic-gate break;
20657c478bd9Sstevel@tonic-gate }
20667c478bd9Sstevel@tonic-gate pp->p_who = who;
20677c478bd9Sstevel@tonic-gate switch (*amode) {
20687c478bd9Sstevel@tonic-gate case '\0':
20697c478bd9Sstevel@tonic-gate break;
20707c478bd9Sstevel@tonic-gate
20717c478bd9Sstevel@tonic-gate case ',':
20727c478bd9Sstevel@tonic-gate ++amode;
20737c478bd9Sstevel@tonic-gate ++pp;
20747c478bd9Sstevel@tonic-gate continue;
20757c478bd9Sstevel@tonic-gate
20767c478bd9Sstevel@tonic-gate default:
20777c478bd9Sstevel@tonic-gate ++pp;
20787c478bd9Sstevel@tonic-gate goto samewho;
20797c478bd9Sstevel@tonic-gate }
20807c478bd9Sstevel@tonic-gate break;
20817c478bd9Sstevel@tonic-gate }
20827c478bd9Sstevel@tonic-gate endp = pp;
208327d3a169SToomas Soome return (0);
20847c478bd9Sstevel@tonic-gate }
20857c478bd9Sstevel@tonic-gate
20867c478bd9Sstevel@tonic-gate /*
20877c478bd9Sstevel@tonic-gate * Given a character from the mode, return the associated
20887c478bd9Sstevel@tonic-gate * value as who (user designation) mask or 0 if this isn't valid.
20897c478bd9Sstevel@tonic-gate */
20907c478bd9Sstevel@tonic-gate static int
iswho(int c)209127d3a169SToomas Soome iswho(int c)
20927c478bd9Sstevel@tonic-gate {
20937c478bd9Sstevel@tonic-gate switch (c) {
20947c478bd9Sstevel@tonic-gate case 'a':
20957c478bd9Sstevel@tonic-gate return (P_A);
20967c478bd9Sstevel@tonic-gate
20977c478bd9Sstevel@tonic-gate case 'u':
20987c478bd9Sstevel@tonic-gate return (P_U);
20997c478bd9Sstevel@tonic-gate
21007c478bd9Sstevel@tonic-gate case 'g':
21017c478bd9Sstevel@tonic-gate return (P_G);
21027c478bd9Sstevel@tonic-gate
21037c478bd9Sstevel@tonic-gate case 'o':
21047c478bd9Sstevel@tonic-gate return (P_O);
21057c478bd9Sstevel@tonic-gate
21067c478bd9Sstevel@tonic-gate default:
21077c478bd9Sstevel@tonic-gate return (0);
21087c478bd9Sstevel@tonic-gate }
21097c478bd9Sstevel@tonic-gate /* NOTREACHED */
21107c478bd9Sstevel@tonic-gate }
21117c478bd9Sstevel@tonic-gate
21127c478bd9Sstevel@tonic-gate /*
21137c478bd9Sstevel@tonic-gate * Return non-zero if this is a valid op code
21147c478bd9Sstevel@tonic-gate * in a symbolic mode.
21157c478bd9Sstevel@tonic-gate */
21167c478bd9Sstevel@tonic-gate static int
isop(int c)211727d3a169SToomas Soome isop(int c)
21187c478bd9Sstevel@tonic-gate {
21197c478bd9Sstevel@tonic-gate switch (c) {
21207c478bd9Sstevel@tonic-gate case '+':
21217c478bd9Sstevel@tonic-gate case '-':
21227c478bd9Sstevel@tonic-gate case '=':
21237c478bd9Sstevel@tonic-gate return (1);
21247c478bd9Sstevel@tonic-gate
21257c478bd9Sstevel@tonic-gate default:
21267c478bd9Sstevel@tonic-gate return (0);
21277c478bd9Sstevel@tonic-gate }
21287c478bd9Sstevel@tonic-gate /* NOTREACHED */
21297c478bd9Sstevel@tonic-gate }
21307c478bd9Sstevel@tonic-gate
21317c478bd9Sstevel@tonic-gate /*
21327c478bd9Sstevel@tonic-gate * Return the permission bits implied by this character or 0
21337c478bd9Sstevel@tonic-gate * if it isn't valid. Also returns 0 when the pseudo-permissions 'u', 'g', or
21347c478bd9Sstevel@tonic-gate * 'o' are used, and sets pp->p_special to the one used.
21357c478bd9Sstevel@tonic-gate */
21367c478bd9Sstevel@tonic-gate static int
isperm(PERMST * pp,int c)213727d3a169SToomas Soome isperm(PERMST *pp, int c)
21387c478bd9Sstevel@tonic-gate {
21397c478bd9Sstevel@tonic-gate switch (c) {
21407c478bd9Sstevel@tonic-gate case 'u':
21417c478bd9Sstevel@tonic-gate case 'g':
21427c478bd9Sstevel@tonic-gate case 'o':
21437c478bd9Sstevel@tonic-gate pp->p_special = c;
21447c478bd9Sstevel@tonic-gate return (0);
21457c478bd9Sstevel@tonic-gate
21467c478bd9Sstevel@tonic-gate case 'r':
21477c478bd9Sstevel@tonic-gate return (S_IRUSR|S_IRGRP|S_IROTH);
21487c478bd9Sstevel@tonic-gate
21497c478bd9Sstevel@tonic-gate case 'w':
21507c478bd9Sstevel@tonic-gate return (S_IWUSR|S_IWGRP|S_IWOTH);
21517c478bd9Sstevel@tonic-gate
21527c478bd9Sstevel@tonic-gate case 'x':
21537c478bd9Sstevel@tonic-gate return (S_IXUSR|S_IXGRP|S_IXOTH);
21547c478bd9Sstevel@tonic-gate
21557c478bd9Sstevel@tonic-gate #if S_ISVTX != 0
21567c478bd9Sstevel@tonic-gate case 't':
21577c478bd9Sstevel@tonic-gate return (S_ISVTX);
21587c478bd9Sstevel@tonic-gate #endif
21597c478bd9Sstevel@tonic-gate
21607c478bd9Sstevel@tonic-gate case 'X':
21617c478bd9Sstevel@tonic-gate pp->p_special = 'X';
21627c478bd9Sstevel@tonic-gate return (S_IXUSR|S_IXGRP|S_IXOTH);
21637c478bd9Sstevel@tonic-gate
21647c478bd9Sstevel@tonic-gate #if S_ISVTX != 0
21657c478bd9Sstevel@tonic-gate case 'a':
21667c478bd9Sstevel@tonic-gate return (S_ISVTX);
21677c478bd9Sstevel@tonic-gate #endif
21687c478bd9Sstevel@tonic-gate
21697c478bd9Sstevel@tonic-gate case 'h':
21707c478bd9Sstevel@tonic-gate return (S_ISUID);
21717c478bd9Sstevel@tonic-gate
21727c478bd9Sstevel@tonic-gate /*
21737c478bd9Sstevel@tonic-gate * This change makes:
21747c478bd9Sstevel@tonic-gate * chmod +s file
21757c478bd9Sstevel@tonic-gate * set the system bit on dos but means that
21767c478bd9Sstevel@tonic-gate * chmod u+s file
21777c478bd9Sstevel@tonic-gate * chmod g+s file
21787c478bd9Sstevel@tonic-gate * chmod a+s file
21797c478bd9Sstevel@tonic-gate * are all like UNIX.
21807c478bd9Sstevel@tonic-gate */
21817c478bd9Sstevel@tonic-gate case 's':
21827c478bd9Sstevel@tonic-gate return (nowho ? S_ISGID : S_ISGID|S_ISUID);
21837c478bd9Sstevel@tonic-gate
21847c478bd9Sstevel@tonic-gate default:
21857c478bd9Sstevel@tonic-gate return (0);
21867c478bd9Sstevel@tonic-gate }
21877c478bd9Sstevel@tonic-gate /* NOTREACHED */
21887c478bd9Sstevel@tonic-gate }
21897c478bd9Sstevel@tonic-gate
21907c478bd9Sstevel@tonic-gate /*
21917c478bd9Sstevel@tonic-gate * Execute the automaton that is created by readmode()
21927c478bd9Sstevel@tonic-gate * to generate the final mode that will be used. This
21937c478bd9Sstevel@tonic-gate * code is passed a starting mode that is usually the original
21947c478bd9Sstevel@tonic-gate * mode of the file being changed (or 0). Note that this mode must contain
21957c478bd9Sstevel@tonic-gate * the file-type bits as well, so that S_ISDIR will succeed on directories.
21967c478bd9Sstevel@tonic-gate */
21977c478bd9Sstevel@tonic-gate static mode_t
getmode(mode_t startmode)21987c478bd9Sstevel@tonic-gate getmode(mode_t startmode)
21997c478bd9Sstevel@tonic-gate {
22007c478bd9Sstevel@tonic-gate PERMST *pp;
22017c478bd9Sstevel@tonic-gate mode_t temp;
22027c478bd9Sstevel@tonic-gate mode_t perm;
22037c478bd9Sstevel@tonic-gate
22047c478bd9Sstevel@tonic-gate for (pp = &machine[0]; pp <= endp; ++pp) {
22057c478bd9Sstevel@tonic-gate perm = (mode_t)0;
22067c478bd9Sstevel@tonic-gate /*
22077c478bd9Sstevel@tonic-gate * For the special modes 'u', 'g' and 'o', the named portion
22087c478bd9Sstevel@tonic-gate * of the mode refers to after the previous clause has been
22097c478bd9Sstevel@tonic-gate * processed, while the 'X' mode refers to the contents of the
22107c478bd9Sstevel@tonic-gate * mode before any clauses have been processed.
22117c478bd9Sstevel@tonic-gate *
22127c478bd9Sstevel@tonic-gate * References: P1003.2/D11.2, Section 4.7.7,
22137c478bd9Sstevel@tonic-gate * lines 2568-2570, 2578-2583
22147c478bd9Sstevel@tonic-gate */
22157c478bd9Sstevel@tonic-gate switch (pp->p_special) {
22167c478bd9Sstevel@tonic-gate case 'u':
22177c478bd9Sstevel@tonic-gate temp = startmode & S_IRWXU;
22187c478bd9Sstevel@tonic-gate if (temp & (S_IRUSR|S_IRGRP|S_IROTH))
22197c478bd9Sstevel@tonic-gate perm |= ((S_IRUSR|S_IRGRP|S_IROTH) &
22207c478bd9Sstevel@tonic-gate pp->p_who);
22217c478bd9Sstevel@tonic-gate if (temp & (S_IWUSR|S_IWGRP|S_IWOTH))
22227c478bd9Sstevel@tonic-gate perm |= ((S_IWUSR|S_IWGRP|S_IWOTH) & pp->p_who);
22237c478bd9Sstevel@tonic-gate if (temp & (S_IXUSR|S_IXGRP|S_IXOTH))
22247c478bd9Sstevel@tonic-gate perm |= ((S_IXUSR|S_IXGRP|S_IXOTH) & pp->p_who);
22257c478bd9Sstevel@tonic-gate break;
22267c478bd9Sstevel@tonic-gate
22277c478bd9Sstevel@tonic-gate case 'g':
22287c478bd9Sstevel@tonic-gate temp = startmode & S_IRWXG;
22297c478bd9Sstevel@tonic-gate if (temp & (S_IRUSR|S_IRGRP|S_IROTH))
22307c478bd9Sstevel@tonic-gate perm |= ((S_IRUSR|S_IRGRP|S_IROTH) & pp->p_who);
22317c478bd9Sstevel@tonic-gate if (temp & (S_IWUSR|S_IWGRP|S_IWOTH))
22327c478bd9Sstevel@tonic-gate perm |= ((S_IWUSR|S_IWGRP|S_IWOTH) & pp->p_who);
22337c478bd9Sstevel@tonic-gate if (temp & (S_IXUSR|S_IXGRP|S_IXOTH))
22347c478bd9Sstevel@tonic-gate perm |= ((S_IXUSR|S_IXGRP|S_IXOTH) & pp->p_who);
22357c478bd9Sstevel@tonic-gate break;
22367c478bd9Sstevel@tonic-gate
22377c478bd9Sstevel@tonic-gate case 'o':
22387c478bd9Sstevel@tonic-gate temp = startmode & S_IRWXO;
22397c478bd9Sstevel@tonic-gate if (temp & (S_IRUSR|S_IRGRP|S_IROTH))
22407c478bd9Sstevel@tonic-gate perm |= ((S_IRUSR|S_IRGRP|S_IROTH) & pp->p_who);
22417c478bd9Sstevel@tonic-gate if (temp & (S_IWUSR|S_IWGRP|S_IWOTH))
22427c478bd9Sstevel@tonic-gate perm |= ((S_IWUSR|S_IWGRP|S_IWOTH) & pp->p_who);
22437c478bd9Sstevel@tonic-gate if (temp & (S_IXUSR|S_IXGRP|S_IXOTH))
22447c478bd9Sstevel@tonic-gate perm |= ((S_IXUSR|S_IXGRP|S_IXOTH) & pp->p_who);
22457c478bd9Sstevel@tonic-gate break;
22467c478bd9Sstevel@tonic-gate
22477c478bd9Sstevel@tonic-gate case 'X':
22487c478bd9Sstevel@tonic-gate perm = pp->p_perm;
22497c478bd9Sstevel@tonic-gate break;
22507c478bd9Sstevel@tonic-gate
22517c478bd9Sstevel@tonic-gate default:
22527c478bd9Sstevel@tonic-gate perm = pp->p_perm;
22537c478bd9Sstevel@tonic-gate break;
22547c478bd9Sstevel@tonic-gate }
22557c478bd9Sstevel@tonic-gate switch (pp->p_op) {
22567c478bd9Sstevel@tonic-gate case '-':
22577c478bd9Sstevel@tonic-gate startmode &= ~(perm & pp->p_who);
22587c478bd9Sstevel@tonic-gate break;
22597c478bd9Sstevel@tonic-gate
22607c478bd9Sstevel@tonic-gate case '=':
22617c478bd9Sstevel@tonic-gate startmode &= ~pp->p_who;
22627c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
22637c478bd9Sstevel@tonic-gate case '+':
22647c478bd9Sstevel@tonic-gate startmode |= (perm & pp->p_who);
22657c478bd9Sstevel@tonic-gate break;
22667c478bd9Sstevel@tonic-gate }
22677c478bd9Sstevel@tonic-gate }
22687c478bd9Sstevel@tonic-gate return (startmode);
22697c478bd9Sstevel@tonic-gate }
22707c478bd9Sstevel@tonic-gate
22717c478bd9Sstevel@tonic-gate /*
22727c478bd9Sstevel@tonic-gate * Returns the last component of a path name, unless it is
22737c478bd9Sstevel@tonic-gate * an absolute path, in which case it returns the whole path
22747c478bd9Sstevel@tonic-gate */
227527d3a169SToomas Soome static const char *
gettail(const char * fname)227627d3a169SToomas Soome gettail(const char *fname)
22777c478bd9Sstevel@tonic-gate {
227827d3a169SToomas Soome const char *base = fname;
22797c478bd9Sstevel@tonic-gate
22807c478bd9Sstevel@tonic-gate if (*fname != '/') {
22817c478bd9Sstevel@tonic-gate if ((base = strrchr(fname, '/')) != NULL)
22827c478bd9Sstevel@tonic-gate base++;
22837c478bd9Sstevel@tonic-gate else
22847c478bd9Sstevel@tonic-gate base = fname;
22857c478bd9Sstevel@tonic-gate }
22867c478bd9Sstevel@tonic-gate return (base);
22877c478bd9Sstevel@tonic-gate }
2288