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