17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5d35170d6Srm * Common Development and Distribution License (the "License"). 6d35170d6Srm * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22ef497ae3SRich Burridge * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 2303f45afcSYuri Pankov * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 2405f32410SAndy Stormont * Copyright (c) 2013 Andrew Stormont. All rights reserved. 25*f3a525d9SJohn Levon * Copyright 2020 Joyent, Inc. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 28da1a9cbeSjonb 297c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 3027d3a169SToomas Soome /* All Rights Reserved */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate /* Parts of this product may be derived from */ 347c478bd9Sstevel@tonic-gate /* Mortice Kern Systems Inc. and Berkeley 4.3 BSD systems. */ 3527d3a169SToomas Soome /* licensed from Mortice Kern Systems Inc. and */ 367c478bd9Sstevel@tonic-gate /* the University of California. */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate /* 397c478bd9Sstevel@tonic-gate * Copyright 1985, 1990 by Mortice Kern Systems Inc. All rights reserved. 407c478bd9Sstevel@tonic-gate */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <stdio.h> 437c478bd9Sstevel@tonic-gate #include <errno.h> 447c478bd9Sstevel@tonic-gate #include <pwd.h> 457c478bd9Sstevel@tonic-gate #include <grp.h> 467c478bd9Sstevel@tonic-gate #include <sys/types.h> 477c478bd9Sstevel@tonic-gate #include <sys/stat.h> 487c478bd9Sstevel@tonic-gate #include <sys/param.h> 497c478bd9Sstevel@tonic-gate #include <sys/acl.h> 507c478bd9Sstevel@tonic-gate #include <limits.h> 517c478bd9Sstevel@tonic-gate #include <unistd.h> 527c478bd9Sstevel@tonic-gate #include <stdlib.h> 537c478bd9Sstevel@tonic-gate #include <locale.h> 547c478bd9Sstevel@tonic-gate #include <string.h> 557c478bd9Sstevel@tonic-gate #include <strings.h> 567c478bd9Sstevel@tonic-gate #include <ctype.h> 577c478bd9Sstevel@tonic-gate #include <wait.h> 587c478bd9Sstevel@tonic-gate #include <fnmatch.h> 597c478bd9Sstevel@tonic-gate #include <langinfo.h> 607c478bd9Sstevel@tonic-gate #include <ftw.h> 619ab6dc39Schin #include <libgen.h> 62b34cd89aSYuri Pankov #include <err.h> 63b34cd89aSYuri Pankov #include <regex.h> 643d63ea05Sas #include "getresponse.h" 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate #define A_DAY (long)(60*60*24) /* a day full of seconds */ 67da1a9cbeSjonb #define A_MIN (long)(60) 687c478bd9Sstevel@tonic-gate #define BLKSIZ 512 697c478bd9Sstevel@tonic-gate #define round(x, s) (((x)+(s)-1)&~((s)-1)) 707c478bd9Sstevel@tonic-gate #ifndef FTW_SLN 717c478bd9Sstevel@tonic-gate #define FTW_SLN 7 727c478bd9Sstevel@tonic-gate #endif 737c478bd9Sstevel@tonic-gate #define LINEBUF_SIZE LINE_MAX /* input or output lines */ 747c478bd9Sstevel@tonic-gate #define REMOTE_FS "/etc/dfs/fstypes" 757c478bd9Sstevel@tonic-gate #define N_FSTYPES 20 76d35170d6Srm #define SHELL_MAXARGS 253 /* see doexec() for description */ 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * This is the list of operations 807c478bd9Sstevel@tonic-gate * F_USER and F_GROUP are named to avoid conflict with USER and GROUP defined 817c478bd9Sstevel@tonic-gate * in sys/acl.h 827c478bd9Sstevel@tonic-gate */ 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate enum Command 857c478bd9Sstevel@tonic-gate { 86b34cd89aSYuri Pankov PRINT, 87b34cd89aSYuri Pankov ACL, AMIN, AND, ATIME, CMIN, CPIO, CSIZE, CTIME, DEPTH, EXEC, F_GROUP, 8805f32410SAndy Stormont F_GROUPACL, F_USER, F_USERACL, FOLLOW, FSTYPE, INAME, INUM, IPATH, 8905f32410SAndy Stormont IREGEX, LINKS, LOCAL, LPAREN, LS, MAXDEPTH, MINDEPTH, MMIN, MOUNT, 9005f32410SAndy Stormont MTIME, NAME, NCPIO, NEWER, NOGRP, NOT, NOUSER, OK, OR, PATH, PERM, 91ab823b7fSPrasad Joshi PRINT0, PRUNE, REGEX, RPAREN, SIZE, TYPE, VARARGS, XATTR, DELETE 927c478bd9Sstevel@tonic-gate }; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate enum Type 957c478bd9Sstevel@tonic-gate { 967c478bd9Sstevel@tonic-gate Unary, Id, Num, Str, Exec, Cpio, Op 977c478bd9Sstevel@tonic-gate }; 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate struct Args 1007c478bd9Sstevel@tonic-gate { 1017c478bd9Sstevel@tonic-gate char name[10]; 1027c478bd9Sstevel@tonic-gate enum Command action; 1037c478bd9Sstevel@tonic-gate enum Type type; 1047c478bd9Sstevel@tonic-gate }; 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* 1077c478bd9Sstevel@tonic-gate * Except for pathnames, these are the only legal arguments 1087c478bd9Sstevel@tonic-gate */ 1097c478bd9Sstevel@tonic-gate static struct Args commands[] = 1107c478bd9Sstevel@tonic-gate { 111b34cd89aSYuri Pankov "!", NOT, Op, 112b34cd89aSYuri Pankov "(", LPAREN, Unary, 113b34cd89aSYuri Pankov ")", RPAREN, Unary, 114b34cd89aSYuri Pankov "-a", AND, Op, 115b34cd89aSYuri Pankov "-acl", ACL, Unary, 116b34cd89aSYuri Pankov "-amin", AMIN, Num, 117b34cd89aSYuri Pankov "-and", AND, Op, 118b34cd89aSYuri Pankov "-atime", ATIME, Num, 119b34cd89aSYuri Pankov "-cmin", CMIN, Num, 120b34cd89aSYuri Pankov "-cpio", CPIO, Cpio, 121b34cd89aSYuri Pankov "-ctime", CTIME, Num, 122b34cd89aSYuri Pankov "-depth", DEPTH, Unary, 123ab823b7fSPrasad Joshi "-delete", DELETE, Unary, 124b34cd89aSYuri Pankov "-exec", EXEC, Exec, 125b34cd89aSYuri Pankov "-follow", FOLLOW, Unary, 126b34cd89aSYuri Pankov "-fstype", FSTYPE, Str, 1277c478bd9Sstevel@tonic-gate "-group", F_GROUP, Num, 128b34cd89aSYuri Pankov "-groupacl", F_GROUPACL, Num, 129b34cd89aSYuri Pankov "-iname", INAME, Str, 130b34cd89aSYuri Pankov "-inum", INUM, Num, 13105f32410SAndy Stormont "-ipath", IPATH, Str, 132b34cd89aSYuri Pankov "-iregex", IREGEX, Str, 13303f45afcSYuri Pankov "-links", LINKS, Num, 13403f45afcSYuri Pankov "-local", LOCAL, Unary, 135b34cd89aSYuri Pankov "-ls", LS, Unary, 136b34cd89aSYuri Pankov "-maxdepth", MAXDEPTH, Num, 137b34cd89aSYuri Pankov "-mindepth", MINDEPTH, Num, 138b34cd89aSYuri Pankov "-mmin", MMIN, Num, 139b34cd89aSYuri Pankov "-mount", MOUNT, Unary, 140b34cd89aSYuri Pankov "-mtime", MTIME, Num, 141b34cd89aSYuri Pankov "-name", NAME, Str, 142b34cd89aSYuri Pankov "-ncpio", NCPIO, Cpio, 143b34cd89aSYuri Pankov "-newer", NEWER, Str, 144b34cd89aSYuri Pankov "-nogroup", NOGRP, Unary, 145b34cd89aSYuri Pankov "-not", NOT, Op, 146b34cd89aSYuri Pankov "-nouser", NOUSER, Unary, 147b34cd89aSYuri Pankov "-o", OR, Op, 148b34cd89aSYuri Pankov "-ok", OK, Exec, 149b34cd89aSYuri Pankov "-or", OR, Op, 15005f32410SAndy Stormont "-path", PATH, Str, 151b34cd89aSYuri Pankov "-perm", PERM, Num, 152b34cd89aSYuri Pankov "-print", PRINT, Unary, 153b34cd89aSYuri Pankov "-print0", PRINT0, Unary, 154b34cd89aSYuri Pankov "-prune", PRUNE, Unary, 155b34cd89aSYuri Pankov "-regex", REGEX, Str, 156b34cd89aSYuri Pankov "-size", SIZE, Num, 157b34cd89aSYuri Pankov "-type", TYPE, Num, 158b34cd89aSYuri Pankov "-user", F_USER, Num, 159b34cd89aSYuri Pankov "-useracl", F_USERACL, Num, 160b34cd89aSYuri Pankov "-xattr", XATTR, Unary, 161b34cd89aSYuri Pankov "-xdev", MOUNT, Unary, 16227d3a169SToomas Soome 0, 0, 0 1637c478bd9Sstevel@tonic-gate }; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate union Item 1667c478bd9Sstevel@tonic-gate { 1677c478bd9Sstevel@tonic-gate struct Node *np; 1687c478bd9Sstevel@tonic-gate struct Arglist *vp; 1697c478bd9Sstevel@tonic-gate time_t t; 1707c478bd9Sstevel@tonic-gate char *cp; 1717c478bd9Sstevel@tonic-gate char **ap; 1727c478bd9Sstevel@tonic-gate long l; 1737c478bd9Sstevel@tonic-gate int i; 1747c478bd9Sstevel@tonic-gate long long ll; 1757c478bd9Sstevel@tonic-gate }; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate struct Node 1787c478bd9Sstevel@tonic-gate { 1797c478bd9Sstevel@tonic-gate struct Node *next; 1807c478bd9Sstevel@tonic-gate enum Command action; 1817c478bd9Sstevel@tonic-gate enum Type type; 1827c478bd9Sstevel@tonic-gate union Item first; 1837c478bd9Sstevel@tonic-gate union Item second; 1847c478bd9Sstevel@tonic-gate }; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* if no -print, -exec or -ok replace "expression" with "(expression) -print" */ 1877c478bd9Sstevel@tonic-gate static struct Node PRINT_NODE = { 0, PRINT, 0, 0}; 1887c478bd9Sstevel@tonic-gate static struct Node LPAREN_NODE = { 0, LPAREN, 0, 0}; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* 1927c478bd9Sstevel@tonic-gate * Prototype variable size arglist buffer 1937c478bd9Sstevel@tonic-gate */ 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate struct Arglist 1967c478bd9Sstevel@tonic-gate { 1977c478bd9Sstevel@tonic-gate struct Arglist *next; 1987c478bd9Sstevel@tonic-gate char *end; 1997c478bd9Sstevel@tonic-gate char *nextstr; 2007c478bd9Sstevel@tonic-gate char **firstvar; 2017c478bd9Sstevel@tonic-gate char **nextvar; 2027c478bd9Sstevel@tonic-gate char *arglist[1]; 2037c478bd9Sstevel@tonic-gate }; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate 20627d3a169SToomas Soome static int compile(char **, struct Node *, int *); 20727d3a169SToomas Soome static int execute(const char *, const struct stat *, int, 20827d3a169SToomas Soome struct FTW *); 20927d3a169SToomas Soome static int doexec(const char *, char **, int *); 21027d3a169SToomas Soome static int dodelete(const char *, const struct stat *, 21127d3a169SToomas Soome struct FTW *); 21227d3a169SToomas Soome static struct Args *lookup(char *); 21327d3a169SToomas Soome static int ok(const char *, char *[]); 2146c83d09fSrobbin static void usage(void) __NORETURN; 21527d3a169SToomas Soome static struct Arglist *varargs(char **); 21627d3a169SToomas Soome static int list(const char *, const struct stat *); 21727d3a169SToomas Soome static char *getgroup(gid_t); 21827d3a169SToomas Soome static FILE *cmdopen(char *, char **, char *, FILE *); 21927d3a169SToomas Soome static int cmdclose(FILE *); 22027d3a169SToomas Soome static char *getshell(void); 22127d3a169SToomas Soome static void init_remote_fs(void); 22227d3a169SToomas Soome static char *getname(uid_t); 22327d3a169SToomas Soome static int readmode(const char *); 22427d3a169SToomas Soome static mode_t getmode(mode_t); 22527d3a169SToomas Soome static const char *gettail(const char *); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate 22868a94df1Scf static int walkflags = FTW_CHDIR|FTW_PHYS|FTW_ANYERR|FTW_NOLOOP; 2297c478bd9Sstevel@tonic-gate static struct Node *topnode; 2307c478bd9Sstevel@tonic-gate static struct Node *freenode; /* next free node we may use later */ 2317c478bd9Sstevel@tonic-gate static char *cpio[] = { "cpio", "-o", 0 }; 2327c478bd9Sstevel@tonic-gate static char *ncpio[] = { "cpio", "-oc", 0 }; 2337c478bd9Sstevel@tonic-gate static char *cpiol[] = { "cpio", "-oL", 0 }; 2347c478bd9Sstevel@tonic-gate static char *ncpiol[] = { "cpio", "-ocL", 0 }; 2357c478bd9Sstevel@tonic-gate static time_t now; 2367c478bd9Sstevel@tonic-gate static FILE *output; 2377c478bd9Sstevel@tonic-gate static char *dummyarg = (char *)-1; 2387c478bd9Sstevel@tonic-gate static int lastval; 2397c478bd9Sstevel@tonic-gate static int varsize; 2407c478bd9Sstevel@tonic-gate static struct Arglist *lastlist; 2417c478bd9Sstevel@tonic-gate static char *cmdname; 2427c478bd9Sstevel@tonic-gate static char *remote_fstypes[N_FSTYPES+1]; 2437c478bd9Sstevel@tonic-gate static int fstype_index = 0; 2447c478bd9Sstevel@tonic-gate static int action_expression = 0; /* -print, -exec, or -ok */ 2457c478bd9Sstevel@tonic-gate static int error = 0; 2467c478bd9Sstevel@tonic-gate static int paren_cnt = 0; /* keeps track of parentheses */ 247b34cd89aSYuri Pankov static int Eflag = 0; 2487c478bd9Sstevel@tonic-gate static int hflag = 0; 2497c478bd9Sstevel@tonic-gate static int lflag = 0; 250d35170d6Srm /* set when doexec()-invoked utility returns non-zero */ 251d35170d6Srm static int exec_exitcode = 0; 252b34cd89aSYuri Pankov static regex_t *preg = NULL; 253b34cd89aSYuri Pankov static int npreg = 0; 254b34cd89aSYuri Pankov static int mindepth = -1, maxdepth = -1; 2557c478bd9Sstevel@tonic-gate extern char **environ; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate int 2587c478bd9Sstevel@tonic-gate main(int argc, char **argv) 2597c478bd9Sstevel@tonic-gate { 2607c478bd9Sstevel@tonic-gate char *cp; 2617c478bd9Sstevel@tonic-gate int c; 2627c478bd9Sstevel@tonic-gate int paths; 2637c478bd9Sstevel@tonic-gate char *cwdpath; 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2667c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 2677c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 2687c478bd9Sstevel@tonic-gate #endif 2697c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate cmdname = argv[0]; 2727c478bd9Sstevel@tonic-gate if (time(&now) == (time_t)(-1)) { 2737c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: time() %s\n"), 2743d63ea05Sas cmdname, strerror(errno)); 2757c478bd9Sstevel@tonic-gate exit(1); 2767c478bd9Sstevel@tonic-gate } 277b34cd89aSYuri Pankov while ((c = getopt(argc, argv, "EHL")) != -1) { 2787c478bd9Sstevel@tonic-gate switch (c) { 279b34cd89aSYuri Pankov case 'E': 280b34cd89aSYuri Pankov Eflag = 1; 281b34cd89aSYuri Pankov break; 2827c478bd9Sstevel@tonic-gate case 'H': 2837c478bd9Sstevel@tonic-gate hflag = 1; 2847c478bd9Sstevel@tonic-gate lflag = 0; 2857c478bd9Sstevel@tonic-gate break; 2867c478bd9Sstevel@tonic-gate case 'L': 2877c478bd9Sstevel@tonic-gate hflag = 0; 2887c478bd9Sstevel@tonic-gate lflag = 1; 2897c478bd9Sstevel@tonic-gate break; 2907c478bd9Sstevel@tonic-gate case '?': 2917c478bd9Sstevel@tonic-gate usage(); 2927c478bd9Sstevel@tonic-gate break; 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate argc -= optind; 2977c478bd9Sstevel@tonic-gate argv += optind; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate if (argc < 1) { 3007c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3017c478bd9Sstevel@tonic-gate gettext("%s: insufficient number of arguments\n"), cmdname); 3027c478bd9Sstevel@tonic-gate usage(); 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate for (paths = 0; (cp = argv[paths]) != 0; ++paths) { 3067c478bd9Sstevel@tonic-gate if (*cp == '-') 3077c478bd9Sstevel@tonic-gate break; 3087c478bd9Sstevel@tonic-gate else if ((*cp == '!' || *cp == '(') && *(cp+1) == 0) 3097c478bd9Sstevel@tonic-gate break; 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate if (paths == 0) /* no path-list */ 3137c478bd9Sstevel@tonic-gate usage(); 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate output = stdout; 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate /* lflag is the same as -follow */ 3187c478bd9Sstevel@tonic-gate if (lflag) 3197c478bd9Sstevel@tonic-gate walkflags &= ~FTW_PHYS; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate /* allocate enough space for the compiler */ 3227c478bd9Sstevel@tonic-gate topnode = malloc((argc + 1) * sizeof (struct Node)); 3237c478bd9Sstevel@tonic-gate (void) memset(topnode, 0, (argc + 1) * sizeof (struct Node)); 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate if (compile(argv + paths, topnode, &action_expression) == 0) { 3267c478bd9Sstevel@tonic-gate /* no expression, default to -print */ 3277c478bd9Sstevel@tonic-gate (void) memcpy(topnode, &PRINT_NODE, sizeof (struct Node)); 3287c478bd9Sstevel@tonic-gate } else if (!action_expression) { 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * if no action expression, insert an LPAREN node above topnode, 3317c478bd9Sstevel@tonic-gate * with a PRINT node as its next node 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate struct Node *savenode; 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate if (freenode == NULL) { 3367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: can't append -print" 3373d63ea05Sas " implicitly; try explicit -print option\n"), 3383d63ea05Sas cmdname); 3397c478bd9Sstevel@tonic-gate exit(1); 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate savenode = topnode; 3427c478bd9Sstevel@tonic-gate topnode = freenode++; 3437c478bd9Sstevel@tonic-gate (void) memcpy(topnode, &LPAREN_NODE, sizeof (struct Node)); 3447c478bd9Sstevel@tonic-gate topnode->next = freenode; 3457c478bd9Sstevel@tonic-gate topnode->first.np = savenode; 3467c478bd9Sstevel@tonic-gate (void) memcpy(topnode->next, &PRINT_NODE, sizeof (struct Node)); 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate while (paths--) { 3507c478bd9Sstevel@tonic-gate char *curpath; 3517c478bd9Sstevel@tonic-gate struct stat sb; 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate curpath = *(argv++); 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* 3567c478bd9Sstevel@tonic-gate * If -H is specified, it means we walk the first 3577c478bd9Sstevel@tonic-gate * level (pathname on command line) logically, following 3587c478bd9Sstevel@tonic-gate * symlinks, but lower levels are walked physically. 3597c478bd9Sstevel@tonic-gate * We use our own secret interface to nftw() to change 3607c478bd9Sstevel@tonic-gate * the from stat to lstat after the top level is walked. 3617c478bd9Sstevel@tonic-gate */ 3627c478bd9Sstevel@tonic-gate if (hflag) { 3637c478bd9Sstevel@tonic-gate if (stat(curpath, &sb) < 0 && errno == ENOENT) 3647c478bd9Sstevel@tonic-gate walkflags &= ~FTW_HOPTION; 3657c478bd9Sstevel@tonic-gate else 3667c478bd9Sstevel@tonic-gate walkflags |= FTW_HOPTION; 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate /* 3707c478bd9Sstevel@tonic-gate * We need this check as nftw needs a CWD and we have no 3717c478bd9Sstevel@tonic-gate * way of returning back from that code with a meaningful 3727c478bd9Sstevel@tonic-gate * error related to this 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate if ((cwdpath = getcwd(NULL, PATH_MAX)) == NULL) { 3754b808d43SRich Burridge if ((errno == EACCES) && (walkflags & FTW_CHDIR)) { 3764b808d43SRich Burridge /* 3774b808d43SRich Burridge * A directory above cwd is inaccessible, 3784b808d43SRich Burridge * so don't do chdir(2)s. Slower, but at least 3794b808d43SRich Burridge * it works. 3804b808d43SRich Burridge */ 3814b808d43SRich Burridge walkflags &= ~FTW_CHDIR; 3824b808d43SRich Burridge free(cwdpath); 3834b808d43SRich Burridge } else { 3844b808d43SRich Burridge (void) fprintf(stderr, 3854b808d43SRich Burridge gettext("%s : cannot get the current " 3864b808d43SRich Burridge "working directory\n"), cmdname); 3874b808d43SRich Burridge exit(1); 3884b808d43SRich Burridge } 3897c478bd9Sstevel@tonic-gate } else 3907c478bd9Sstevel@tonic-gate free(cwdpath); 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate if (nftw(curpath, execute, 1000, walkflags)) { 3947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 3957c478bd9Sstevel@tonic-gate gettext("%s: cannot open %s: %s\n"), 3967c478bd9Sstevel@tonic-gate cmdname, curpath, strerror(errno)); 3977c478bd9Sstevel@tonic-gate error = 1; 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate /* execute any remaining variable length lists */ 4037c478bd9Sstevel@tonic-gate while (lastlist) { 4047c478bd9Sstevel@tonic-gate if (lastlist->end != lastlist->nextstr) { 4057c478bd9Sstevel@tonic-gate *lastlist->nextvar = 0; 40627d3a169SToomas Soome (void) doexec(NULL, lastlist->arglist, 407d35170d6Srm &exec_exitcode); 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate lastlist = lastlist->next; 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate if (output != stdout) 4127c478bd9Sstevel@tonic-gate return (cmdclose(output)); 413d35170d6Srm return ((exec_exitcode != 0) ? exec_exitcode : error); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * compile the arguments 4187c478bd9Sstevel@tonic-gate */ 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate static int 42127d3a169SToomas Soome compile(char **argv, struct Node *np, int *actionp) 4227c478bd9Sstevel@tonic-gate { 4237c478bd9Sstevel@tonic-gate char *b; 4247c478bd9Sstevel@tonic-gate char **av; 4257c478bd9Sstevel@tonic-gate struct Node *oldnp = topnode; 4267c478bd9Sstevel@tonic-gate struct Args *argp; 4277c478bd9Sstevel@tonic-gate char **com; 4287c478bd9Sstevel@tonic-gate int i; 4297c478bd9Sstevel@tonic-gate enum Command wasop = PRINT; 4307c478bd9Sstevel@tonic-gate 4313d63ea05Sas if (init_yes() < 0) { 4323d63ea05Sas (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES), 4333d63ea05Sas strerror(errno)); 4343d63ea05Sas exit(1); 4353d63ea05Sas } 4363d63ea05Sas 4377c478bd9Sstevel@tonic-gate for (av = argv; *av && (argp = lookup(*av)); av++) { 4387c478bd9Sstevel@tonic-gate np->next = 0; 4397c478bd9Sstevel@tonic-gate np->action = argp->action; 4407c478bd9Sstevel@tonic-gate np->type = argp->type; 4417c478bd9Sstevel@tonic-gate np->second.i = 0; 4427c478bd9Sstevel@tonic-gate if (argp->type == Op) { 4437c478bd9Sstevel@tonic-gate if (wasop == NOT || (wasop && np->action != NOT)) { 4447c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 44527d3a169SToomas Soome gettext("%s: operand follows operand\n"), 44627d3a169SToomas Soome cmdname); 4477c478bd9Sstevel@tonic-gate exit(1); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate if (np->action != NOT && oldnp == 0) 4507c478bd9Sstevel@tonic-gate goto err; 4517c478bd9Sstevel@tonic-gate wasop = argp->action; 4527c478bd9Sstevel@tonic-gate } else { 4537c478bd9Sstevel@tonic-gate wasop = PRINT; 4547c478bd9Sstevel@tonic-gate if (argp->type != Unary) { 4557c478bd9Sstevel@tonic-gate if (!(b = *++av)) { 45627d3a169SToomas Soome (void) fprintf(stderr, gettext( 45727d3a169SToomas Soome "%s: incomplete statement\n"), 45827d3a169SToomas Soome cmdname); 4597c478bd9Sstevel@tonic-gate exit(1); 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate if (argp->type == Num) { 462b34cd89aSYuri Pankov if (((argp->action == MAXDEPTH) || 463b34cd89aSYuri Pankov (argp->action == MINDEPTH)) && 464b34cd89aSYuri Pankov ((int)strtol(b, (char **)NULL, 465b34cd89aSYuri Pankov 10) < 0)) 46627d3a169SToomas Soome errx(1, gettext( 46727d3a169SToomas Soome "%s: value must be " 46827d3a169SToomas Soome "positive"), 469b34cd89aSYuri Pankov (argp->action == MAXDEPTH) ? 470b34cd89aSYuri Pankov "maxdepth" : "mindepth"); 4717c478bd9Sstevel@tonic-gate if ((argp->action != PERM) || 4727c478bd9Sstevel@tonic-gate (*b != '+')) { 4737c478bd9Sstevel@tonic-gate if (*b == '+' || *b == '-') { 4747c478bd9Sstevel@tonic-gate np->second.i = *b; 4757c478bd9Sstevel@tonic-gate b++; 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate switch (argp->action) { 4827c478bd9Sstevel@tonic-gate case AND: 4837c478bd9Sstevel@tonic-gate break; 4847c478bd9Sstevel@tonic-gate case NOT: 4857c478bd9Sstevel@tonic-gate break; 4867c478bd9Sstevel@tonic-gate case OR: 4877c478bd9Sstevel@tonic-gate np->first.np = topnode; 4887c478bd9Sstevel@tonic-gate topnode = np; 4897c478bd9Sstevel@tonic-gate oldnp->next = 0; 4907c478bd9Sstevel@tonic-gate break; 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate case LPAREN: { 4937c478bd9Sstevel@tonic-gate struct Node *save = topnode; 4947c478bd9Sstevel@tonic-gate topnode = np+1; 4957c478bd9Sstevel@tonic-gate paren_cnt++; 4967c478bd9Sstevel@tonic-gate i = compile(++av, topnode, actionp); 4977c478bd9Sstevel@tonic-gate np->first.np = topnode; 4987c478bd9Sstevel@tonic-gate topnode = save; 4997c478bd9Sstevel@tonic-gate av += i; 5007c478bd9Sstevel@tonic-gate oldnp = np; 5017c478bd9Sstevel@tonic-gate np += i + 1; 5027c478bd9Sstevel@tonic-gate oldnp->next = np; 5037c478bd9Sstevel@tonic-gate continue; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate case RPAREN: 5077c478bd9Sstevel@tonic-gate if (paren_cnt <= 0) { 5087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 5097c478bd9Sstevel@tonic-gate gettext("%s: unmatched ')'\n"), 5107c478bd9Sstevel@tonic-gate cmdname); 5117c478bd9Sstevel@tonic-gate exit(1); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate paren_cnt--; 5147c478bd9Sstevel@tonic-gate if (oldnp == 0) 5157c478bd9Sstevel@tonic-gate goto err; 5167c478bd9Sstevel@tonic-gate if (oldnp->type == Op) { 5177c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 5187c478bd9Sstevel@tonic-gate gettext("%s: cannot immediately" 5197c478bd9Sstevel@tonic-gate " follow an operand with ')'\n"), 5207c478bd9Sstevel@tonic-gate cmdname); 5217c478bd9Sstevel@tonic-gate exit(1); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate oldnp->next = 0; 5247c478bd9Sstevel@tonic-gate return (av-argv); 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate case FOLLOW: 5277c478bd9Sstevel@tonic-gate walkflags &= ~FTW_PHYS; 5287c478bd9Sstevel@tonic-gate break; 5297c478bd9Sstevel@tonic-gate case MOUNT: 5307c478bd9Sstevel@tonic-gate walkflags |= FTW_MOUNT; 5317c478bd9Sstevel@tonic-gate break; 5327c478bd9Sstevel@tonic-gate case DEPTH: 5337c478bd9Sstevel@tonic-gate walkflags |= FTW_DEPTH; 5347c478bd9Sstevel@tonic-gate break; 535ab823b7fSPrasad Joshi case DELETE: 536ab823b7fSPrasad Joshi walkflags |= (FTW_DEPTH | FTW_PHYS); 537ab823b7fSPrasad Joshi walkflags &= ~FTW_CHDIR; 538ab823b7fSPrasad Joshi (*actionp)++; 539ab823b7fSPrasad Joshi break; 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate case LOCAL: 5427c478bd9Sstevel@tonic-gate np->first.l = 0L; 5437c478bd9Sstevel@tonic-gate np->first.ll = 0LL; 5447c478bd9Sstevel@tonic-gate np->second.i = '+'; 5457c478bd9Sstevel@tonic-gate /* 5467c478bd9Sstevel@tonic-gate * Make it compatible to df -l for 5477c478bd9Sstevel@tonic-gate * future enhancement. So, anything 5487c478bd9Sstevel@tonic-gate * that is not remote, then it is 5497c478bd9Sstevel@tonic-gate * local. 5507c478bd9Sstevel@tonic-gate */ 5517c478bd9Sstevel@tonic-gate init_remote_fs(); 5527c478bd9Sstevel@tonic-gate break; 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate case SIZE: 5557c478bd9Sstevel@tonic-gate if (b[strlen(b)-1] == 'c') 5567c478bd9Sstevel@tonic-gate np->action = CSIZE; 5577c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 5587c478bd9Sstevel@tonic-gate case INUM: 5597c478bd9Sstevel@tonic-gate np->first.ll = atoll(b); 5607c478bd9Sstevel@tonic-gate break; 5617c478bd9Sstevel@tonic-gate 562da1a9cbeSjonb case CMIN: 5637c478bd9Sstevel@tonic-gate case CTIME: 564da1a9cbeSjonb case MMIN: 5657c478bd9Sstevel@tonic-gate case MTIME: 566da1a9cbeSjonb case AMIN: 5677c478bd9Sstevel@tonic-gate case ATIME: 5687c478bd9Sstevel@tonic-gate case LINKS: 5697c478bd9Sstevel@tonic-gate np->first.l = atol(b); 5707c478bd9Sstevel@tonic-gate break; 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate case F_USER: 573b34cd89aSYuri Pankov case F_GROUP: 574b34cd89aSYuri Pankov case F_USERACL: 575b34cd89aSYuri Pankov case F_GROUPACL: { 5767c478bd9Sstevel@tonic-gate struct passwd *pw; 5777c478bd9Sstevel@tonic-gate struct group *gr; 578ef497ae3SRich Burridge long value; 579ef497ae3SRich Burridge char *q; 580ef497ae3SRich Burridge 581ef497ae3SRich Burridge value = -1; 582b34cd89aSYuri Pankov if (argp->action == F_USER || 583b34cd89aSYuri Pankov argp->action == F_USERACL) { 5847c478bd9Sstevel@tonic-gate if ((pw = getpwnam(b)) != 0) 585ef497ae3SRich Burridge value = (long)pw->pw_uid; 5867c478bd9Sstevel@tonic-gate } else { 5877c478bd9Sstevel@tonic-gate if ((gr = getgrnam(b)) != 0) 588ef497ae3SRich Burridge value = (long)gr->gr_gid; 5897c478bd9Sstevel@tonic-gate } 590ef497ae3SRich Burridge if (value == -1) { 591ef497ae3SRich Burridge errno = 0; 592ef497ae3SRich Burridge value = strtol(b, &q, 10); 593ef497ae3SRich Burridge if (errno != 0 || q == b || *q != '\0') { 5947c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 5957c478bd9Sstevel@tonic-gate "%s: cannot find %s name\n"), 59627d3a169SToomas Soome cmdname, *av); 5977c478bd9Sstevel@tonic-gate exit(1); 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate } 600ef497ae3SRich Burridge np->first.l = value; 6017c478bd9Sstevel@tonic-gate break; 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate case EXEC: 6057c478bd9Sstevel@tonic-gate case OK: 6067c478bd9Sstevel@tonic-gate walkflags &= ~FTW_CHDIR; 6077c478bd9Sstevel@tonic-gate np->first.ap = av; 6087c478bd9Sstevel@tonic-gate (*actionp)++; 6097c478bd9Sstevel@tonic-gate for (;;) { 6107c478bd9Sstevel@tonic-gate if ((b = *av) == 0) { 61127d3a169SToomas Soome (void) fprintf(stderr, gettext( 61227d3a169SToomas Soome "%s: incomplete statement\n"), 61327d3a169SToomas Soome cmdname); 6147c478bd9Sstevel@tonic-gate exit(1); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate if (strcmp(b, ";") == 0) { 6177c478bd9Sstevel@tonic-gate *av = 0; 6187c478bd9Sstevel@tonic-gate break; 6197c478bd9Sstevel@tonic-gate } else if (strcmp(b, "{}") == 0) 6207c478bd9Sstevel@tonic-gate *av = dummyarg; 6217c478bd9Sstevel@tonic-gate else if (strcmp(b, "+") == 0 && 62227d3a169SToomas Soome av[-1] == dummyarg && np->action == EXEC) { 6237c478bd9Sstevel@tonic-gate av[-1] = 0; 6247c478bd9Sstevel@tonic-gate np->first.vp = varargs(np->first.ap); 6257c478bd9Sstevel@tonic-gate np->action = VARARGS; 6267c478bd9Sstevel@tonic-gate break; 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate av++; 6297c478bd9Sstevel@tonic-gate } 6307c478bd9Sstevel@tonic-gate break; 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate case NAME: 633b34cd89aSYuri Pankov case INAME: 63405f32410SAndy Stormont case PATH: 63505f32410SAndy Stormont case IPATH: 6367c478bd9Sstevel@tonic-gate np->first.cp = b; 6377c478bd9Sstevel@tonic-gate break; 638b34cd89aSYuri Pankov case REGEX: 639b34cd89aSYuri Pankov case IREGEX: { 640b34cd89aSYuri Pankov int error; 641b34cd89aSYuri Pankov size_t errlen; 642b34cd89aSYuri Pankov char *errmsg; 643b34cd89aSYuri Pankov 644b34cd89aSYuri Pankov if ((preg = realloc(preg, (npreg + 1) * 645b34cd89aSYuri Pankov sizeof (regex_t))) == NULL) 646b34cd89aSYuri Pankov err(1, "realloc"); 647b34cd89aSYuri Pankov if ((error = regcomp(&preg[npreg], b, 648b34cd89aSYuri Pankov ((np->action == IREGEX) ? REG_ICASE : 0) | 649b34cd89aSYuri Pankov ((Eflag) ? REG_EXTENDED : 0))) != 0) { 650b34cd89aSYuri Pankov errlen = regerror(error, &preg[npreg], NULL, 0); 651b34cd89aSYuri Pankov if ((errmsg = malloc(errlen)) == NULL) 652b34cd89aSYuri Pankov err(1, "malloc"); 653b34cd89aSYuri Pankov (void) regerror(error, &preg[npreg], errmsg, 654b34cd89aSYuri Pankov errlen); 655b34cd89aSYuri Pankov errx(1, gettext("RE error: %s"), errmsg); 656b34cd89aSYuri Pankov } 657b34cd89aSYuri Pankov npreg++; 658b34cd89aSYuri Pankov break; 659b34cd89aSYuri Pankov } 6607c478bd9Sstevel@tonic-gate case PERM: 6617c478bd9Sstevel@tonic-gate if (*b == '-') 6627c478bd9Sstevel@tonic-gate ++b; 6637c478bd9Sstevel@tonic-gate 66427d3a169SToomas Soome if (readmode(b) != 0) { 6657c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 6667c478bd9Sstevel@tonic-gate "find: -perm: Bad permission string\n")); 6677c478bd9Sstevel@tonic-gate usage(); 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate np->first.l = (long)getmode((mode_t)0); 6707c478bd9Sstevel@tonic-gate break; 6717c478bd9Sstevel@tonic-gate case TYPE: 6727c478bd9Sstevel@tonic-gate i = *b; 6737c478bd9Sstevel@tonic-gate np->first.l = 6747c478bd9Sstevel@tonic-gate i == 'd' ? S_IFDIR : 6757c478bd9Sstevel@tonic-gate i == 'b' ? S_IFBLK : 6767c478bd9Sstevel@tonic-gate i == 'c' ? S_IFCHR : 6777c478bd9Sstevel@tonic-gate #ifdef S_IFIFO 6787c478bd9Sstevel@tonic-gate i == 'p' ? S_IFIFO : 6797c478bd9Sstevel@tonic-gate #endif 6807c478bd9Sstevel@tonic-gate i == 'f' ? S_IFREG : 6817c478bd9Sstevel@tonic-gate #ifdef S_IFLNK 6827c478bd9Sstevel@tonic-gate i == 'l' ? S_IFLNK : 6837c478bd9Sstevel@tonic-gate #endif 6847c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK 6857c478bd9Sstevel@tonic-gate i == 's' ? S_IFSOCK : 6867c478bd9Sstevel@tonic-gate #endif 6877c478bd9Sstevel@tonic-gate #ifdef S_IFDOOR 6887c478bd9Sstevel@tonic-gate i == 'D' ? S_IFDOOR : 6897c478bd9Sstevel@tonic-gate #endif 6907c478bd9Sstevel@tonic-gate 0; 6917c478bd9Sstevel@tonic-gate break; 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate case CPIO: 6947c478bd9Sstevel@tonic-gate if (walkflags & FTW_PHYS) 6957c478bd9Sstevel@tonic-gate com = cpio; 6967c478bd9Sstevel@tonic-gate else 6977c478bd9Sstevel@tonic-gate com = cpiol; 6987c478bd9Sstevel@tonic-gate goto common; 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate case NCPIO: { 7017c478bd9Sstevel@tonic-gate FILE *fd; 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate if (walkflags & FTW_PHYS) 7047c478bd9Sstevel@tonic-gate com = ncpio; 7057c478bd9Sstevel@tonic-gate else 7067c478bd9Sstevel@tonic-gate com = ncpiol; 7077c478bd9Sstevel@tonic-gate common: 7087c478bd9Sstevel@tonic-gate /* set up cpio */ 7097c478bd9Sstevel@tonic-gate if ((fd = fopen(b, "w")) == NULL) { 7107c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 71127d3a169SToomas Soome gettext("%s: cannot create %s\n"), 71227d3a169SToomas Soome cmdname, b); 7137c478bd9Sstevel@tonic-gate exit(1); 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate np->first.l = (long)cmdopen("cpio", com, "w", fd); 7177c478bd9Sstevel@tonic-gate (void) fclose(fd); 7187c478bd9Sstevel@tonic-gate walkflags |= FTW_DEPTH; 7197c478bd9Sstevel@tonic-gate np->action = CPIO; 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 7227c478bd9Sstevel@tonic-gate case PRINT: 723b34cd89aSYuri Pankov case PRINT0: 7247c478bd9Sstevel@tonic-gate (*actionp)++; 7257c478bd9Sstevel@tonic-gate break; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate case NEWER: { 7287c478bd9Sstevel@tonic-gate struct stat statb; 7297c478bd9Sstevel@tonic-gate if (stat(b, &statb) < 0) { 7307c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 73127d3a169SToomas Soome gettext("%s: cannot access %s\n"), 73227d3a169SToomas Soome cmdname, b); 7337c478bd9Sstevel@tonic-gate exit(1); 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate np->first.l = statb.st_mtime; 7367c478bd9Sstevel@tonic-gate np->second.i = '+'; 7377c478bd9Sstevel@tonic-gate break; 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate case PRUNE: 7417c478bd9Sstevel@tonic-gate case NOUSER: 7427c478bd9Sstevel@tonic-gate case NOGRP: 7437c478bd9Sstevel@tonic-gate break; 7447c478bd9Sstevel@tonic-gate case FSTYPE: 7457c478bd9Sstevel@tonic-gate np->first.cp = b; 7467c478bd9Sstevel@tonic-gate break; 7477c478bd9Sstevel@tonic-gate case LS: 7487c478bd9Sstevel@tonic-gate (*actionp)++; 7497c478bd9Sstevel@tonic-gate break; 7507c478bd9Sstevel@tonic-gate case XATTR: 7517c478bd9Sstevel@tonic-gate break; 7527c478bd9Sstevel@tonic-gate case ACL: 7537c478bd9Sstevel@tonic-gate break; 754b34cd89aSYuri Pankov case MAXDEPTH: 75527d3a169SToomas Soome maxdepth = (int)strtol(b, NULL, 10); 756b34cd89aSYuri Pankov break; 757b34cd89aSYuri Pankov case MINDEPTH: 75827d3a169SToomas Soome mindepth = (int)strtol(b, NULL, 10); 759b34cd89aSYuri Pankov break; 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate oldnp = np++; 7637c478bd9Sstevel@tonic-gate oldnp->next = np; 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate if ((*av) || (wasop)) 7677c478bd9Sstevel@tonic-gate goto err; 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate if (paren_cnt != 0) { 77027d3a169SToomas Soome (void) fprintf(stderr, gettext("%s: unmatched '('\n"), cmdname); 7717c478bd9Sstevel@tonic-gate exit(1); 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate /* just before returning, save next free node from the list */ 7757c478bd9Sstevel@tonic-gate freenode = oldnp->next; 7767c478bd9Sstevel@tonic-gate oldnp->next = 0; 7777c478bd9Sstevel@tonic-gate return (av-argv); 7787c478bd9Sstevel@tonic-gate err: 7797c478bd9Sstevel@tonic-gate if (*av) 7807c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 7817c478bd9Sstevel@tonic-gate gettext("%s: bad option %s\n"), cmdname, *av); 7827c478bd9Sstevel@tonic-gate else 7837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: bad option\n"), cmdname); 7847c478bd9Sstevel@tonic-gate usage(); 7857c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate /* 7897c478bd9Sstevel@tonic-gate * print out a usage message 7907c478bd9Sstevel@tonic-gate */ 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate static void 7936c83d09fSrobbin usage(void) 7947c478bd9Sstevel@tonic-gate { 7957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 796b34cd89aSYuri Pankov gettext("%s: [-E] [-H | -L] path-list predicate-list\n"), cmdname); 7977c478bd9Sstevel@tonic-gate exit(1); 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate /* 8017c478bd9Sstevel@tonic-gate * This is the function that gets executed at each node 8027c478bd9Sstevel@tonic-gate */ 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate static int 80527d3a169SToomas Soome execute(const char *name, const struct stat *statb, int type, struct FTW *state) 8067c478bd9Sstevel@tonic-gate { 8077c478bd9Sstevel@tonic-gate struct Node *np = topnode; 8087c478bd9Sstevel@tonic-gate int val; 8097c478bd9Sstevel@tonic-gate time_t t; 8107c478bd9Sstevel@tonic-gate long l; 8117c478bd9Sstevel@tonic-gate long long ll; 8127c478bd9Sstevel@tonic-gate int not = 1; 81327d3a169SToomas Soome const char *filename; 814b34cd89aSYuri Pankov int cnpreg = 0; 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate if (type == FTW_NS) { 8177c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: stat() error %s: %s\n"), 81827d3a169SToomas Soome cmdname, name, strerror(errno)); 8197c478bd9Sstevel@tonic-gate error = 1; 8207c478bd9Sstevel@tonic-gate return (0); 8217c478bd9Sstevel@tonic-gate } else if (type == FTW_DNR) { 8227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: cannot read dir %s: %s\n"), 82327d3a169SToomas Soome cmdname, name, strerror(errno)); 8247c478bd9Sstevel@tonic-gate error = 1; 8250729abfeSRich Burridge } else if (type == FTW_SLN && lflag == 1) { 8267c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 82727d3a169SToomas Soome gettext("%s: cannot follow symbolic link %s: %s\n"), 82827d3a169SToomas Soome cmdname, name, strerror(errno)); 8297c478bd9Sstevel@tonic-gate error = 1; 83068a94df1Scf } else if (type == FTW_DL) { 83168a94df1Scf (void) fprintf(stderr, gettext("%s: cycle detected for %s\n"), 83227d3a169SToomas Soome cmdname, name); 83368a94df1Scf error = 1; 83468a94df1Scf return (0); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate 837b34cd89aSYuri Pankov if ((maxdepth != -1 && state->level > maxdepth) || 838b34cd89aSYuri Pankov (mindepth != -1 && state->level < mindepth)) 839b34cd89aSYuri Pankov return (0); 840b34cd89aSYuri Pankov 8417c478bd9Sstevel@tonic-gate while (np) { 8427c478bd9Sstevel@tonic-gate switch (np->action) { 8437c478bd9Sstevel@tonic-gate case NOT: 8447c478bd9Sstevel@tonic-gate not = !not; 8457c478bd9Sstevel@tonic-gate np = np->next; 8467c478bd9Sstevel@tonic-gate continue; 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate case AND: 8497c478bd9Sstevel@tonic-gate np = np->next; 8507c478bd9Sstevel@tonic-gate continue; 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate case OR: 8537c478bd9Sstevel@tonic-gate if (np->first.np == np) { 8547c478bd9Sstevel@tonic-gate /* 8557c478bd9Sstevel@tonic-gate * handle naked OR (no term on left hand side) 8567c478bd9Sstevel@tonic-gate */ 8577c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8587c478bd9Sstevel@tonic-gate gettext("%s: invalid -o construction\n"), 8597c478bd9Sstevel@tonic-gate cmdname); 8607c478bd9Sstevel@tonic-gate exit(2); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 8637c478bd9Sstevel@tonic-gate case LPAREN: { 8647c478bd9Sstevel@tonic-gate struct Node *save = topnode; 8657c478bd9Sstevel@tonic-gate topnode = np->first.np; 8667c478bd9Sstevel@tonic-gate (void) execute(name, statb, type, state); 8677c478bd9Sstevel@tonic-gate val = lastval; 8687c478bd9Sstevel@tonic-gate topnode = save; 8697c478bd9Sstevel@tonic-gate if (np->action == OR) { 8707c478bd9Sstevel@tonic-gate if (val) 8717c478bd9Sstevel@tonic-gate return (0); 8727c478bd9Sstevel@tonic-gate val = 1; 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate break; 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate case LOCAL: { 8787c478bd9Sstevel@tonic-gate int nremfs; 8797c478bd9Sstevel@tonic-gate val = 1; 8807c478bd9Sstevel@tonic-gate /* 8817c478bd9Sstevel@tonic-gate * If file system type matches the remote 8827c478bd9Sstevel@tonic-gate * file system type, then it is not local. 8837c478bd9Sstevel@tonic-gate */ 8847c478bd9Sstevel@tonic-gate for (nremfs = 0; nremfs < fstype_index; nremfs++) { 8857c478bd9Sstevel@tonic-gate if (strcmp(remote_fstypes[nremfs], 88627d3a169SToomas Soome statb->st_fstype) == 0) { 8877c478bd9Sstevel@tonic-gate val = 0; 8887c478bd9Sstevel@tonic-gate break; 8897c478bd9Sstevel@tonic-gate } 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate break; 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate case TYPE: 8957c478bd9Sstevel@tonic-gate l = (long)statb->st_mode&S_IFMT; 8967c478bd9Sstevel@tonic-gate goto num; 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate case PERM: 8997c478bd9Sstevel@tonic-gate l = (long)statb->st_mode&07777; 9007c478bd9Sstevel@tonic-gate if (np->second.i == '-') 9017c478bd9Sstevel@tonic-gate val = ((l&np->first.l) == np->first.l); 9027c478bd9Sstevel@tonic-gate else 9037c478bd9Sstevel@tonic-gate val = (l == np->first.l); 9047c478bd9Sstevel@tonic-gate break; 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate case INUM: 9077c478bd9Sstevel@tonic-gate ll = (long long)statb->st_ino; 9087c478bd9Sstevel@tonic-gate goto llnum; 9097c478bd9Sstevel@tonic-gate case NEWER: 9107c478bd9Sstevel@tonic-gate l = statb->st_mtime; 9117c478bd9Sstevel@tonic-gate goto num; 9127c478bd9Sstevel@tonic-gate case ATIME: 9137c478bd9Sstevel@tonic-gate t = statb->st_atime; 9147c478bd9Sstevel@tonic-gate goto days; 9157c478bd9Sstevel@tonic-gate case CTIME: 9167c478bd9Sstevel@tonic-gate t = statb->st_ctime; 9177c478bd9Sstevel@tonic-gate goto days; 9187c478bd9Sstevel@tonic-gate case MTIME: 9197c478bd9Sstevel@tonic-gate t = statb->st_mtime; 9207c478bd9Sstevel@tonic-gate days: 9217c478bd9Sstevel@tonic-gate l = (now-t)/A_DAY; 9227c478bd9Sstevel@tonic-gate goto num; 923da1a9cbeSjonb case MMIN: 924da1a9cbeSjonb t = statb->st_mtime; 925da1a9cbeSjonb goto mins; 926da1a9cbeSjonb case AMIN: 927da1a9cbeSjonb t = statb->st_atime; 928da1a9cbeSjonb goto mins; 929da1a9cbeSjonb case CMIN: 930da1a9cbeSjonb t = statb->st_ctime; 931da1a9cbeSjonb goto mins; 932da1a9cbeSjonb mins: 933da1a9cbeSjonb l = (now-t)/A_MIN; 934da1a9cbeSjonb goto num; 9357c478bd9Sstevel@tonic-gate case CSIZE: 9367c478bd9Sstevel@tonic-gate ll = (long long)statb->st_size; 9377c478bd9Sstevel@tonic-gate goto llnum; 9387c478bd9Sstevel@tonic-gate case SIZE: 9397c478bd9Sstevel@tonic-gate ll = (long long)round(statb->st_size, BLKSIZ)/BLKSIZ; 9407c478bd9Sstevel@tonic-gate goto llnum; 9417c478bd9Sstevel@tonic-gate case F_USER: 9427c478bd9Sstevel@tonic-gate l = (long)statb->st_uid; 9437c478bd9Sstevel@tonic-gate goto num; 9447c478bd9Sstevel@tonic-gate case F_GROUP: 9457c478bd9Sstevel@tonic-gate l = (long)statb->st_gid; 9467c478bd9Sstevel@tonic-gate goto num; 9477c478bd9Sstevel@tonic-gate case LINKS: 9487c478bd9Sstevel@tonic-gate l = (long)statb->st_nlink; 9497c478bd9Sstevel@tonic-gate goto num; 9507c478bd9Sstevel@tonic-gate llnum: 9517c478bd9Sstevel@tonic-gate if (np->second.i == '+') 9527c478bd9Sstevel@tonic-gate val = (ll > np->first.ll); 9537c478bd9Sstevel@tonic-gate else if (np->second.i == '-') 9547c478bd9Sstevel@tonic-gate val = (ll < np->first.ll); 9557c478bd9Sstevel@tonic-gate else 9567c478bd9Sstevel@tonic-gate val = (ll == np->first.ll); 9577c478bd9Sstevel@tonic-gate break; 9587c478bd9Sstevel@tonic-gate num: 9597c478bd9Sstevel@tonic-gate if (np->second.i == '+') 9607c478bd9Sstevel@tonic-gate val = (l > np->first.l); 9617c478bd9Sstevel@tonic-gate else if (np->second.i == '-') 9627c478bd9Sstevel@tonic-gate val = (l < np->first.l); 9637c478bd9Sstevel@tonic-gate else 9647c478bd9Sstevel@tonic-gate val = (l == np->first.l); 9657c478bd9Sstevel@tonic-gate break; 9667c478bd9Sstevel@tonic-gate case OK: 9677c478bd9Sstevel@tonic-gate val = ok(name, np->first.ap); 9687c478bd9Sstevel@tonic-gate break; 9697c478bd9Sstevel@tonic-gate case EXEC: 970d35170d6Srm val = doexec(name, np->first.ap, NULL); 9717c478bd9Sstevel@tonic-gate break; 972ab823b7fSPrasad Joshi case DELETE: 973ab823b7fSPrasad Joshi val = dodelete(name, statb, state); 974ab823b7fSPrasad Joshi break; 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate case VARARGS: { 9777c478bd9Sstevel@tonic-gate struct Arglist *ap = np->first.vp; 9787c478bd9Sstevel@tonic-gate char *cp; 9797c478bd9Sstevel@tonic-gate cp = ap->nextstr - (strlen(name)+1); 9807c478bd9Sstevel@tonic-gate if (cp >= (char *)(ap->nextvar+3)) { 9817c478bd9Sstevel@tonic-gate /* there is room just copy the name */ 9827c478bd9Sstevel@tonic-gate val = 1; 9837c478bd9Sstevel@tonic-gate (void) strcpy(cp, name); 9847c478bd9Sstevel@tonic-gate *ap->nextvar++ = cp; 9857c478bd9Sstevel@tonic-gate ap->nextstr = cp; 9867c478bd9Sstevel@tonic-gate } else { 9877c478bd9Sstevel@tonic-gate /* no more room, exec command */ 98827d3a169SToomas Soome *ap->nextvar++ = (char *)name; 9897c478bd9Sstevel@tonic-gate *ap->nextvar = 0; 9907c478bd9Sstevel@tonic-gate val = 1; 99127d3a169SToomas Soome (void) doexec(NULL, ap->arglist, 992d35170d6Srm &exec_exitcode); 9937c478bd9Sstevel@tonic-gate ap->nextstr = ap->end; 9947c478bd9Sstevel@tonic-gate ap->nextvar = ap->firstvar; 9957c478bd9Sstevel@tonic-gate } 9967c478bd9Sstevel@tonic-gate break; 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate case DEPTH: 10007c478bd9Sstevel@tonic-gate case MOUNT: 10017c478bd9Sstevel@tonic-gate case FOLLOW: 10027c478bd9Sstevel@tonic-gate val = 1; 10037c478bd9Sstevel@tonic-gate break; 10047c478bd9Sstevel@tonic-gate 1005b34cd89aSYuri Pankov case NAME: 100605f32410SAndy Stormont case INAME: 100705f32410SAndy Stormont case PATH: 100805f32410SAndy Stormont case IPATH: { 100905f32410SAndy Stormont char *path; 101005f32410SAndy Stormont int fnmflags = 0; 101105f32410SAndy Stormont 101205f32410SAndy Stormont if (np->action == INAME || np->action == IPATH) 101305f32410SAndy Stormont fnmflags = FNM_IGNORECASE; 10149ab6dc39Schin 10159ab6dc39Schin /* 10169ab6dc39Schin * basename(3c) may modify name, so 10179ab6dc39Schin * we need to pass another string 10189ab6dc39Schin */ 101905f32410SAndy Stormont if ((path = strdup(name)) == NULL) { 10209ab6dc39Schin (void) fprintf(stderr, 10219ab6dc39Schin gettext("%s: cannot strdup() %s: %s\n"), 10226b238a5aSchin cmdname, name, strerror(errno)); 10239ab6dc39Schin exit(2); 10249ab6dc39Schin } 10257c478bd9Sstevel@tonic-gate /* 10267c478bd9Sstevel@tonic-gate * XPG4 find should not treat a leading '.' in a 10277c478bd9Sstevel@tonic-gate * filename specially for pattern matching. 10287c478bd9Sstevel@tonic-gate * /usr/bin/find will not pattern match a leading 10297c478bd9Sstevel@tonic-gate * '.' in a filename, unless '.' is explicitly 10307c478bd9Sstevel@tonic-gate * specified. 1031*f3a525d9SJohn Levon * 1032*f3a525d9SJohn Levon * The legacy behavior makes no sense for PATH. 10337c478bd9Sstevel@tonic-gate */ 1034b34cd89aSYuri Pankov #ifndef XPG4 1035*f3a525d9SJohn Levon if (np->action == NAME || np->action == INAME) 1036*f3a525d9SJohn Levon fnmflags |= FNM_PERIOD; 10377c478bd9Sstevel@tonic-gate #endif 103805f32410SAndy Stormont 103905f32410SAndy Stormont val = !fnmatch(np->first.cp, 104027d3a169SToomas Soome (np->action == NAME || np->action == INAME) ? 104127d3a169SToomas Soome basename(path) : path, fnmflags); 104205f32410SAndy Stormont free(path); 10437c478bd9Sstevel@tonic-gate break; 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate case PRUNE: 10477c478bd9Sstevel@tonic-gate if (type == FTW_D) 10487c478bd9Sstevel@tonic-gate state->quit = FTW_PRUNE; 10497c478bd9Sstevel@tonic-gate val = 1; 10507c478bd9Sstevel@tonic-gate break; 10517c478bd9Sstevel@tonic-gate case NOUSER: 10527c478bd9Sstevel@tonic-gate val = ((getpwuid(statb->st_uid)) == 0); 10537c478bd9Sstevel@tonic-gate break; 10547c478bd9Sstevel@tonic-gate case NOGRP: 10557c478bd9Sstevel@tonic-gate val = ((getgrgid(statb->st_gid)) == 0); 10567c478bd9Sstevel@tonic-gate break; 10577c478bd9Sstevel@tonic-gate case FSTYPE: 10587c478bd9Sstevel@tonic-gate val = (strcmp(np->first.cp, statb->st_fstype) == 0); 10597c478bd9Sstevel@tonic-gate break; 10607c478bd9Sstevel@tonic-gate case CPIO: 10617c478bd9Sstevel@tonic-gate output = (FILE *)np->first.l; 10627c478bd9Sstevel@tonic-gate (void) fprintf(output, "%s\n", name); 10637c478bd9Sstevel@tonic-gate val = 1; 10647c478bd9Sstevel@tonic-gate break; 10657c478bd9Sstevel@tonic-gate case PRINT: 1066b34cd89aSYuri Pankov case PRINT0: 1067b34cd89aSYuri Pankov (void) fprintf(stdout, "%s%c", name, 1068b34cd89aSYuri Pankov (np->action == PRINT) ? '\n' : '\0'); 10697c478bd9Sstevel@tonic-gate val = 1; 10707c478bd9Sstevel@tonic-gate break; 10717c478bd9Sstevel@tonic-gate case LS: 10727c478bd9Sstevel@tonic-gate (void) list(name, statb); 10737c478bd9Sstevel@tonic-gate val = 1; 10747c478bd9Sstevel@tonic-gate break; 10757c478bd9Sstevel@tonic-gate case XATTR: 1076f467e6fbSJohn Sonnenschein filename = (walkflags & FTW_CHDIR) ? 107727d3a169SToomas Soome gettail(name) : name; 10787c478bd9Sstevel@tonic-gate val = (pathconf(filename, _PC_XATTR_EXISTS) == 1); 10797c478bd9Sstevel@tonic-gate break; 10807c478bd9Sstevel@tonic-gate case ACL: 10817c478bd9Sstevel@tonic-gate /* 10827c478bd9Sstevel@tonic-gate * Need to get the tail of the file name, since we have 10837c478bd9Sstevel@tonic-gate * already chdir()ed into the directory (performed in 10847c478bd9Sstevel@tonic-gate * nftw()) of the file 10857c478bd9Sstevel@tonic-gate */ 1086f467e6fbSJohn Sonnenschein filename = (walkflags & FTW_CHDIR) ? 108727d3a169SToomas Soome gettail(name) : name; 1088f467e6fbSJohn Sonnenschein val = acl_trivial(filename); 10897c478bd9Sstevel@tonic-gate break; 1090b34cd89aSYuri Pankov case F_USERACL: 1091b34cd89aSYuri Pankov case F_GROUPACL: { 1092b34cd89aSYuri Pankov int i; 1093b34cd89aSYuri Pankov acl_t *acl; 1094b34cd89aSYuri Pankov void *acl_entry; 1095b34cd89aSYuri Pankov aclent_t *p1; 1096b34cd89aSYuri Pankov ace_t *p2; 1097b34cd89aSYuri Pankov 1098b34cd89aSYuri Pankov filename = (walkflags & FTW_CHDIR) ? 1099b34cd89aSYuri Pankov gettail(name) : name; 1100b34cd89aSYuri Pankov val = 0; 1101b34cd89aSYuri Pankov if (acl_get(filename, 0, &acl) != 0) 1102b34cd89aSYuri Pankov break; 1103b34cd89aSYuri Pankov for (i = 0, acl_entry = acl->acl_aclp; 1104b34cd89aSYuri Pankov i != acl->acl_cnt; i++) { 1105b34cd89aSYuri Pankov if (acl->acl_type == ACLENT_T) { 1106b34cd89aSYuri Pankov p1 = (aclent_t *)acl_entry; 1107b34cd89aSYuri Pankov if (p1->a_id == np->first.l) { 1108b34cd89aSYuri Pankov val = 1; 1109b34cd89aSYuri Pankov acl_free(acl); 1110b34cd89aSYuri Pankov break; 1111b34cd89aSYuri Pankov } 1112b34cd89aSYuri Pankov } else { 1113b34cd89aSYuri Pankov p2 = (ace_t *)acl_entry; 1114b34cd89aSYuri Pankov if (p2->a_who == np->first.l) { 1115b34cd89aSYuri Pankov val = 1; 1116b34cd89aSYuri Pankov acl_free(acl); 1117b34cd89aSYuri Pankov break; 1118b34cd89aSYuri Pankov } 1119b34cd89aSYuri Pankov } 1120b34cd89aSYuri Pankov acl_entry = ((char *)acl_entry + 1121b34cd89aSYuri Pankov acl->acl_entry_size); 1122b34cd89aSYuri Pankov } 1123b34cd89aSYuri Pankov acl_free(acl); 1124b34cd89aSYuri Pankov break; 1125b34cd89aSYuri Pankov } 1126b34cd89aSYuri Pankov case IREGEX: 1127b34cd89aSYuri Pankov case REGEX: { 1128b34cd89aSYuri Pankov regmatch_t pmatch; 1129b34cd89aSYuri Pankov 1130b34cd89aSYuri Pankov val = 0; 113127d3a169SToomas Soome if (regexec(&preg[cnpreg], name, 1, &pmatch, 0) == 0) 1132b34cd89aSYuri Pankov val = ((pmatch.rm_so == 0) && 1133b34cd89aSYuri Pankov (pmatch.rm_eo == strlen(name))); 1134b34cd89aSYuri Pankov cnpreg++; 1135b34cd89aSYuri Pankov break; 1136b34cd89aSYuri Pankov } 1137b34cd89aSYuri Pankov case MAXDEPTH: 1138b34cd89aSYuri Pankov if (state->level == maxdepth && type == FTW_D) 1139b34cd89aSYuri Pankov state->quit = FTW_PRUNE; 1140b34cd89aSYuri Pankov /* FALLTHROUGH */ 1141b34cd89aSYuri Pankov case MINDEPTH: 1142b34cd89aSYuri Pankov val = 1; 1143b34cd89aSYuri Pankov break; 11447c478bd9Sstevel@tonic-gate } 11457c478bd9Sstevel@tonic-gate /* 11467c478bd9Sstevel@tonic-gate * evaluate 'val' and 'not' (exclusive-or) 11477c478bd9Sstevel@tonic-gate * if no inversion (not == 1), return only when val == 0 11487c478bd9Sstevel@tonic-gate * (primary not true). Otherwise, invert the primary 11497c478bd9Sstevel@tonic-gate * and return when the primary is true. 11507c478bd9Sstevel@tonic-gate * 'Lastval' saves the last result (fail or pass) when 11517c478bd9Sstevel@tonic-gate * returning back to the calling routine. 11527c478bd9Sstevel@tonic-gate */ 115327d3a169SToomas Soome if (val ^ not) { 11547c478bd9Sstevel@tonic-gate lastval = 0; 11557c478bd9Sstevel@tonic-gate return (0); 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate lastval = 1; 11587c478bd9Sstevel@tonic-gate not = 1; 11597c478bd9Sstevel@tonic-gate np = np->next; 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate return (0); 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate /* 11657c478bd9Sstevel@tonic-gate * code for the -ok option 11667c478bd9Sstevel@tonic-gate */ 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate static int 116927d3a169SToomas Soome ok(const char *name, char *argv[]) 11707c478bd9Sstevel@tonic-gate { 11713d63ea05Sas int c; 11723d63ea05Sas int i = 0; 11733d63ea05Sas char resp[LINE_MAX + 1]; 11747c478bd9Sstevel@tonic-gate 117527d3a169SToomas Soome (void) fflush(stdout); /* to flush possible `-print' */ 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate if ((*argv != dummyarg) && (strcmp(*argv, name))) 11787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "< %s ... %s >? ", *argv, name); 11797c478bd9Sstevel@tonic-gate else 11807c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "< {} ... %s >? ", name); 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate (void) fflush(stderr); 11833d63ea05Sas 11843d63ea05Sas while ((c = getchar()) != '\n') { 11857c478bd9Sstevel@tonic-gate if (c == EOF) 11867c478bd9Sstevel@tonic-gate exit(2); 11873d63ea05Sas if (i < LINE_MAX) 11883d63ea05Sas resp[i++] = c; 11893d63ea05Sas } 11903d63ea05Sas resp[i] = '\0'; 11913d63ea05Sas 11923d63ea05Sas if (yes_check(resp)) 11933d63ea05Sas return (doexec(name, argv, NULL)); 11943d63ea05Sas else 11953d63ea05Sas return (0); 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate /* 11997c478bd9Sstevel@tonic-gate * execute argv with {} replaced by name 1200d35170d6Srm * 1201d35170d6Srm * Per XPG6, find must exit non-zero if an invocation through 1202d35170d6Srm * -exec, punctuated by a plus sign, exits non-zero, so set 1203d35170d6Srm * exitcode if we see a non-zero exit. 1204d35170d6Srm * exitcode should be NULL when -exec or -ok is not punctuated 1205d35170d6Srm * by a plus sign. 12067c478bd9Sstevel@tonic-gate */ 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate static int 120927d3a169SToomas Soome doexec(const char *name, char *argv[], int *exitcode) 12107c478bd9Sstevel@tonic-gate { 12117c478bd9Sstevel@tonic-gate char *cp; 12127c478bd9Sstevel@tonic-gate char **av = argv; 1213d35170d6Srm char *newargs[1 + SHELL_MAXARGS + 1]; 12147c478bd9Sstevel@tonic-gate int dummyseen = 0; 1215d35170d6Srm int i, j, status, rc, r = 0; 1216d35170d6Srm int exit_status = 0; 1217d35170d6Srm pid_t pid, pid1; 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate (void) fflush(stdout); /* to flush possible `-print' */ 12207c478bd9Sstevel@tonic-gate if (name) { 12217c478bd9Sstevel@tonic-gate while (cp = *av++) { 12227c478bd9Sstevel@tonic-gate if (cp == dummyarg) { 12237c478bd9Sstevel@tonic-gate dummyseen = 1; 122427d3a169SToomas Soome av[-1] = (char *)name; 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate } 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate if (argv[0] == NULL) /* null command line */ 12307c478bd9Sstevel@tonic-gate return (r); 12317c478bd9Sstevel@tonic-gate 1232d35170d6Srm if ((pid = fork()) == -1) { 1233d35170d6Srm /* fork failed */ 1234d35170d6Srm if (exitcode != NULL) 1235d35170d6Srm *exitcode = 1; 1236d35170d6Srm return (0); 1237d35170d6Srm } 1238d35170d6Srm if (pid != 0) { 1239d35170d6Srm /* parent */ 1240d35170d6Srm do { 1241d35170d6Srm /* wait for child to exit */ 1242d35170d6Srm if ((rc = wait(&r)) == -1 && errno != EINTR) { 1243d35170d6Srm (void) fprintf(stderr, 1244d35170d6Srm gettext("wait failed %s"), strerror(errno)); 1245d35170d6Srm 1246d35170d6Srm if (exitcode != NULL) 1247d35170d6Srm *exitcode = 1; 1248d35170d6Srm return (0); 1249d35170d6Srm } 1250d35170d6Srm } while (rc != pid); 1251d35170d6Srm } else { 1252d35170d6Srm /* child */ 12537c478bd9Sstevel@tonic-gate (void) execvp(argv[0], argv); 1254d35170d6Srm if (errno != E2BIG) 1255d35170d6Srm exit(1); 1256d35170d6Srm 1257d35170d6Srm /* 1258d35170d6Srm * We are in a situation where argv[0] points to a 1259d35170d6Srm * script without the interpreter line, e.g. #!/bin/sh. 1260d35170d6Srm * execvp() will execute either /usr/bin/sh or 1261d35170d6Srm * /usr/xpg4/bin/sh against the script, and you will be 1262d35170d6Srm * limited to SHELL_MAXARGS arguments. If you try to 1263d35170d6Srm * pass more than SHELL_MAXARGS arguments, execvp() 1264d35170d6Srm * fails with E2BIG. 1265d35170d6Srm * See usr/src/lib/libc/port/gen/execvp.c. 1266d35170d6Srm * 1267d35170d6Srm * In this situation, process the argument list by 1268d35170d6Srm * packets of SHELL_MAXARGS arguments with respect of 1269d35170d6Srm * the following rules: 1270d35170d6Srm * 1. the invocations have to complete before find exits 1271d35170d6Srm * 2. only one invocation can be running at a time 1272d35170d6Srm */ 1273d35170d6Srm 1274d35170d6Srm i = 1; 1275d35170d6Srm newargs[0] = argv[0]; 1276d35170d6Srm 1277d35170d6Srm while (argv[i]) { 1278d35170d6Srm j = 1; 1279d35170d6Srm while (j <= SHELL_MAXARGS && argv[i]) { 1280d35170d6Srm newargs[j++] = argv[i++]; 1281d35170d6Srm } 1282d35170d6Srm newargs[j] = NULL; 1283d35170d6Srm 1284d35170d6Srm if ((pid1 = fork()) == -1) { 1285d35170d6Srm /* fork failed */ 1286d35170d6Srm exit(1); 1287d35170d6Srm } 1288d35170d6Srm if (pid1 == 0) { 1289d35170d6Srm /* child */ 1290d35170d6Srm (void) execvp(newargs[0], newargs); 1291d35170d6Srm exit(1); 1292d35170d6Srm } 1293d35170d6Srm 1294d35170d6Srm status = 0; 1295d35170d6Srm 1296d35170d6Srm do { 1297d35170d6Srm /* wait for the child to exit */ 1298d35170d6Srm if ((rc = wait(&status)) == -1 && 1299d35170d6Srm errno != EINTR) { 1300d35170d6Srm (void) fprintf(stderr, 1301d35170d6Srm gettext("wait failed %s"), 1302d35170d6Srm strerror(errno)); 1303d35170d6Srm exit(1); 1304d35170d6Srm } 1305d35170d6Srm } while (rc != pid1); 1306d35170d6Srm 1307d35170d6Srm if (status) 1308d35170d6Srm exit_status = 1; 1309d35170d6Srm } 1310d35170d6Srm /* all the invocations have completed */ 1311d35170d6Srm exit(exit_status); 13127c478bd9Sstevel@tonic-gate } 1313d35170d6Srm 13147c478bd9Sstevel@tonic-gate if (name && dummyseen) { 13157c478bd9Sstevel@tonic-gate for (av = argv; cp = *av++; ) { 13167c478bd9Sstevel@tonic-gate if (cp == name) 13177c478bd9Sstevel@tonic-gate av[-1] = dummyarg; 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate 1321d35170d6Srm if (r && exitcode != NULL) 1322d35170d6Srm *exitcode = 3; /* use to indicate error in cmd invocation */ 1323d35170d6Srm 13247c478bd9Sstevel@tonic-gate return (!r); 13257c478bd9Sstevel@tonic-gate } 13267c478bd9Sstevel@tonic-gate 1327ab823b7fSPrasad Joshi static int 132827d3a169SToomas Soome dodelete(const char *name, const struct stat *statb, struct FTW *state) 1329ab823b7fSPrasad Joshi { 133027d3a169SToomas Soome const char *fn; 1331ab823b7fSPrasad Joshi int rc = 0; 1332ab823b7fSPrasad Joshi 1333ab823b7fSPrasad Joshi /* restrict symlinks */ 1334ab823b7fSPrasad Joshi if ((walkflags & FTW_PHYS) == 0) { 1335ab823b7fSPrasad Joshi (void) fprintf(stderr, 1336ab823b7fSPrasad Joshi gettext("-delete is not allowed when symlinks are " 1337ab823b7fSPrasad Joshi "followed.\n")); 1338ab823b7fSPrasad Joshi return (1); 1339ab823b7fSPrasad Joshi } 1340ab823b7fSPrasad Joshi 1341ab823b7fSPrasad Joshi fn = name + state->base; 1342ab823b7fSPrasad Joshi if (strcmp(fn, ".") == 0) { 1343ab823b7fSPrasad Joshi /* nothing to do */ 1344ab823b7fSPrasad Joshi return (1); 1345ab823b7fSPrasad Joshi } 1346ab823b7fSPrasad Joshi 1347ab823b7fSPrasad Joshi if (strchr(fn, '/') != NULL) { 1348ab823b7fSPrasad Joshi (void) fprintf(stderr, 1349ab823b7fSPrasad Joshi gettext("-delete with relative path is unsafe.")); 1350ab823b7fSPrasad Joshi return (1); 1351ab823b7fSPrasad Joshi } 1352ab823b7fSPrasad Joshi 1353ab823b7fSPrasad Joshi if (S_ISDIR(statb->st_mode)) { 1354ab823b7fSPrasad Joshi /* delete directory */ 1355ab823b7fSPrasad Joshi rc = rmdir(name); 1356ab823b7fSPrasad Joshi } else { 1357ab823b7fSPrasad Joshi /* delete file */ 1358ab823b7fSPrasad Joshi rc = unlink(name); 1359ab823b7fSPrasad Joshi } 1360ab823b7fSPrasad Joshi 1361ab823b7fSPrasad Joshi if (rc < 0) { 1362ab823b7fSPrasad Joshi /* operation failed */ 1363ab823b7fSPrasad Joshi (void) fprintf(stderr, gettext("delete failed %s: %s\n"), 1364ab823b7fSPrasad Joshi name, strerror(errno)); 1365ab823b7fSPrasad Joshi return (1); 1366ab823b7fSPrasad Joshi } 1367ab823b7fSPrasad Joshi 1368ab823b7fSPrasad Joshi return (1); 1369ab823b7fSPrasad Joshi } 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate /* 13727c478bd9Sstevel@tonic-gate * Table lookup routine 13737c478bd9Sstevel@tonic-gate */ 13747c478bd9Sstevel@tonic-gate static struct Args * 137527d3a169SToomas Soome lookup(char *word) 13767c478bd9Sstevel@tonic-gate { 13777c478bd9Sstevel@tonic-gate struct Args *argp = commands; 13787c478bd9Sstevel@tonic-gate int second; 13797c478bd9Sstevel@tonic-gate if (word == 0 || *word == 0) 13807c478bd9Sstevel@tonic-gate return (0); 13817c478bd9Sstevel@tonic-gate second = word[1]; 13827c478bd9Sstevel@tonic-gate while (*argp->name) { 13837c478bd9Sstevel@tonic-gate if (second == argp->name[1] && strcmp(word, argp->name) == 0) 13847c478bd9Sstevel@tonic-gate return (argp); 13857c478bd9Sstevel@tonic-gate argp++; 13867c478bd9Sstevel@tonic-gate } 13877c478bd9Sstevel@tonic-gate return (0); 13887c478bd9Sstevel@tonic-gate } 13897c478bd9Sstevel@tonic-gate 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate /* 13927c478bd9Sstevel@tonic-gate * Get space for variable length argument list 13937c478bd9Sstevel@tonic-gate */ 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate static struct Arglist * 139627d3a169SToomas Soome varargs(char **com) 13977c478bd9Sstevel@tonic-gate { 13987c478bd9Sstevel@tonic-gate struct Arglist *ap; 13997c478bd9Sstevel@tonic-gate int n; 14007c478bd9Sstevel@tonic-gate char **ep; 14017c478bd9Sstevel@tonic-gate if (varsize == 0) { 14027c478bd9Sstevel@tonic-gate n = 2*sizeof (char **); 14037c478bd9Sstevel@tonic-gate for (ep = environ; *ep; ep++) 14047c478bd9Sstevel@tonic-gate n += (strlen(*ep)+sizeof (ep) + 1); 14057c478bd9Sstevel@tonic-gate varsize = sizeof (struct Arglist)+ARG_MAX-PATH_MAX-n-1; 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate ap = (struct Arglist *)malloc(varsize+1); 14087c478bd9Sstevel@tonic-gate ap->end = (char *)ap + varsize; 14097c478bd9Sstevel@tonic-gate ap->nextstr = ap->end; 14107c478bd9Sstevel@tonic-gate ap->nextvar = ap->arglist; 141127d3a169SToomas Soome while (*ap->nextvar++ = *com++) 141227d3a169SToomas Soome ; 14137c478bd9Sstevel@tonic-gate ap->nextvar--; 14147c478bd9Sstevel@tonic-gate ap->firstvar = ap->nextvar; 14157c478bd9Sstevel@tonic-gate ap->next = lastlist; 14167c478bd9Sstevel@tonic-gate lastlist = ap; 14177c478bd9Sstevel@tonic-gate return (ap); 14187c478bd9Sstevel@tonic-gate } 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate /* 14217c478bd9Sstevel@tonic-gate * filter command support 14227c478bd9Sstevel@tonic-gate * fork and exec cmd(argv) according to mode: 14237c478bd9Sstevel@tonic-gate * 14247c478bd9Sstevel@tonic-gate * "r" with fp as stdin of cmd (default stdin), cmd stdout returned 14257c478bd9Sstevel@tonic-gate * "w" with fp as stdout of cmd (default stdout), cmd stdin returned 14267c478bd9Sstevel@tonic-gate */ 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate #define CMDERR ((1<<8)-1) /* command error exit code */ 14297c478bd9Sstevel@tonic-gate #define MAXCMDS 8 /* max # simultaneous cmdopen()'s */ 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate static struct /* info for each cmdopen() */ 14327c478bd9Sstevel@tonic-gate { 14337c478bd9Sstevel@tonic-gate FILE *fp; /* returned by cmdopen() */ 14347c478bd9Sstevel@tonic-gate pid_t pid; /* pid used by cmdopen() */ 14357c478bd9Sstevel@tonic-gate } cmdproc[MAXCMDS]; 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate static FILE * 143827d3a169SToomas Soome cmdopen(char *cmd, char **argv, char *mode, FILE *fp) 14397c478bd9Sstevel@tonic-gate { 14407c478bd9Sstevel@tonic-gate int proc; 14417c478bd9Sstevel@tonic-gate int cmdfd; 14427c478bd9Sstevel@tonic-gate int usrfd; 14437c478bd9Sstevel@tonic-gate int pio[2]; 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate switch (*mode) { 14467c478bd9Sstevel@tonic-gate case 'r': 14477c478bd9Sstevel@tonic-gate cmdfd = 1; 14487c478bd9Sstevel@tonic-gate usrfd = 0; 14497c478bd9Sstevel@tonic-gate break; 14507c478bd9Sstevel@tonic-gate case 'w': 14517c478bd9Sstevel@tonic-gate cmdfd = 0; 14527c478bd9Sstevel@tonic-gate usrfd = 1; 14537c478bd9Sstevel@tonic-gate break; 14547c478bd9Sstevel@tonic-gate default: 14557c478bd9Sstevel@tonic-gate return (0); 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate for (proc = 0; proc < MAXCMDS; proc++) 14597c478bd9Sstevel@tonic-gate if (!cmdproc[proc].fp) 14607c478bd9Sstevel@tonic-gate break; 14617c478bd9Sstevel@tonic-gate if (proc >= MAXCMDS) 14627c478bd9Sstevel@tonic-gate return (0); 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate if (pipe(pio)) 14657c478bd9Sstevel@tonic-gate return (0); 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate switch (cmdproc[proc].pid = fork()) { 14687c478bd9Sstevel@tonic-gate case -1: 14697c478bd9Sstevel@tonic-gate return (0); 14707c478bd9Sstevel@tonic-gate case 0: 14717c478bd9Sstevel@tonic-gate if (fp && fileno(fp) != usrfd) { 14727c478bd9Sstevel@tonic-gate (void) close(usrfd); 14737c478bd9Sstevel@tonic-gate if (dup2(fileno(fp), usrfd) != usrfd) 14747c478bd9Sstevel@tonic-gate _exit(CMDERR); 14757c478bd9Sstevel@tonic-gate (void) close(fileno(fp)); 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate (void) close(cmdfd); 14787c478bd9Sstevel@tonic-gate if (dup2(pio[cmdfd], cmdfd) != cmdfd) 14797c478bd9Sstevel@tonic-gate _exit(CMDERR); 14807c478bd9Sstevel@tonic-gate (void) close(pio[cmdfd]); 14817c478bd9Sstevel@tonic-gate (void) close(pio[usrfd]); 14827c478bd9Sstevel@tonic-gate (void) execvp(cmd, argv); 14837c478bd9Sstevel@tonic-gate if (errno == ENOEXEC) { 14847c478bd9Sstevel@tonic-gate char **p; 14857c478bd9Sstevel@tonic-gate char **v; 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate /* 14887c478bd9Sstevel@tonic-gate * assume cmd is a shell script 14897c478bd9Sstevel@tonic-gate */ 14907c478bd9Sstevel@tonic-gate 14917c478bd9Sstevel@tonic-gate p = argv; 149227d3a169SToomas Soome while (*p++) 149327d3a169SToomas Soome ; 149427d3a169SToomas Soome if (v = malloc((p - argv + 1) * sizeof (char **))) { 14957c478bd9Sstevel@tonic-gate p = v; 14967c478bd9Sstevel@tonic-gate *p++ = cmd; 149727d3a169SToomas Soome if (*argv) 149827d3a169SToomas Soome argv++; 149927d3a169SToomas Soome while (*p++ = *argv++) 150027d3a169SToomas Soome ; 15017c478bd9Sstevel@tonic-gate (void) execv(getshell(), v); 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate } 15047c478bd9Sstevel@tonic-gate _exit(CMDERR); 15057c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 15067c478bd9Sstevel@tonic-gate default: 15077c478bd9Sstevel@tonic-gate (void) close(pio[cmdfd]); 15087c478bd9Sstevel@tonic-gate return (cmdproc[proc].fp = fdopen(pio[usrfd], mode)); 15097c478bd9Sstevel@tonic-gate } 15107c478bd9Sstevel@tonic-gate } 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate /* 15137c478bd9Sstevel@tonic-gate * close a stream opened by cmdopen() 15147c478bd9Sstevel@tonic-gate * -1 returned if cmdopen() had a problem 15157c478bd9Sstevel@tonic-gate * otherwise exit() status of command is returned 15167c478bd9Sstevel@tonic-gate */ 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate static int 151927d3a169SToomas Soome cmdclose(FILE *fp) 15207c478bd9Sstevel@tonic-gate { 15217c478bd9Sstevel@tonic-gate int i; 15227c478bd9Sstevel@tonic-gate pid_t p, pid; 15237c478bd9Sstevel@tonic-gate int status; 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate for (i = 0; i < MAXCMDS; i++) 15267c478bd9Sstevel@tonic-gate if (fp == cmdproc[i].fp) break; 15277c478bd9Sstevel@tonic-gate if (i >= MAXCMDS) 15287c478bd9Sstevel@tonic-gate return (-1); 15297c478bd9Sstevel@tonic-gate (void) fclose(fp); 15307c478bd9Sstevel@tonic-gate cmdproc[i].fp = 0; 15317c478bd9Sstevel@tonic-gate pid = cmdproc[i].pid; 153227d3a169SToomas Soome while ((p = wait(&status)) != pid && p != (pid_t)-1) 153327d3a169SToomas Soome ; 15347c478bd9Sstevel@tonic-gate if (p == pid) { 15357c478bd9Sstevel@tonic-gate status = (status >> 8) & CMDERR; 15367c478bd9Sstevel@tonic-gate if (status == CMDERR) 15377c478bd9Sstevel@tonic-gate status = -1; 15387c478bd9Sstevel@tonic-gate } 15397c478bd9Sstevel@tonic-gate else 15407c478bd9Sstevel@tonic-gate status = -1; 15417c478bd9Sstevel@tonic-gate return (status); 15427c478bd9Sstevel@tonic-gate } 15437c478bd9Sstevel@tonic-gate 15447c478bd9Sstevel@tonic-gate /* 15457c478bd9Sstevel@tonic-gate * return pointer to the full path name of the shell 15467c478bd9Sstevel@tonic-gate * 15477c478bd9Sstevel@tonic-gate * SHELL is read from the environment and must start with / 15487c478bd9Sstevel@tonic-gate * 15497c478bd9Sstevel@tonic-gate * if set-uid or set-gid then the executable and its containing 15507c478bd9Sstevel@tonic-gate * directory must not be writable by the real user 15517c478bd9Sstevel@tonic-gate * 15527c478bd9Sstevel@tonic-gate * /usr/bin/sh is returned by default 15537c478bd9Sstevel@tonic-gate */ 15547c478bd9Sstevel@tonic-gate 15557c478bd9Sstevel@tonic-gate char * 155627d3a169SToomas Soome getshell(void) 15577c478bd9Sstevel@tonic-gate { 15587c478bd9Sstevel@tonic-gate char *s; 15597c478bd9Sstevel@tonic-gate char *sh; 15607c478bd9Sstevel@tonic-gate uid_t u; 15617c478bd9Sstevel@tonic-gate int j; 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate if (((sh = getenv("SHELL")) != 0) && *sh == '/') { 15647c478bd9Sstevel@tonic-gate if (u = getuid()) { 15657c478bd9Sstevel@tonic-gate if ((u != geteuid() || getgid() != getegid()) && 15663d63ea05Sas access(sh, 2) == 0) 15677c478bd9Sstevel@tonic-gate goto defshell; 15687c478bd9Sstevel@tonic-gate s = strrchr(sh, '/'); 15697c478bd9Sstevel@tonic-gate *s = 0; 15707c478bd9Sstevel@tonic-gate j = access(sh, 2); 15717c478bd9Sstevel@tonic-gate *s = '/'; 15727c478bd9Sstevel@tonic-gate if (!j) goto defshell; 15737c478bd9Sstevel@tonic-gate } 15747c478bd9Sstevel@tonic-gate return (sh); 15757c478bd9Sstevel@tonic-gate } 15767c478bd9Sstevel@tonic-gate defshell: 15777c478bd9Sstevel@tonic-gate return ("/usr/bin/sh"); 15787c478bd9Sstevel@tonic-gate } 15797c478bd9Sstevel@tonic-gate 15807c478bd9Sstevel@tonic-gate /* 15817c478bd9Sstevel@tonic-gate * the following functions implement the added "-ls" option 15827c478bd9Sstevel@tonic-gate */ 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate #include <utmpx.h> 15857c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate struct utmpx utmpx; 15887c478bd9Sstevel@tonic-gate #define NMAX (sizeof (utmpx.ut_name)) 15897c478bd9Sstevel@tonic-gate #define SCPYN(a, b) (void) strncpy(a, b, NMAX) 15907c478bd9Sstevel@tonic-gate 15917c478bd9Sstevel@tonic-gate #define NUID 64 15927c478bd9Sstevel@tonic-gate #define NGID 64 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate static struct ncache { 15957c478bd9Sstevel@tonic-gate int id; 15967c478bd9Sstevel@tonic-gate char name[NMAX+1]; 15977c478bd9Sstevel@tonic-gate } nc[NUID], gc[NGID]; 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate /* 16007c478bd9Sstevel@tonic-gate * This function assumes that the password file is hashed 16017c478bd9Sstevel@tonic-gate * (or some such) to allow fast access based on a name key. 16027c478bd9Sstevel@tonic-gate */ 16037c478bd9Sstevel@tonic-gate static char * 16047c478bd9Sstevel@tonic-gate getname(uid_t uid) 16057c478bd9Sstevel@tonic-gate { 16067c478bd9Sstevel@tonic-gate struct passwd *pw; 16077c478bd9Sstevel@tonic-gate int cp; 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate #if (((NUID) & ((NUID) - 1)) != 0) 16107c478bd9Sstevel@tonic-gate cp = uid % (NUID); 16117c478bd9Sstevel@tonic-gate #else 16127c478bd9Sstevel@tonic-gate cp = uid & ((NUID) - 1); 16137c478bd9Sstevel@tonic-gate #endif 1614f48205beScasper if (nc[cp].id == uid && nc[cp].name[0]) 16157c478bd9Sstevel@tonic-gate return (nc[cp].name); 16167c478bd9Sstevel@tonic-gate pw = getpwuid(uid); 16177c478bd9Sstevel@tonic-gate if (!pw) 16187c478bd9Sstevel@tonic-gate return (0); 16197c478bd9Sstevel@tonic-gate nc[cp].id = uid; 16207c478bd9Sstevel@tonic-gate SCPYN(nc[cp].name, pw->pw_name); 16217c478bd9Sstevel@tonic-gate return (nc[cp].name); 16227c478bd9Sstevel@tonic-gate } 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate /* 16257c478bd9Sstevel@tonic-gate * This function assumes that the group file is hashed 16267c478bd9Sstevel@tonic-gate * (or some such) to allow fast access based on a name key. 16277c478bd9Sstevel@tonic-gate */ 16287c478bd9Sstevel@tonic-gate static char * 16297c478bd9Sstevel@tonic-gate getgroup(gid_t gid) 16307c478bd9Sstevel@tonic-gate { 16317c478bd9Sstevel@tonic-gate struct group *gr; 16327c478bd9Sstevel@tonic-gate int cp; 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate #if (((NGID) & ((NGID) - 1)) != 0) 16357c478bd9Sstevel@tonic-gate cp = gid % (NGID); 16367c478bd9Sstevel@tonic-gate #else 16377c478bd9Sstevel@tonic-gate cp = gid & ((NGID) - 1); 16387c478bd9Sstevel@tonic-gate #endif 1639f48205beScasper if (gc[cp].id == gid && gc[cp].name[0]) 16407c478bd9Sstevel@tonic-gate return (gc[cp].name); 16417c478bd9Sstevel@tonic-gate gr = getgrgid(gid); 16427c478bd9Sstevel@tonic-gate if (!gr) 16437c478bd9Sstevel@tonic-gate return (0); 16447c478bd9Sstevel@tonic-gate gc[cp].id = gid; 16457c478bd9Sstevel@tonic-gate SCPYN(gc[cp].name, gr->gr_name); 16467c478bd9Sstevel@tonic-gate return (gc[cp].name); 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate #define permoffset(who) ((who) * 3) 16507c478bd9Sstevel@tonic-gate #define permission(who, type) ((type) >> permoffset(who)) 16517c478bd9Sstevel@tonic-gate #define kbytes(bytes) (((bytes) + 1023) / 1024) 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate static int 165427d3a169SToomas Soome list(const char *file, const struct stat *stp) 16557c478bd9Sstevel@tonic-gate { 16567c478bd9Sstevel@tonic-gate char pmode[32], uname[32], gname[32], fsize[32], ftime[32]; 1657fa9e4066Sahrens int trivial; 16587c478bd9Sstevel@tonic-gate 16597c478bd9Sstevel@tonic-gate /* 16607c478bd9Sstevel@tonic-gate * Each line below contains the relevant permission (column 1) and character 16617c478bd9Sstevel@tonic-gate * shown when the corresponding execute bit is either clear (column 2) 16627c478bd9Sstevel@tonic-gate * or set (column 3) 16637c478bd9Sstevel@tonic-gate * These permissions are as shown by ls(1b) 16647c478bd9Sstevel@tonic-gate */ 16657c478bd9Sstevel@tonic-gate static long special[] = { S_ISUID, 'S', 's', 16667c478bd9Sstevel@tonic-gate S_ISGID, 'S', 's', 16677c478bd9Sstevel@tonic-gate S_ISVTX, 'T', 't' }; 16687c478bd9Sstevel@tonic-gate 16697c478bd9Sstevel@tonic-gate static time_t sixmonthsago = -1; 16707c478bd9Sstevel@tonic-gate #ifdef S_IFLNK 16717c478bd9Sstevel@tonic-gate char flink[MAXPATHLEN + 1]; 16727c478bd9Sstevel@tonic-gate #endif 16737c478bd9Sstevel@tonic-gate int who; 16747c478bd9Sstevel@tonic-gate char *cp; 167527d3a169SToomas Soome const char *tailname; 16767c478bd9Sstevel@tonic-gate time_t now; 16777c478bd9Sstevel@tonic-gate long long ksize; 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate if (file == NULL || stp == NULL) 16807c478bd9Sstevel@tonic-gate return (-1); 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate (void) time(&now); 16837c478bd9Sstevel@tonic-gate if (sixmonthsago == -1) 16847c478bd9Sstevel@tonic-gate sixmonthsago = now - 6L*30L*24L*60L*60L; 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate switch (stp->st_mode & S_IFMT) { 16877c478bd9Sstevel@tonic-gate #ifdef S_IFDIR 16887c478bd9Sstevel@tonic-gate case S_IFDIR: /* directory */ 16897c478bd9Sstevel@tonic-gate pmode[0] = 'd'; 16907c478bd9Sstevel@tonic-gate break; 16917c478bd9Sstevel@tonic-gate #endif 16927c478bd9Sstevel@tonic-gate #ifdef S_IFCHR 16937c478bd9Sstevel@tonic-gate case S_IFCHR: /* character special */ 16947c478bd9Sstevel@tonic-gate pmode[0] = 'c'; 16957c478bd9Sstevel@tonic-gate break; 16967c478bd9Sstevel@tonic-gate #endif 16977c478bd9Sstevel@tonic-gate #ifdef S_IFBLK 16987c478bd9Sstevel@tonic-gate case S_IFBLK: /* block special */ 16997c478bd9Sstevel@tonic-gate pmode[0] = 'b'; 17007c478bd9Sstevel@tonic-gate break; 17017c478bd9Sstevel@tonic-gate #endif 17027c478bd9Sstevel@tonic-gate #ifdef S_IFIFO 17037c478bd9Sstevel@tonic-gate case S_IFIFO: /* fifo special */ 17047c478bd9Sstevel@tonic-gate pmode[0] = 'p'; 17057c478bd9Sstevel@tonic-gate break; 17067c478bd9Sstevel@tonic-gate #endif 17077c478bd9Sstevel@tonic-gate #ifdef S_IFLNK 17087c478bd9Sstevel@tonic-gate case S_IFLNK: /* symbolic link */ 17097c478bd9Sstevel@tonic-gate pmode[0] = 'l'; 17107c478bd9Sstevel@tonic-gate break; 17117c478bd9Sstevel@tonic-gate #endif 17127c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK 17137c478bd9Sstevel@tonic-gate case S_IFSOCK: /* socket */ 17147c478bd9Sstevel@tonic-gate pmode[0] = 's'; 17157c478bd9Sstevel@tonic-gate break; 17167c478bd9Sstevel@tonic-gate #endif 17177c478bd9Sstevel@tonic-gate #ifdef S_IFDOOR 17187c478bd9Sstevel@tonic-gate case S_IFDOOR: /* door */ 17197c478bd9Sstevel@tonic-gate pmode[0] = 'D'; 17207c478bd9Sstevel@tonic-gate break; 17217c478bd9Sstevel@tonic-gate #endif 17227c478bd9Sstevel@tonic-gate #ifdef S_IFREG 17237c478bd9Sstevel@tonic-gate case S_IFREG: /* regular */ 17247c478bd9Sstevel@tonic-gate pmode[0] = '-'; 17257c478bd9Sstevel@tonic-gate break; 17267c478bd9Sstevel@tonic-gate #endif 17277c478bd9Sstevel@tonic-gate default: 17287c478bd9Sstevel@tonic-gate pmode[0] = '?'; 17297c478bd9Sstevel@tonic-gate break; 17307c478bd9Sstevel@tonic-gate } 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate for (who = 0; who < 3; who++) { 17337c478bd9Sstevel@tonic-gate int is_exec = stp->st_mode & permission(who, S_IEXEC)? 1 : 0; 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate if (stp->st_mode & permission(who, S_IREAD)) 17367c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 1] = 'r'; 17377c478bd9Sstevel@tonic-gate else 17387c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 1] = '-'; 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate if (stp->st_mode & permission(who, S_IWRITE)) 17417c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 2] = 'w'; 17427c478bd9Sstevel@tonic-gate else 17437c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 2] = '-'; 17447c478bd9Sstevel@tonic-gate 17457c478bd9Sstevel@tonic-gate if (stp->st_mode & special[who * 3]) 17467c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 3] = 174727d3a169SToomas Soome special[who * 3 + 1 + is_exec]; 17487c478bd9Sstevel@tonic-gate else if (is_exec) 17497c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 3] = 'x'; 17507c478bd9Sstevel@tonic-gate else 17517c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 3] = '-'; 17527c478bd9Sstevel@tonic-gate } 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate /* 17557c478bd9Sstevel@tonic-gate * Need to get the tail of the file name, since we have 17567c478bd9Sstevel@tonic-gate * already chdir()ed into the directory of the file 17577c478bd9Sstevel@tonic-gate */ 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate tailname = gettail(file); 17607c478bd9Sstevel@tonic-gate 1761fa9e4066Sahrens trivial = acl_trivial(tailname); 1762fa9e4066Sahrens if (trivial == -1) 1763fa9e4066Sahrens trivial = 0; 1764fa9e4066Sahrens 1765fa9e4066Sahrens if (trivial == 1) 17667c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 1] = '+'; 17677c478bd9Sstevel@tonic-gate else 17687c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 1] = ' '; 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 2] = '\0'; 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate /* 17737c478bd9Sstevel@tonic-gate * Prepare uname and gname. Always add a space afterwards 17747c478bd9Sstevel@tonic-gate * to keep columns from running together. 17757c478bd9Sstevel@tonic-gate */ 17767c478bd9Sstevel@tonic-gate cp = getname(stp->st_uid); 17777c478bd9Sstevel@tonic-gate if (cp != NULL) 17787c478bd9Sstevel@tonic-gate (void) sprintf(uname, "%-8s ", cp); 17797c478bd9Sstevel@tonic-gate else 1780f48205beScasper (void) sprintf(uname, "%-8u ", stp->st_uid); 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate cp = getgroup(stp->st_gid); 17837c478bd9Sstevel@tonic-gate if (cp != NULL) 17847c478bd9Sstevel@tonic-gate (void) sprintf(gname, "%-8s ", cp); 17857c478bd9Sstevel@tonic-gate else 1786f48205beScasper (void) sprintf(gname, "%-8u ", stp->st_gid); 17877c478bd9Sstevel@tonic-gate 17887c478bd9Sstevel@tonic-gate if (pmode[0] == 'b' || pmode[0] == 'c') 17897c478bd9Sstevel@tonic-gate (void) sprintf(fsize, "%3ld,%4ld", 179027d3a169SToomas Soome major(stp->st_rdev), minor(stp->st_rdev)); 17917c478bd9Sstevel@tonic-gate else { 17927c478bd9Sstevel@tonic-gate (void) sprintf(fsize, (stp->st_size < 100000000) ? 179327d3a169SToomas Soome "%8lld" : "%lld", stp->st_size); 17947c478bd9Sstevel@tonic-gate #ifdef S_IFLNK 17957c478bd9Sstevel@tonic-gate if (pmode[0] == 'l') { 17967c478bd9Sstevel@tonic-gate who = readlink(tailname, flink, sizeof (flink) - 1); 17977c478bd9Sstevel@tonic-gate 17987c478bd9Sstevel@tonic-gate if (who >= 0) 17997c478bd9Sstevel@tonic-gate flink[who] = '\0'; 18007c478bd9Sstevel@tonic-gate else 18017c478bd9Sstevel@tonic-gate flink[0] = '\0'; 18027c478bd9Sstevel@tonic-gate } 18037c478bd9Sstevel@tonic-gate #endif 18047c478bd9Sstevel@tonic-gate } 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate cp = ctime(&stp->st_mtime); 18077c478bd9Sstevel@tonic-gate if (stp->st_mtime < sixmonthsago || stp->st_mtime > now) 18087c478bd9Sstevel@tonic-gate (void) sprintf(ftime, "%-7.7s %-4.4s", cp + 4, cp + 20); 18097c478bd9Sstevel@tonic-gate else 18107c478bd9Sstevel@tonic-gate (void) sprintf(ftime, "%-12.12s", cp + 4); 18117c478bd9Sstevel@tonic-gate 18127c478bd9Sstevel@tonic-gate (void) printf((stp->st_ino < 100000) ? "%5llu " : 181327d3a169SToomas Soome "%llu ", stp->st_ino); /* inode # */ 18147c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK 18157c478bd9Sstevel@tonic-gate ksize = (long long) kbytes(ldbtob(stp->st_blocks)); /* kbytes */ 18167c478bd9Sstevel@tonic-gate #else 18177c478bd9Sstevel@tonic-gate ksize = (long long) kbytes(stp->st_size); /* kbytes */ 18187c478bd9Sstevel@tonic-gate #endif 18197c478bd9Sstevel@tonic-gate (void) printf((ksize < 10000) ? "%4lld " : "%lld ", ksize); 18207c478bd9Sstevel@tonic-gate #ifdef S_IFLNK 182127d3a169SToomas Soome (void) printf("%s %2ld %s%s%s %s %s%s%s\n", 182227d3a169SToomas Soome pmode, /* protection */ 182327d3a169SToomas Soome stp->st_nlink, /* # of links */ 182427d3a169SToomas Soome uname, /* owner */ 182527d3a169SToomas Soome gname, /* group */ 182627d3a169SToomas Soome fsize, /* # of bytes */ 182727d3a169SToomas Soome ftime, /* modify time */ 182827d3a169SToomas Soome file, /* name */ 182927d3a169SToomas Soome (pmode[0] == 'l') ? " -> " : "", 183027d3a169SToomas Soome (pmode[0] == 'l') ? flink : ""); /* symlink */ 18317c478bd9Sstevel@tonic-gate #else 183227d3a169SToomas Soome (void) printf("%s %2ld %s%s%s %s %s\n", 183327d3a169SToomas Soome pmode, /* protection */ 183427d3a169SToomas Soome stp->st_nlink, /* # of links */ 183527d3a169SToomas Soome uname, /* owner */ 183627d3a169SToomas Soome gname, /* group */ 183727d3a169SToomas Soome fsize, /* # of bytes */ 183827d3a169SToomas Soome ftime, /* modify time */ 183927d3a169SToomas Soome file); /* name */ 18407c478bd9Sstevel@tonic-gate #endif 18417c478bd9Sstevel@tonic-gate 18427c478bd9Sstevel@tonic-gate return (0); 18437c478bd9Sstevel@tonic-gate } 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate static char * 18467c478bd9Sstevel@tonic-gate new_string(char *s) 18477c478bd9Sstevel@tonic-gate { 18487c478bd9Sstevel@tonic-gate char *p = strdup(s); 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate if (p) 18517c478bd9Sstevel@tonic-gate return (p); 18527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: out of memory\n"), cmdname); 18537c478bd9Sstevel@tonic-gate exit(1); 18547c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 18557c478bd9Sstevel@tonic-gate } 18567c478bd9Sstevel@tonic-gate 18577c478bd9Sstevel@tonic-gate /* 18587c478bd9Sstevel@tonic-gate * Read remote file system types from REMOTE_FS into the 18597c478bd9Sstevel@tonic-gate * remote_fstypes array. 18607c478bd9Sstevel@tonic-gate */ 18617c478bd9Sstevel@tonic-gate static void 186227d3a169SToomas Soome init_remote_fs(void) 18637c478bd9Sstevel@tonic-gate { 18647c478bd9Sstevel@tonic-gate FILE *fp; 18657c478bd9Sstevel@tonic-gate char line_buf[LINEBUF_SIZE]; 18667c478bd9Sstevel@tonic-gate 18677c478bd9Sstevel@tonic-gate if ((fp = fopen(REMOTE_FS, "r")) == NULL) { 18687c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 18693d63ea05Sas gettext("%s: Warning: can't open %s, ignored\n"), 18703d63ea05Sas REMOTE_FS, cmdname); 18717c478bd9Sstevel@tonic-gate /* Use default string name for NFS */ 18727c478bd9Sstevel@tonic-gate remote_fstypes[fstype_index++] = "nfs"; 18737c478bd9Sstevel@tonic-gate return; 18747c478bd9Sstevel@tonic-gate } 18757c478bd9Sstevel@tonic-gate 18767c478bd9Sstevel@tonic-gate while (fgets(line_buf, sizeof (line_buf), fp) != NULL) { 18777c478bd9Sstevel@tonic-gate char buf[LINEBUF_SIZE]; 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate /* LINTED - unbounded string specifier */ 18807c478bd9Sstevel@tonic-gate (void) sscanf(line_buf, "%s", buf); 18817c478bd9Sstevel@tonic-gate remote_fstypes[fstype_index++] = new_string(buf); 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate if (fstype_index == N_FSTYPES) 18847c478bd9Sstevel@tonic-gate break; 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate (void) fclose(fp); 18877c478bd9Sstevel@tonic-gate } 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate #define NPERM 30 /* Largest machine */ 18907c478bd9Sstevel@tonic-gate 18917c478bd9Sstevel@tonic-gate /* 18927c478bd9Sstevel@tonic-gate * The PERM struct is the machine that builds permissions. The p_special 18937c478bd9Sstevel@tonic-gate * field contains what permissions need to be checked at run-time in 18947c478bd9Sstevel@tonic-gate * getmode(). This is one of 'X', 'u', 'g', or 'o'. It contains '\0' to 18957c478bd9Sstevel@tonic-gate * indicate normal processing. 18967c478bd9Sstevel@tonic-gate */ 18977c478bd9Sstevel@tonic-gate typedef struct PERMST { 18987c478bd9Sstevel@tonic-gate ushort_t p_who; /* Range of permission (e.g. ugo) */ 18997c478bd9Sstevel@tonic-gate ushort_t p_perm; /* Bits to turn on, off, assign */ 19007c478bd9Sstevel@tonic-gate uchar_t p_op; /* Operation: + - = */ 19017c478bd9Sstevel@tonic-gate uchar_t p_special; /* Special handling? */ 19027c478bd9Sstevel@tonic-gate } PERMST; 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate #ifndef S_ISVTX 19057c478bd9Sstevel@tonic-gate #define S_ISVTX 0 /* Not .1 */ 19067c478bd9Sstevel@tonic-gate #endif 19077c478bd9Sstevel@tonic-gate 19087c478bd9Sstevel@tonic-gate /* Mask values */ 19097c478bd9Sstevel@tonic-gate #define P_A (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) /* allbits */ 19107c478bd9Sstevel@tonic-gate #define P_U (S_ISUID|S_ISVTX|S_IRWXU) /* user */ 19117c478bd9Sstevel@tonic-gate #define P_G (S_ISGID|S_ISVTX|S_IRWXG) /* group */ 19127c478bd9Sstevel@tonic-gate #define P_O (S_ISVTX|S_IRWXO) /* other */ 19137c478bd9Sstevel@tonic-gate 19147c478bd9Sstevel@tonic-gate static int iswho(int c); 19157c478bd9Sstevel@tonic-gate static int isop(int c); 19167c478bd9Sstevel@tonic-gate static int isperm(PERMST *pp, int c); 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate static PERMST machine[NPERM]; /* Permission construction machine */ 19197c478bd9Sstevel@tonic-gate static PERMST *endp; /* Last used PERM structure */ 19207c478bd9Sstevel@tonic-gate 19217c478bd9Sstevel@tonic-gate static uint_t nowho; /* No who for this mode (DOS kludge) */ 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate /* 19247c478bd9Sstevel@tonic-gate * Read an ASCII string containing the symbolic/octal mode and 19257c478bd9Sstevel@tonic-gate * compile an automaton that recognizes it. The return value 19267c478bd9Sstevel@tonic-gate * is NULL if everything is OK, otherwise it is -1. 19277c478bd9Sstevel@tonic-gate */ 19287c478bd9Sstevel@tonic-gate static int 192927d3a169SToomas Soome readmode(const char *ascmode) 19307c478bd9Sstevel@tonic-gate { 19317c478bd9Sstevel@tonic-gate const char *amode = ascmode; 19327c478bd9Sstevel@tonic-gate PERMST *pp; 19337c478bd9Sstevel@tonic-gate int seen_X; 19347c478bd9Sstevel@tonic-gate 19357c478bd9Sstevel@tonic-gate nowho = 0; 19367c478bd9Sstevel@tonic-gate seen_X = 0; 19377c478bd9Sstevel@tonic-gate pp = &machine[0]; 19387c478bd9Sstevel@tonic-gate if (*amode >= '0' && *amode <= '7') { 19397c478bd9Sstevel@tonic-gate int mode; 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate mode = 0; 19427c478bd9Sstevel@tonic-gate while (*amode >= '0' && *amode <= '7') 19437c478bd9Sstevel@tonic-gate mode = (mode<<3) + *amode++ - '0'; 19447c478bd9Sstevel@tonic-gate if (*amode != '\0') 19457c478bd9Sstevel@tonic-gate return (-1); 19467c478bd9Sstevel@tonic-gate #if S_ISUID != 04000 || S_ISGID != 02000 || \ 19477c478bd9Sstevel@tonic-gate S_IRUSR != 0400 || S_IWUSR != 0200 || S_IXUSR != 0100 || \ 19487c478bd9Sstevel@tonic-gate S_IRGRP != 0040 || S_IWGRP != 0020 || S_IXGRP != 0010 || \ 19497c478bd9Sstevel@tonic-gate S_IROTH != 0004 || S_IWOTH != 0002 || S_IXOTH != 0001 19507c478bd9Sstevel@tonic-gate /* 19517c478bd9Sstevel@tonic-gate * There is no requirement of the octal mode bits being 19527c478bd9Sstevel@tonic-gate * the same as the S_ macros. 19537c478bd9Sstevel@tonic-gate */ 19547c478bd9Sstevel@tonic-gate { 19557c478bd9Sstevel@tonic-gate mode_t mapping[] = { 19567c478bd9Sstevel@tonic-gate S_IXOTH, S_IWOTH, S_IROTH, 19577c478bd9Sstevel@tonic-gate S_IXGRP, S_IWGRP, S_IRGRP, 19587c478bd9Sstevel@tonic-gate S_IXUSR, S_IWUSR, S_IRUSR, 19597c478bd9Sstevel@tonic-gate S_ISGID, S_ISUID, 19607c478bd9Sstevel@tonic-gate 0 19617c478bd9Sstevel@tonic-gate }; 19627c478bd9Sstevel@tonic-gate int i, newmode = 0; 19637c478bd9Sstevel@tonic-gate 19647c478bd9Sstevel@tonic-gate for (i = 0; mapping[i] != 0; i++) 19657c478bd9Sstevel@tonic-gate if (mode & (1<<i)) 19667c478bd9Sstevel@tonic-gate newmode |= mapping[i]; 19677c478bd9Sstevel@tonic-gate mode = newmode; 19687c478bd9Sstevel@tonic-gate } 19697c478bd9Sstevel@tonic-gate #endif 19707c478bd9Sstevel@tonic-gate pp->p_who = P_A; 19717c478bd9Sstevel@tonic-gate pp->p_perm = mode; 19727c478bd9Sstevel@tonic-gate pp->p_op = '='; 19737c478bd9Sstevel@tonic-gate } else for (;;) { 19747c478bd9Sstevel@tonic-gate int t; 19757c478bd9Sstevel@tonic-gate int who = 0; 19767c478bd9Sstevel@tonic-gate 19777c478bd9Sstevel@tonic-gate while ((t = iswho(*amode)) != 0) { 19787c478bd9Sstevel@tonic-gate ++amode; 19797c478bd9Sstevel@tonic-gate who |= t; 19807c478bd9Sstevel@tonic-gate } 19817c478bd9Sstevel@tonic-gate if (who == 0) { 19827c478bd9Sstevel@tonic-gate mode_t currmask; 19837c478bd9Sstevel@tonic-gate (void) umask(currmask = umask((mode_t)0)); 19847c478bd9Sstevel@tonic-gate 19857c478bd9Sstevel@tonic-gate /* 19867c478bd9Sstevel@tonic-gate * If no who specified, must use contents of 19877c478bd9Sstevel@tonic-gate * umask to determine which bits to flip. This 19887c478bd9Sstevel@tonic-gate * is POSIX/V7/BSD behaviour, but not SVID. 19897c478bd9Sstevel@tonic-gate */ 19907c478bd9Sstevel@tonic-gate who = (~currmask)&P_A; 19917c478bd9Sstevel@tonic-gate ++nowho; 19927c478bd9Sstevel@tonic-gate } else 19937c478bd9Sstevel@tonic-gate nowho = 0; 19947c478bd9Sstevel@tonic-gate samewho: 19957c478bd9Sstevel@tonic-gate if (!isop(pp->p_op = *amode++)) 19967c478bd9Sstevel@tonic-gate return (-1); 19977c478bd9Sstevel@tonic-gate pp->p_perm = 0; 19987c478bd9Sstevel@tonic-gate pp->p_special = 0; 19997c478bd9Sstevel@tonic-gate while ((t = isperm(pp, *amode)) != 0) { 20007c478bd9Sstevel@tonic-gate if (pp->p_special == 'X') { 20017c478bd9Sstevel@tonic-gate seen_X = 1; 20027c478bd9Sstevel@tonic-gate 20037c478bd9Sstevel@tonic-gate if (pp->p_perm != 0) { 20047c478bd9Sstevel@tonic-gate ushort_t op; 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate /* 20077c478bd9Sstevel@tonic-gate * Remember the 'who' for the previous 20087c478bd9Sstevel@tonic-gate * transformation. 20097c478bd9Sstevel@tonic-gate */ 20107c478bd9Sstevel@tonic-gate pp->p_who = who; 20117c478bd9Sstevel@tonic-gate pp->p_special = 0; 20127c478bd9Sstevel@tonic-gate 20137c478bd9Sstevel@tonic-gate op = pp->p_op; 20147c478bd9Sstevel@tonic-gate 20157c478bd9Sstevel@tonic-gate /* Keep 'X' separate */ 20167c478bd9Sstevel@tonic-gate ++pp; 20177c478bd9Sstevel@tonic-gate pp->p_special = 'X'; 20187c478bd9Sstevel@tonic-gate pp->p_op = op; 20197c478bd9Sstevel@tonic-gate } 20207c478bd9Sstevel@tonic-gate } else if (seen_X) { 20217c478bd9Sstevel@tonic-gate ushort_t op; 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate /* Remember the 'who' for the X */ 20247c478bd9Sstevel@tonic-gate pp->p_who = who; 20257c478bd9Sstevel@tonic-gate 20267c478bd9Sstevel@tonic-gate op = pp->p_op; 20277c478bd9Sstevel@tonic-gate 20287c478bd9Sstevel@tonic-gate /* Keep 'X' separate */ 20297c478bd9Sstevel@tonic-gate ++pp; 20307c478bd9Sstevel@tonic-gate pp->p_perm = 0; 20317c478bd9Sstevel@tonic-gate pp->p_special = 0; 20327c478bd9Sstevel@tonic-gate pp->p_op = op; 20337c478bd9Sstevel@tonic-gate } 20347c478bd9Sstevel@tonic-gate ++amode; 20357c478bd9Sstevel@tonic-gate pp->p_perm |= t; 20367c478bd9Sstevel@tonic-gate } 20377c478bd9Sstevel@tonic-gate 20387c478bd9Sstevel@tonic-gate /* 20397c478bd9Sstevel@tonic-gate * These returned 0, but were actually parsed, so 20407c478bd9Sstevel@tonic-gate * don't look at them again. 20417c478bd9Sstevel@tonic-gate */ 20427c478bd9Sstevel@tonic-gate switch (pp->p_special) { 20437c478bd9Sstevel@tonic-gate case 'u': 20447c478bd9Sstevel@tonic-gate case 'g': 20457c478bd9Sstevel@tonic-gate case 'o': 20467c478bd9Sstevel@tonic-gate ++amode; 20477c478bd9Sstevel@tonic-gate break; 20487c478bd9Sstevel@tonic-gate } 20497c478bd9Sstevel@tonic-gate pp->p_who = who; 20507c478bd9Sstevel@tonic-gate switch (*amode) { 20517c478bd9Sstevel@tonic-gate case '\0': 20527c478bd9Sstevel@tonic-gate break; 20537c478bd9Sstevel@tonic-gate 20547c478bd9Sstevel@tonic-gate case ',': 20557c478bd9Sstevel@tonic-gate ++amode; 20567c478bd9Sstevel@tonic-gate ++pp; 20577c478bd9Sstevel@tonic-gate continue; 20587c478bd9Sstevel@tonic-gate 20597c478bd9Sstevel@tonic-gate default: 20607c478bd9Sstevel@tonic-gate ++pp; 20617c478bd9Sstevel@tonic-gate goto samewho; 20627c478bd9Sstevel@tonic-gate } 20637c478bd9Sstevel@tonic-gate break; 20647c478bd9Sstevel@tonic-gate } 20657c478bd9Sstevel@tonic-gate endp = pp; 206627d3a169SToomas Soome return (0); 20677c478bd9Sstevel@tonic-gate } 20687c478bd9Sstevel@tonic-gate 20697c478bd9Sstevel@tonic-gate /* 20707c478bd9Sstevel@tonic-gate * Given a character from the mode, return the associated 20717c478bd9Sstevel@tonic-gate * value as who (user designation) mask or 0 if this isn't valid. 20727c478bd9Sstevel@tonic-gate */ 20737c478bd9Sstevel@tonic-gate static int 207427d3a169SToomas Soome iswho(int c) 20757c478bd9Sstevel@tonic-gate { 20767c478bd9Sstevel@tonic-gate switch (c) { 20777c478bd9Sstevel@tonic-gate case 'a': 20787c478bd9Sstevel@tonic-gate return (P_A); 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate case 'u': 20817c478bd9Sstevel@tonic-gate return (P_U); 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate case 'g': 20847c478bd9Sstevel@tonic-gate return (P_G); 20857c478bd9Sstevel@tonic-gate 20867c478bd9Sstevel@tonic-gate case 'o': 20877c478bd9Sstevel@tonic-gate return (P_O); 20887c478bd9Sstevel@tonic-gate 20897c478bd9Sstevel@tonic-gate default: 20907c478bd9Sstevel@tonic-gate return (0); 20917c478bd9Sstevel@tonic-gate } 20927c478bd9Sstevel@tonic-gate /* NOTREACHED */ 20937c478bd9Sstevel@tonic-gate } 20947c478bd9Sstevel@tonic-gate 20957c478bd9Sstevel@tonic-gate /* 20967c478bd9Sstevel@tonic-gate * Return non-zero if this is a valid op code 20977c478bd9Sstevel@tonic-gate * in a symbolic mode. 20987c478bd9Sstevel@tonic-gate */ 20997c478bd9Sstevel@tonic-gate static int 210027d3a169SToomas Soome isop(int c) 21017c478bd9Sstevel@tonic-gate { 21027c478bd9Sstevel@tonic-gate switch (c) { 21037c478bd9Sstevel@tonic-gate case '+': 21047c478bd9Sstevel@tonic-gate case '-': 21057c478bd9Sstevel@tonic-gate case '=': 21067c478bd9Sstevel@tonic-gate return (1); 21077c478bd9Sstevel@tonic-gate 21087c478bd9Sstevel@tonic-gate default: 21097c478bd9Sstevel@tonic-gate return (0); 21107c478bd9Sstevel@tonic-gate } 21117c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21127c478bd9Sstevel@tonic-gate } 21137c478bd9Sstevel@tonic-gate 21147c478bd9Sstevel@tonic-gate /* 21157c478bd9Sstevel@tonic-gate * Return the permission bits implied by this character or 0 21167c478bd9Sstevel@tonic-gate * if it isn't valid. Also returns 0 when the pseudo-permissions 'u', 'g', or 21177c478bd9Sstevel@tonic-gate * 'o' are used, and sets pp->p_special to the one used. 21187c478bd9Sstevel@tonic-gate */ 21197c478bd9Sstevel@tonic-gate static int 212027d3a169SToomas Soome isperm(PERMST *pp, int c) 21217c478bd9Sstevel@tonic-gate { 21227c478bd9Sstevel@tonic-gate switch (c) { 21237c478bd9Sstevel@tonic-gate case 'u': 21247c478bd9Sstevel@tonic-gate case 'g': 21257c478bd9Sstevel@tonic-gate case 'o': 21267c478bd9Sstevel@tonic-gate pp->p_special = c; 21277c478bd9Sstevel@tonic-gate return (0); 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate case 'r': 21307c478bd9Sstevel@tonic-gate return (S_IRUSR|S_IRGRP|S_IROTH); 21317c478bd9Sstevel@tonic-gate 21327c478bd9Sstevel@tonic-gate case 'w': 21337c478bd9Sstevel@tonic-gate return (S_IWUSR|S_IWGRP|S_IWOTH); 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate case 'x': 21367c478bd9Sstevel@tonic-gate return (S_IXUSR|S_IXGRP|S_IXOTH); 21377c478bd9Sstevel@tonic-gate 21387c478bd9Sstevel@tonic-gate #if S_ISVTX != 0 21397c478bd9Sstevel@tonic-gate case 't': 21407c478bd9Sstevel@tonic-gate return (S_ISVTX); 21417c478bd9Sstevel@tonic-gate #endif 21427c478bd9Sstevel@tonic-gate 21437c478bd9Sstevel@tonic-gate case 'X': 21447c478bd9Sstevel@tonic-gate pp->p_special = 'X'; 21457c478bd9Sstevel@tonic-gate return (S_IXUSR|S_IXGRP|S_IXOTH); 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate #if S_ISVTX != 0 21487c478bd9Sstevel@tonic-gate case 'a': 21497c478bd9Sstevel@tonic-gate return (S_ISVTX); 21507c478bd9Sstevel@tonic-gate #endif 21517c478bd9Sstevel@tonic-gate 21527c478bd9Sstevel@tonic-gate case 'h': 21537c478bd9Sstevel@tonic-gate return (S_ISUID); 21547c478bd9Sstevel@tonic-gate 21557c478bd9Sstevel@tonic-gate /* 21567c478bd9Sstevel@tonic-gate * This change makes: 21577c478bd9Sstevel@tonic-gate * chmod +s file 21587c478bd9Sstevel@tonic-gate * set the system bit on dos but means that 21597c478bd9Sstevel@tonic-gate * chmod u+s file 21607c478bd9Sstevel@tonic-gate * chmod g+s file 21617c478bd9Sstevel@tonic-gate * chmod a+s file 21627c478bd9Sstevel@tonic-gate * are all like UNIX. 21637c478bd9Sstevel@tonic-gate */ 21647c478bd9Sstevel@tonic-gate case 's': 21657c478bd9Sstevel@tonic-gate return (nowho ? S_ISGID : S_ISGID|S_ISUID); 21667c478bd9Sstevel@tonic-gate 21677c478bd9Sstevel@tonic-gate default: 21687c478bd9Sstevel@tonic-gate return (0); 21697c478bd9Sstevel@tonic-gate } 21707c478bd9Sstevel@tonic-gate /* NOTREACHED */ 21717c478bd9Sstevel@tonic-gate } 21727c478bd9Sstevel@tonic-gate 21737c478bd9Sstevel@tonic-gate /* 21747c478bd9Sstevel@tonic-gate * Execute the automaton that is created by readmode() 21757c478bd9Sstevel@tonic-gate * to generate the final mode that will be used. This 21767c478bd9Sstevel@tonic-gate * code is passed a starting mode that is usually the original 21777c478bd9Sstevel@tonic-gate * mode of the file being changed (or 0). Note that this mode must contain 21787c478bd9Sstevel@tonic-gate * the file-type bits as well, so that S_ISDIR will succeed on directories. 21797c478bd9Sstevel@tonic-gate */ 21807c478bd9Sstevel@tonic-gate static mode_t 21817c478bd9Sstevel@tonic-gate getmode(mode_t startmode) 21827c478bd9Sstevel@tonic-gate { 21837c478bd9Sstevel@tonic-gate PERMST *pp; 21847c478bd9Sstevel@tonic-gate mode_t temp; 21857c478bd9Sstevel@tonic-gate mode_t perm; 21867c478bd9Sstevel@tonic-gate 21877c478bd9Sstevel@tonic-gate for (pp = &machine[0]; pp <= endp; ++pp) { 21887c478bd9Sstevel@tonic-gate perm = (mode_t)0; 21897c478bd9Sstevel@tonic-gate /* 21907c478bd9Sstevel@tonic-gate * For the special modes 'u', 'g' and 'o', the named portion 21917c478bd9Sstevel@tonic-gate * of the mode refers to after the previous clause has been 21927c478bd9Sstevel@tonic-gate * processed, while the 'X' mode refers to the contents of the 21937c478bd9Sstevel@tonic-gate * mode before any clauses have been processed. 21947c478bd9Sstevel@tonic-gate * 21957c478bd9Sstevel@tonic-gate * References: P1003.2/D11.2, Section 4.7.7, 21967c478bd9Sstevel@tonic-gate * lines 2568-2570, 2578-2583 21977c478bd9Sstevel@tonic-gate */ 21987c478bd9Sstevel@tonic-gate switch (pp->p_special) { 21997c478bd9Sstevel@tonic-gate case 'u': 22007c478bd9Sstevel@tonic-gate temp = startmode & S_IRWXU; 22017c478bd9Sstevel@tonic-gate if (temp & (S_IRUSR|S_IRGRP|S_IROTH)) 22027c478bd9Sstevel@tonic-gate perm |= ((S_IRUSR|S_IRGRP|S_IROTH) & 22037c478bd9Sstevel@tonic-gate pp->p_who); 22047c478bd9Sstevel@tonic-gate if (temp & (S_IWUSR|S_IWGRP|S_IWOTH)) 22057c478bd9Sstevel@tonic-gate perm |= ((S_IWUSR|S_IWGRP|S_IWOTH) & pp->p_who); 22067c478bd9Sstevel@tonic-gate if (temp & (S_IXUSR|S_IXGRP|S_IXOTH)) 22077c478bd9Sstevel@tonic-gate perm |= ((S_IXUSR|S_IXGRP|S_IXOTH) & pp->p_who); 22087c478bd9Sstevel@tonic-gate break; 22097c478bd9Sstevel@tonic-gate 22107c478bd9Sstevel@tonic-gate case 'g': 22117c478bd9Sstevel@tonic-gate temp = startmode & S_IRWXG; 22127c478bd9Sstevel@tonic-gate if (temp & (S_IRUSR|S_IRGRP|S_IROTH)) 22137c478bd9Sstevel@tonic-gate perm |= ((S_IRUSR|S_IRGRP|S_IROTH) & pp->p_who); 22147c478bd9Sstevel@tonic-gate if (temp & (S_IWUSR|S_IWGRP|S_IWOTH)) 22157c478bd9Sstevel@tonic-gate perm |= ((S_IWUSR|S_IWGRP|S_IWOTH) & pp->p_who); 22167c478bd9Sstevel@tonic-gate if (temp & (S_IXUSR|S_IXGRP|S_IXOTH)) 22177c478bd9Sstevel@tonic-gate perm |= ((S_IXUSR|S_IXGRP|S_IXOTH) & pp->p_who); 22187c478bd9Sstevel@tonic-gate break; 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate case 'o': 22217c478bd9Sstevel@tonic-gate temp = startmode & S_IRWXO; 22227c478bd9Sstevel@tonic-gate if (temp & (S_IRUSR|S_IRGRP|S_IROTH)) 22237c478bd9Sstevel@tonic-gate perm |= ((S_IRUSR|S_IRGRP|S_IROTH) & pp->p_who); 22247c478bd9Sstevel@tonic-gate if (temp & (S_IWUSR|S_IWGRP|S_IWOTH)) 22257c478bd9Sstevel@tonic-gate perm |= ((S_IWUSR|S_IWGRP|S_IWOTH) & pp->p_who); 22267c478bd9Sstevel@tonic-gate if (temp & (S_IXUSR|S_IXGRP|S_IXOTH)) 22277c478bd9Sstevel@tonic-gate perm |= ((S_IXUSR|S_IXGRP|S_IXOTH) & pp->p_who); 22287c478bd9Sstevel@tonic-gate break; 22297c478bd9Sstevel@tonic-gate 22307c478bd9Sstevel@tonic-gate case 'X': 22317c478bd9Sstevel@tonic-gate perm = pp->p_perm; 22327c478bd9Sstevel@tonic-gate break; 22337c478bd9Sstevel@tonic-gate 22347c478bd9Sstevel@tonic-gate default: 22357c478bd9Sstevel@tonic-gate perm = pp->p_perm; 22367c478bd9Sstevel@tonic-gate break; 22377c478bd9Sstevel@tonic-gate } 22387c478bd9Sstevel@tonic-gate switch (pp->p_op) { 22397c478bd9Sstevel@tonic-gate case '-': 22407c478bd9Sstevel@tonic-gate startmode &= ~(perm & pp->p_who); 22417c478bd9Sstevel@tonic-gate break; 22427c478bd9Sstevel@tonic-gate 22437c478bd9Sstevel@tonic-gate case '=': 22447c478bd9Sstevel@tonic-gate startmode &= ~pp->p_who; 22457c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 22467c478bd9Sstevel@tonic-gate case '+': 22477c478bd9Sstevel@tonic-gate startmode |= (perm & pp->p_who); 22487c478bd9Sstevel@tonic-gate break; 22497c478bd9Sstevel@tonic-gate } 22507c478bd9Sstevel@tonic-gate } 22517c478bd9Sstevel@tonic-gate return (startmode); 22527c478bd9Sstevel@tonic-gate } 22537c478bd9Sstevel@tonic-gate 22547c478bd9Sstevel@tonic-gate /* 22557c478bd9Sstevel@tonic-gate * Returns the last component of a path name, unless it is 22567c478bd9Sstevel@tonic-gate * an absolute path, in which case it returns the whole path 22577c478bd9Sstevel@tonic-gate */ 225827d3a169SToomas Soome static const char * 225927d3a169SToomas Soome gettail(const char *fname) 22607c478bd9Sstevel@tonic-gate { 226127d3a169SToomas Soome const char *base = fname; 22627c478bd9Sstevel@tonic-gate 22637c478bd9Sstevel@tonic-gate if (*fname != '/') { 22647c478bd9Sstevel@tonic-gate if ((base = strrchr(fname, '/')) != NULL) 22657c478bd9Sstevel@tonic-gate base++; 22667c478bd9Sstevel@tonic-gate else 22677c478bd9Sstevel@tonic-gate base = fname; 22687c478bd9Sstevel@tonic-gate } 22697c478bd9Sstevel@tonic-gate return (base); 22707c478bd9Sstevel@tonic-gate } 2271