1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 30*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate /* Parts of this product may be derived from */ 34*7c478bd9Sstevel@tonic-gate /* Mortice Kern Systems Inc. and Berkeley 4.3 BSD systems. */ 35*7c478bd9Sstevel@tonic-gate /* licensed from Mortice Kern Systems Inc. and */ 36*7c478bd9Sstevel@tonic-gate /* the University of California. */ 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate /* 39*7c478bd9Sstevel@tonic-gate * Copyright 1985, 1990 by Mortice Kern Systems Inc. All rights reserved. 40*7c478bd9Sstevel@tonic-gate */ 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate #include <stdio.h> 43*7c478bd9Sstevel@tonic-gate #include <errno.h> 44*7c478bd9Sstevel@tonic-gate #include <pwd.h> 45*7c478bd9Sstevel@tonic-gate #include <grp.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/acl.h> 50*7c478bd9Sstevel@tonic-gate #include <limits.h> 51*7c478bd9Sstevel@tonic-gate #include <unistd.h> 52*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 53*7c478bd9Sstevel@tonic-gate #include <locale.h> 54*7c478bd9Sstevel@tonic-gate #include <string.h> 55*7c478bd9Sstevel@tonic-gate #include <strings.h> 56*7c478bd9Sstevel@tonic-gate #include <libgen.h> 57*7c478bd9Sstevel@tonic-gate #include <ctype.h> 58*7c478bd9Sstevel@tonic-gate #include <wait.h> 59*7c478bd9Sstevel@tonic-gate #include <fnmatch.h> 60*7c478bd9Sstevel@tonic-gate #include <langinfo.h> 61*7c478bd9Sstevel@tonic-gate #include <ftw.h> 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate #define A_DAY (long)(60*60*24) /* a day full of seconds */ 65*7c478bd9Sstevel@tonic-gate #define BLKSIZ 512 66*7c478bd9Sstevel@tonic-gate #define round(x, s) (((x)+(s)-1)&~((s)-1)) 67*7c478bd9Sstevel@tonic-gate #ifndef FTW_SLN 68*7c478bd9Sstevel@tonic-gate #define FTW_SLN 7 69*7c478bd9Sstevel@tonic-gate #endif 70*7c478bd9Sstevel@tonic-gate #define LINEBUF_SIZE LINE_MAX /* input or output lines */ 71*7c478bd9Sstevel@tonic-gate #define REMOTE_FS "/etc/dfs/fstypes" 72*7c478bd9Sstevel@tonic-gate #define N_FSTYPES 20 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate /* 75*7c478bd9Sstevel@tonic-gate * This is the list of operations 76*7c478bd9Sstevel@tonic-gate * F_USER and F_GROUP are named to avoid conflict with USER and GROUP defined 77*7c478bd9Sstevel@tonic-gate * in sys/acl.h 78*7c478bd9Sstevel@tonic-gate */ 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate enum Command 81*7c478bd9Sstevel@tonic-gate { 82*7c478bd9Sstevel@tonic-gate PRINT, DEPTH, LOCAL, MOUNT, ATIME, MTIME, CTIME, NEWER, 83*7c478bd9Sstevel@tonic-gate NAME, F_USER, F_GROUP, INUM, SIZE, LINKS, PERM, EXEC, OK, CPIO, NCPIO, 84*7c478bd9Sstevel@tonic-gate TYPE, AND, OR, NOT, LPAREN, RPAREN, CSIZE, VARARGS, FOLLOW, 85*7c478bd9Sstevel@tonic-gate PRUNE, NOUSER, NOGRP, FSTYPE, LS, XATTR, ACL 86*7c478bd9Sstevel@tonic-gate }; 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate enum Type 89*7c478bd9Sstevel@tonic-gate { 90*7c478bd9Sstevel@tonic-gate Unary, Id, Num, Str, Exec, Cpio, Op 91*7c478bd9Sstevel@tonic-gate }; 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate struct Args 94*7c478bd9Sstevel@tonic-gate { 95*7c478bd9Sstevel@tonic-gate char name[10]; 96*7c478bd9Sstevel@tonic-gate enum Command action; 97*7c478bd9Sstevel@tonic-gate enum Type type; 98*7c478bd9Sstevel@tonic-gate }; 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate /* 101*7c478bd9Sstevel@tonic-gate * Except for pathnames, these are the only legal arguments 102*7c478bd9Sstevel@tonic-gate */ 103*7c478bd9Sstevel@tonic-gate static struct Args commands[] = 104*7c478bd9Sstevel@tonic-gate { 105*7c478bd9Sstevel@tonic-gate "!", NOT, Op, 106*7c478bd9Sstevel@tonic-gate "(", LPAREN, Unary, 107*7c478bd9Sstevel@tonic-gate ")", RPAREN, Unary, 108*7c478bd9Sstevel@tonic-gate "-a", AND, Op, 109*7c478bd9Sstevel@tonic-gate "-atime", ATIME, Num, 110*7c478bd9Sstevel@tonic-gate "-cpio", CPIO, Cpio, 111*7c478bd9Sstevel@tonic-gate "-ctime", CTIME, Num, 112*7c478bd9Sstevel@tonic-gate "-depth", DEPTH, Unary, 113*7c478bd9Sstevel@tonic-gate "-exec", EXEC, Exec, 114*7c478bd9Sstevel@tonic-gate "-follow", FOLLOW, Unary, 115*7c478bd9Sstevel@tonic-gate "-group", F_GROUP, Num, 116*7c478bd9Sstevel@tonic-gate "-inum", INUM, Num, 117*7c478bd9Sstevel@tonic-gate "-links", LINKS, Num, 118*7c478bd9Sstevel@tonic-gate "-local", LOCAL, Unary, 119*7c478bd9Sstevel@tonic-gate "-mount", MOUNT, Unary, 120*7c478bd9Sstevel@tonic-gate "-mtime", MTIME, Num, 121*7c478bd9Sstevel@tonic-gate "-name", NAME, Str, 122*7c478bd9Sstevel@tonic-gate "-ncpio", NCPIO, Cpio, 123*7c478bd9Sstevel@tonic-gate "-newer", NEWER, Str, 124*7c478bd9Sstevel@tonic-gate "-o", OR, Op, 125*7c478bd9Sstevel@tonic-gate "-ok", OK, Exec, 126*7c478bd9Sstevel@tonic-gate "-perm", PERM, Num, 127*7c478bd9Sstevel@tonic-gate "-print", PRINT, Unary, 128*7c478bd9Sstevel@tonic-gate "-size", SIZE, Num, 129*7c478bd9Sstevel@tonic-gate "-type", TYPE, Num, 130*7c478bd9Sstevel@tonic-gate "-xdev", MOUNT, Unary, 131*7c478bd9Sstevel@tonic-gate "-user", F_USER, Num, 132*7c478bd9Sstevel@tonic-gate "-prune", PRUNE, Unary, 133*7c478bd9Sstevel@tonic-gate "-nouser", NOUSER, Unary, 134*7c478bd9Sstevel@tonic-gate "-nogroup", NOGRP, Unary, 135*7c478bd9Sstevel@tonic-gate "-fstype", FSTYPE, Str, 136*7c478bd9Sstevel@tonic-gate "-ls", LS, Unary, 137*7c478bd9Sstevel@tonic-gate "-xattr", XATTR, Unary, 138*7c478bd9Sstevel@tonic-gate "-acl", ACL, Unary, 139*7c478bd9Sstevel@tonic-gate NULL, 0, 0 140*7c478bd9Sstevel@tonic-gate }; 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate union Item 143*7c478bd9Sstevel@tonic-gate { 144*7c478bd9Sstevel@tonic-gate struct Node *np; 145*7c478bd9Sstevel@tonic-gate struct Arglist *vp; 146*7c478bd9Sstevel@tonic-gate time_t t; 147*7c478bd9Sstevel@tonic-gate char *cp; 148*7c478bd9Sstevel@tonic-gate char **ap; 149*7c478bd9Sstevel@tonic-gate long l; 150*7c478bd9Sstevel@tonic-gate int i; 151*7c478bd9Sstevel@tonic-gate long long ll; 152*7c478bd9Sstevel@tonic-gate }; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate struct Node 155*7c478bd9Sstevel@tonic-gate { 156*7c478bd9Sstevel@tonic-gate struct Node *next; 157*7c478bd9Sstevel@tonic-gate enum Command action; 158*7c478bd9Sstevel@tonic-gate enum Type type; 159*7c478bd9Sstevel@tonic-gate union Item first; 160*7c478bd9Sstevel@tonic-gate union Item second; 161*7c478bd9Sstevel@tonic-gate }; 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate /* if no -print, -exec or -ok replace "expression" with "(expression) -print" */ 164*7c478bd9Sstevel@tonic-gate static struct Node PRINT_NODE = { 0, PRINT, 0, 0}; 165*7c478bd9Sstevel@tonic-gate static struct Node LPAREN_NODE = { 0, LPAREN, 0, 0}; 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate /* 169*7c478bd9Sstevel@tonic-gate * Prototype variable size arglist buffer 170*7c478bd9Sstevel@tonic-gate */ 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate struct Arglist 173*7c478bd9Sstevel@tonic-gate { 174*7c478bd9Sstevel@tonic-gate struct Arglist *next; 175*7c478bd9Sstevel@tonic-gate char *end; 176*7c478bd9Sstevel@tonic-gate char *nextstr; 177*7c478bd9Sstevel@tonic-gate char **firstvar; 178*7c478bd9Sstevel@tonic-gate char **nextvar; 179*7c478bd9Sstevel@tonic-gate char *arglist[1]; 180*7c478bd9Sstevel@tonic-gate }; 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate static int compile(); 184*7c478bd9Sstevel@tonic-gate static int execute(); 185*7c478bd9Sstevel@tonic-gate static int doexec(); 186*7c478bd9Sstevel@tonic-gate static struct Args *lookup(); 187*7c478bd9Sstevel@tonic-gate static int ok(); 188*7c478bd9Sstevel@tonic-gate static void usage(); 189*7c478bd9Sstevel@tonic-gate static struct Arglist *varargs(); 190*7c478bd9Sstevel@tonic-gate static int list(); 191*7c478bd9Sstevel@tonic-gate static char *getgroup(); 192*7c478bd9Sstevel@tonic-gate static FILE *cmdopen(); 193*7c478bd9Sstevel@tonic-gate static int cmdclose(); 194*7c478bd9Sstevel@tonic-gate static char *getshell(); 195*7c478bd9Sstevel@tonic-gate static void init_remote_fs(); 196*7c478bd9Sstevel@tonic-gate static char *getname(); 197*7c478bd9Sstevel@tonic-gate static int readmode(); 198*7c478bd9Sstevel@tonic-gate static mode_t getmode(); 199*7c478bd9Sstevel@tonic-gate static char *gettail(); 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate static int walkflags = FTW_CHDIR|FTW_PHYS|FTW_ANYERR; 203*7c478bd9Sstevel@tonic-gate static struct Node *savetnode; 204*7c478bd9Sstevel@tonic-gate static struct Node *topnode; 205*7c478bd9Sstevel@tonic-gate static struct Node *freenode; /* next free node we may use later */ 206*7c478bd9Sstevel@tonic-gate static char *cpio[] = { "cpio", "-o", 0 }; 207*7c478bd9Sstevel@tonic-gate static char *ncpio[] = { "cpio", "-oc", 0 }; 208*7c478bd9Sstevel@tonic-gate static char *cpiol[] = { "cpio", "-oL", 0 }; 209*7c478bd9Sstevel@tonic-gate static char *ncpiol[] = { "cpio", "-ocL", 0 }; 210*7c478bd9Sstevel@tonic-gate static time_t now; 211*7c478bd9Sstevel@tonic-gate static FILE *output; 212*7c478bd9Sstevel@tonic-gate static char *dummyarg = (char *)-1; 213*7c478bd9Sstevel@tonic-gate static int lastval; 214*7c478bd9Sstevel@tonic-gate static int varsize; 215*7c478bd9Sstevel@tonic-gate static struct Arglist *lastlist; 216*7c478bd9Sstevel@tonic-gate static char *cmdname; 217*7c478bd9Sstevel@tonic-gate static char *remote_fstypes[N_FSTYPES+1]; 218*7c478bd9Sstevel@tonic-gate static int fstype_index = 0; 219*7c478bd9Sstevel@tonic-gate static int action_expression = 0; /* -print, -exec, or -ok */ 220*7c478bd9Sstevel@tonic-gate static int error = 0; 221*7c478bd9Sstevel@tonic-gate static int paren_cnt = 0; /* keeps track of parentheses */ 222*7c478bd9Sstevel@tonic-gate static int hflag = 0; 223*7c478bd9Sstevel@tonic-gate static int lflag = 0; 224*7c478bd9Sstevel@tonic-gate static int varexecrc = 0; 225*7c478bd9Sstevel@tonic-gate extern char **environ; 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate int 228*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 229*7c478bd9Sstevel@tonic-gate { 230*7c478bd9Sstevel@tonic-gate char *cp; 231*7c478bd9Sstevel@tonic-gate int c; 232*7c478bd9Sstevel@tonic-gate int paths; 233*7c478bd9Sstevel@tonic-gate char *cwdpath; 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 236*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 237*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 238*7c478bd9Sstevel@tonic-gate #endif 239*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate cmdname = argv[0]; 242*7c478bd9Sstevel@tonic-gate if (time(&now) == (time_t)(-1)) { 243*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: time() %s\n"), 244*7c478bd9Sstevel@tonic-gate cmdname, strerror(errno)); 245*7c478bd9Sstevel@tonic-gate exit(1); 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "HL")) != -1) { 248*7c478bd9Sstevel@tonic-gate switch (c) { 249*7c478bd9Sstevel@tonic-gate case 'H': 250*7c478bd9Sstevel@tonic-gate hflag = 1; 251*7c478bd9Sstevel@tonic-gate lflag = 0; 252*7c478bd9Sstevel@tonic-gate break; 253*7c478bd9Sstevel@tonic-gate case 'L': 254*7c478bd9Sstevel@tonic-gate hflag = 0; 255*7c478bd9Sstevel@tonic-gate lflag = 1; 256*7c478bd9Sstevel@tonic-gate break; 257*7c478bd9Sstevel@tonic-gate case '?': 258*7c478bd9Sstevel@tonic-gate usage(); 259*7c478bd9Sstevel@tonic-gate break; 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate } 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate argc -= optind; 264*7c478bd9Sstevel@tonic-gate argv += optind; 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate if (argc < 1) { 267*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 268*7c478bd9Sstevel@tonic-gate gettext("%s: insufficient number of arguments\n"), cmdname); 269*7c478bd9Sstevel@tonic-gate usage(); 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate for (paths = 0; (cp = argv[paths]) != 0; ++paths) { 273*7c478bd9Sstevel@tonic-gate if (*cp == '-') 274*7c478bd9Sstevel@tonic-gate break; 275*7c478bd9Sstevel@tonic-gate else if ((*cp == '!' || *cp == '(') && *(cp+1) == 0) 276*7c478bd9Sstevel@tonic-gate break; 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate if (paths == 0) /* no path-list */ 280*7c478bd9Sstevel@tonic-gate usage(); 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate output = stdout; 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate /* lflag is the same as -follow */ 285*7c478bd9Sstevel@tonic-gate if (lflag) 286*7c478bd9Sstevel@tonic-gate walkflags &= ~FTW_PHYS; 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate /* allocate enough space for the compiler */ 289*7c478bd9Sstevel@tonic-gate topnode = malloc((argc + 1) * sizeof (struct Node)); 290*7c478bd9Sstevel@tonic-gate savetnode = malloc((argc + 1) * sizeof (struct Node)); 291*7c478bd9Sstevel@tonic-gate (void) memset(topnode, 0, (argc + 1) * sizeof (struct Node)); 292*7c478bd9Sstevel@tonic-gate (void) memset(savetnode, 0, (argc + 1) * sizeof (struct Node)); 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate if (compile(argv + paths, topnode, &action_expression) == 0) { 295*7c478bd9Sstevel@tonic-gate /* no expression, default to -print */ 296*7c478bd9Sstevel@tonic-gate (void) memcpy(topnode, &PRINT_NODE, sizeof (struct Node)); 297*7c478bd9Sstevel@tonic-gate } else if (!action_expression) { 298*7c478bd9Sstevel@tonic-gate /* 299*7c478bd9Sstevel@tonic-gate * if no action expression, insert an LPAREN node above topnode, 300*7c478bd9Sstevel@tonic-gate * with a PRINT node as its next node 301*7c478bd9Sstevel@tonic-gate */ 302*7c478bd9Sstevel@tonic-gate struct Node *savenode; 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate if (freenode == NULL) { 305*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: can't append -print" 306*7c478bd9Sstevel@tonic-gate " implicitly; try explicit -print option\n"), 307*7c478bd9Sstevel@tonic-gate cmdname); 308*7c478bd9Sstevel@tonic-gate exit(1); 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate savenode = topnode; 311*7c478bd9Sstevel@tonic-gate topnode = freenode++; 312*7c478bd9Sstevel@tonic-gate (void) memcpy(topnode, &LPAREN_NODE, sizeof (struct Node)); 313*7c478bd9Sstevel@tonic-gate topnode->next = freenode; 314*7c478bd9Sstevel@tonic-gate topnode->first.np = savenode; 315*7c478bd9Sstevel@tonic-gate (void) memcpy(topnode->next, &PRINT_NODE, sizeof (struct Node)); 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate (void) memcpy(savetnode, topnode, ((argc + 1) * sizeof (struct Node))); 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate while (paths--) { 320*7c478bd9Sstevel@tonic-gate char *curpath; 321*7c478bd9Sstevel@tonic-gate struct stat sb; 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate curpath = *(argv++); 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate /* 326*7c478bd9Sstevel@tonic-gate * If -H is specified, it means we walk the first 327*7c478bd9Sstevel@tonic-gate * level (pathname on command line) logically, following 328*7c478bd9Sstevel@tonic-gate * symlinks, but lower levels are walked physically. 329*7c478bd9Sstevel@tonic-gate * We use our own secret interface to nftw() to change 330*7c478bd9Sstevel@tonic-gate * the from stat to lstat after the top level is walked. 331*7c478bd9Sstevel@tonic-gate */ 332*7c478bd9Sstevel@tonic-gate if (hflag) { 333*7c478bd9Sstevel@tonic-gate if (stat(curpath, &sb) < 0 && errno == ENOENT) 334*7c478bd9Sstevel@tonic-gate walkflags &= ~FTW_HOPTION; 335*7c478bd9Sstevel@tonic-gate else 336*7c478bd9Sstevel@tonic-gate walkflags |= FTW_HOPTION; 337*7c478bd9Sstevel@tonic-gate } 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate /* 340*7c478bd9Sstevel@tonic-gate * We need this check as nftw needs a CWD and we have no 341*7c478bd9Sstevel@tonic-gate * way of returning back from that code with a meaningful 342*7c478bd9Sstevel@tonic-gate * error related to this 343*7c478bd9Sstevel@tonic-gate */ 344*7c478bd9Sstevel@tonic-gate if ((cwdpath = getcwd(NULL, PATH_MAX)) == NULL) { 345*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 346*7c478bd9Sstevel@tonic-gate gettext("%s : cannot get the current working " 347*7c478bd9Sstevel@tonic-gate "directory\n"), cmdname); 348*7c478bd9Sstevel@tonic-gate exit(1); 349*7c478bd9Sstevel@tonic-gate } else 350*7c478bd9Sstevel@tonic-gate free(cwdpath); 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate if (nftw(curpath, execute, 1000, walkflags)) { 354*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 355*7c478bd9Sstevel@tonic-gate gettext("%s: cannot open %s: %s\n"), 356*7c478bd9Sstevel@tonic-gate cmdname, curpath, strerror(errno)); 357*7c478bd9Sstevel@tonic-gate error = 1; 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate if (paths > 1) 361*7c478bd9Sstevel@tonic-gate (void) memcpy(topnode, savetnode, 362*7c478bd9Sstevel@tonic-gate ((argc + 1) * sizeof (struct Node))); 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate /* execute any remaining variable length lists */ 366*7c478bd9Sstevel@tonic-gate while (lastlist) { 367*7c478bd9Sstevel@tonic-gate if (lastlist->end != lastlist->nextstr) { 368*7c478bd9Sstevel@tonic-gate *lastlist->nextvar = 0; 369*7c478bd9Sstevel@tonic-gate (void) doexec((char *)0, lastlist->arglist); 370*7c478bd9Sstevel@tonic-gate } 371*7c478bd9Sstevel@tonic-gate lastlist = lastlist->next; 372*7c478bd9Sstevel@tonic-gate } 373*7c478bd9Sstevel@tonic-gate if (output != stdout) 374*7c478bd9Sstevel@tonic-gate return (cmdclose(output)); 375*7c478bd9Sstevel@tonic-gate return ((varexecrc != 0) ? varexecrc : error); 376*7c478bd9Sstevel@tonic-gate } 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate /* 379*7c478bd9Sstevel@tonic-gate * compile the arguments 380*7c478bd9Sstevel@tonic-gate */ 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate static int 383*7c478bd9Sstevel@tonic-gate compile(argv, np, actionp) 384*7c478bd9Sstevel@tonic-gate char **argv; 385*7c478bd9Sstevel@tonic-gate struct Node *np; 386*7c478bd9Sstevel@tonic-gate int *actionp; 387*7c478bd9Sstevel@tonic-gate { 388*7c478bd9Sstevel@tonic-gate char *b; 389*7c478bd9Sstevel@tonic-gate char **av; 390*7c478bd9Sstevel@tonic-gate struct Node *oldnp = topnode; 391*7c478bd9Sstevel@tonic-gate struct Args *argp; 392*7c478bd9Sstevel@tonic-gate char **com; 393*7c478bd9Sstevel@tonic-gate int i; 394*7c478bd9Sstevel@tonic-gate enum Command wasop = PRINT; 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate for (av = argv; *av && (argp = lookup(*av)); av++) { 397*7c478bd9Sstevel@tonic-gate np->next = 0; 398*7c478bd9Sstevel@tonic-gate np->action = argp->action; 399*7c478bd9Sstevel@tonic-gate np->type = argp->type; 400*7c478bd9Sstevel@tonic-gate np->second.i = 0; 401*7c478bd9Sstevel@tonic-gate if (argp->type == Op) { 402*7c478bd9Sstevel@tonic-gate if (wasop == NOT || (wasop && np->action != NOT)) { 403*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 404*7c478bd9Sstevel@tonic-gate gettext("%s: operand follows operand\n"), 405*7c478bd9Sstevel@tonic-gate cmdname); 406*7c478bd9Sstevel@tonic-gate exit(1); 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate if (np->action != NOT && oldnp == 0) 409*7c478bd9Sstevel@tonic-gate goto err; 410*7c478bd9Sstevel@tonic-gate wasop = argp->action; 411*7c478bd9Sstevel@tonic-gate } else { 412*7c478bd9Sstevel@tonic-gate wasop = PRINT; 413*7c478bd9Sstevel@tonic-gate if (argp->type != Unary) { 414*7c478bd9Sstevel@tonic-gate if (!(b = *++av)) { 415*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 416*7c478bd9Sstevel@tonic-gate gettext("%s: incomplete statement\n"), 417*7c478bd9Sstevel@tonic-gate cmdname); 418*7c478bd9Sstevel@tonic-gate exit(1); 419*7c478bd9Sstevel@tonic-gate } 420*7c478bd9Sstevel@tonic-gate if (argp->type == Num) { 421*7c478bd9Sstevel@tonic-gate if ((argp->action != PERM) || 422*7c478bd9Sstevel@tonic-gate (*b != '+')) { 423*7c478bd9Sstevel@tonic-gate if (*b == '+' || *b == '-') { 424*7c478bd9Sstevel@tonic-gate np->second.i = *b; 425*7c478bd9Sstevel@tonic-gate b++; 426*7c478bd9Sstevel@tonic-gate } 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate } 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate switch (argp->action) { 432*7c478bd9Sstevel@tonic-gate case AND: 433*7c478bd9Sstevel@tonic-gate break; 434*7c478bd9Sstevel@tonic-gate case NOT: 435*7c478bd9Sstevel@tonic-gate break; 436*7c478bd9Sstevel@tonic-gate case OR: 437*7c478bd9Sstevel@tonic-gate np->first.np = topnode; 438*7c478bd9Sstevel@tonic-gate topnode = np; 439*7c478bd9Sstevel@tonic-gate oldnp->next = 0; 440*7c478bd9Sstevel@tonic-gate break; 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate case LPAREN: { 443*7c478bd9Sstevel@tonic-gate struct Node *save = topnode; 444*7c478bd9Sstevel@tonic-gate topnode = np+1; 445*7c478bd9Sstevel@tonic-gate paren_cnt++; 446*7c478bd9Sstevel@tonic-gate i = compile(++av, topnode, actionp); 447*7c478bd9Sstevel@tonic-gate np->first.np = topnode; 448*7c478bd9Sstevel@tonic-gate topnode = save; 449*7c478bd9Sstevel@tonic-gate av += i; 450*7c478bd9Sstevel@tonic-gate oldnp = np; 451*7c478bd9Sstevel@tonic-gate np += i + 1; 452*7c478bd9Sstevel@tonic-gate oldnp->next = np; 453*7c478bd9Sstevel@tonic-gate continue; 454*7c478bd9Sstevel@tonic-gate } 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate case RPAREN: 457*7c478bd9Sstevel@tonic-gate if (paren_cnt <= 0) { 458*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 459*7c478bd9Sstevel@tonic-gate gettext("%s: unmatched ')'\n"), 460*7c478bd9Sstevel@tonic-gate cmdname); 461*7c478bd9Sstevel@tonic-gate exit(1); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate paren_cnt--; 464*7c478bd9Sstevel@tonic-gate if (oldnp == 0) 465*7c478bd9Sstevel@tonic-gate goto err; 466*7c478bd9Sstevel@tonic-gate if (oldnp->type == Op) { 467*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 468*7c478bd9Sstevel@tonic-gate gettext("%s: cannot immediately" 469*7c478bd9Sstevel@tonic-gate " follow an operand with ')'\n"), 470*7c478bd9Sstevel@tonic-gate cmdname); 471*7c478bd9Sstevel@tonic-gate exit(1); 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate oldnp->next = 0; 474*7c478bd9Sstevel@tonic-gate return (av-argv); 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate case FOLLOW: 477*7c478bd9Sstevel@tonic-gate walkflags &= ~FTW_PHYS; 478*7c478bd9Sstevel@tonic-gate break; 479*7c478bd9Sstevel@tonic-gate case MOUNT: 480*7c478bd9Sstevel@tonic-gate walkflags |= FTW_MOUNT; 481*7c478bd9Sstevel@tonic-gate break; 482*7c478bd9Sstevel@tonic-gate case DEPTH: 483*7c478bd9Sstevel@tonic-gate walkflags |= FTW_DEPTH; 484*7c478bd9Sstevel@tonic-gate break; 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate case LOCAL: 487*7c478bd9Sstevel@tonic-gate np->first.l = 0L; 488*7c478bd9Sstevel@tonic-gate np->first.ll = 0LL; 489*7c478bd9Sstevel@tonic-gate np->second.i = '+'; 490*7c478bd9Sstevel@tonic-gate /* 491*7c478bd9Sstevel@tonic-gate * Make it compatible to df -l for 492*7c478bd9Sstevel@tonic-gate * future enhancement. So, anything 493*7c478bd9Sstevel@tonic-gate * that is not remote, then it is 494*7c478bd9Sstevel@tonic-gate * local. 495*7c478bd9Sstevel@tonic-gate */ 496*7c478bd9Sstevel@tonic-gate init_remote_fs(); 497*7c478bd9Sstevel@tonic-gate break; 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate case SIZE: 500*7c478bd9Sstevel@tonic-gate if (b[strlen(b)-1] == 'c') 501*7c478bd9Sstevel@tonic-gate np->action = CSIZE; 502*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 503*7c478bd9Sstevel@tonic-gate case INUM: 504*7c478bd9Sstevel@tonic-gate np->first.ll = atoll(b); 505*7c478bd9Sstevel@tonic-gate break; 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate case CTIME: 508*7c478bd9Sstevel@tonic-gate case MTIME: 509*7c478bd9Sstevel@tonic-gate case ATIME: 510*7c478bd9Sstevel@tonic-gate case LINKS: 511*7c478bd9Sstevel@tonic-gate np->first.l = atol(b); 512*7c478bd9Sstevel@tonic-gate break; 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate case F_USER: 515*7c478bd9Sstevel@tonic-gate case F_GROUP: { 516*7c478bd9Sstevel@tonic-gate struct passwd *pw; 517*7c478bd9Sstevel@tonic-gate struct group *gr; 518*7c478bd9Sstevel@tonic-gate i = -1; 519*7c478bd9Sstevel@tonic-gate if (argp->action == F_USER) { 520*7c478bd9Sstevel@tonic-gate if ((pw = getpwnam(b)) != 0) 521*7c478bd9Sstevel@tonic-gate i = (int)pw->pw_uid; 522*7c478bd9Sstevel@tonic-gate } else { 523*7c478bd9Sstevel@tonic-gate if ((gr = getgrnam(b)) != 0) 524*7c478bd9Sstevel@tonic-gate i = (int)gr->gr_gid; 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate if (i == -1) { 527*7c478bd9Sstevel@tonic-gate if (fnmatch("[0-9][0-9][0-9]*", b, 0) && 528*7c478bd9Sstevel@tonic-gate fnmatch("[0-9][0-9]", b, 0) && 529*7c478bd9Sstevel@tonic-gate fnmatch("[0-9]", b, 0)) { 530*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 531*7c478bd9Sstevel@tonic-gate "%s: cannot find %s name\n"), 532*7c478bd9Sstevel@tonic-gate cmdname, *av); 533*7c478bd9Sstevel@tonic-gate exit(1); 534*7c478bd9Sstevel@tonic-gate } 535*7c478bd9Sstevel@tonic-gate i = atoi(b); 536*7c478bd9Sstevel@tonic-gate } 537*7c478bd9Sstevel@tonic-gate np->first.l = i; 538*7c478bd9Sstevel@tonic-gate break; 539*7c478bd9Sstevel@tonic-gate } 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate case EXEC: 542*7c478bd9Sstevel@tonic-gate case OK: 543*7c478bd9Sstevel@tonic-gate walkflags &= ~FTW_CHDIR; 544*7c478bd9Sstevel@tonic-gate np->first.ap = av; 545*7c478bd9Sstevel@tonic-gate (*actionp)++; 546*7c478bd9Sstevel@tonic-gate for (;;) { 547*7c478bd9Sstevel@tonic-gate if ((b = *av) == 0) { 548*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 549*7c478bd9Sstevel@tonic-gate gettext("%s: incomplete statement\n"), 550*7c478bd9Sstevel@tonic-gate cmdname); 551*7c478bd9Sstevel@tonic-gate exit(1); 552*7c478bd9Sstevel@tonic-gate } 553*7c478bd9Sstevel@tonic-gate if (strcmp(b, ";") == 0) { 554*7c478bd9Sstevel@tonic-gate *av = 0; 555*7c478bd9Sstevel@tonic-gate break; 556*7c478bd9Sstevel@tonic-gate } else if (strcmp(b, "{}") == 0) 557*7c478bd9Sstevel@tonic-gate *av = dummyarg; 558*7c478bd9Sstevel@tonic-gate else if (strcmp(b, "+") == 0 && 559*7c478bd9Sstevel@tonic-gate av[-1] == dummyarg && 560*7c478bd9Sstevel@tonic-gate np->action == EXEC) { 561*7c478bd9Sstevel@tonic-gate av[-1] = 0; 562*7c478bd9Sstevel@tonic-gate np->first.vp = varargs(np->first.ap); 563*7c478bd9Sstevel@tonic-gate np->action = VARARGS; 564*7c478bd9Sstevel@tonic-gate break; 565*7c478bd9Sstevel@tonic-gate } 566*7c478bd9Sstevel@tonic-gate av++; 567*7c478bd9Sstevel@tonic-gate } 568*7c478bd9Sstevel@tonic-gate break; 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate case NAME: 571*7c478bd9Sstevel@tonic-gate np->first.cp = b; 572*7c478bd9Sstevel@tonic-gate break; 573*7c478bd9Sstevel@tonic-gate case PERM: 574*7c478bd9Sstevel@tonic-gate if (*b == '-') 575*7c478bd9Sstevel@tonic-gate ++b; 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate if (readmode(b) != NULL) { 578*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 579*7c478bd9Sstevel@tonic-gate "find: -perm: Bad permission string\n")); 580*7c478bd9Sstevel@tonic-gate usage(); 581*7c478bd9Sstevel@tonic-gate } 582*7c478bd9Sstevel@tonic-gate np->first.l = (long)getmode((mode_t)0); 583*7c478bd9Sstevel@tonic-gate break; 584*7c478bd9Sstevel@tonic-gate case TYPE: 585*7c478bd9Sstevel@tonic-gate i = *b; 586*7c478bd9Sstevel@tonic-gate np->first.l = 587*7c478bd9Sstevel@tonic-gate i == 'd' ? S_IFDIR : 588*7c478bd9Sstevel@tonic-gate i == 'b' ? S_IFBLK : 589*7c478bd9Sstevel@tonic-gate i == 'c' ? S_IFCHR : 590*7c478bd9Sstevel@tonic-gate #ifdef S_IFIFO 591*7c478bd9Sstevel@tonic-gate i == 'p' ? S_IFIFO : 592*7c478bd9Sstevel@tonic-gate #endif 593*7c478bd9Sstevel@tonic-gate i == 'f' ? S_IFREG : 594*7c478bd9Sstevel@tonic-gate #ifdef S_IFLNK 595*7c478bd9Sstevel@tonic-gate i == 'l' ? S_IFLNK : 596*7c478bd9Sstevel@tonic-gate #endif 597*7c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK 598*7c478bd9Sstevel@tonic-gate i == 's' ? S_IFSOCK : 599*7c478bd9Sstevel@tonic-gate #endif 600*7c478bd9Sstevel@tonic-gate #ifdef S_IFDOOR 601*7c478bd9Sstevel@tonic-gate i == 'D' ? S_IFDOOR : 602*7c478bd9Sstevel@tonic-gate #endif 603*7c478bd9Sstevel@tonic-gate 0; 604*7c478bd9Sstevel@tonic-gate break; 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate case CPIO: 607*7c478bd9Sstevel@tonic-gate if (walkflags & FTW_PHYS) 608*7c478bd9Sstevel@tonic-gate com = cpio; 609*7c478bd9Sstevel@tonic-gate else 610*7c478bd9Sstevel@tonic-gate com = cpiol; 611*7c478bd9Sstevel@tonic-gate goto common; 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate case NCPIO: { 614*7c478bd9Sstevel@tonic-gate FILE *fd; 615*7c478bd9Sstevel@tonic-gate 616*7c478bd9Sstevel@tonic-gate if (walkflags & FTW_PHYS) 617*7c478bd9Sstevel@tonic-gate com = ncpio; 618*7c478bd9Sstevel@tonic-gate else 619*7c478bd9Sstevel@tonic-gate com = ncpiol; 620*7c478bd9Sstevel@tonic-gate common: 621*7c478bd9Sstevel@tonic-gate /* set up cpio */ 622*7c478bd9Sstevel@tonic-gate if ((fd = fopen(b, "w")) == NULL) { 623*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 624*7c478bd9Sstevel@tonic-gate gettext("%s: cannot create %s\n"), 625*7c478bd9Sstevel@tonic-gate cmdname, b); 626*7c478bd9Sstevel@tonic-gate exit(1); 627*7c478bd9Sstevel@tonic-gate } 628*7c478bd9Sstevel@tonic-gate 629*7c478bd9Sstevel@tonic-gate np->first.l = (long)cmdopen("cpio", com, "w", fd); 630*7c478bd9Sstevel@tonic-gate (void) fclose(fd); 631*7c478bd9Sstevel@tonic-gate walkflags |= FTW_DEPTH; 632*7c478bd9Sstevel@tonic-gate np->action = CPIO; 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 635*7c478bd9Sstevel@tonic-gate case PRINT: 636*7c478bd9Sstevel@tonic-gate (*actionp)++; 637*7c478bd9Sstevel@tonic-gate break; 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate case NEWER: { 640*7c478bd9Sstevel@tonic-gate struct stat statb; 641*7c478bd9Sstevel@tonic-gate if (stat(b, &statb) < 0) { 642*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 643*7c478bd9Sstevel@tonic-gate gettext("%s: cannot access %s\n"), 644*7c478bd9Sstevel@tonic-gate cmdname, b); 645*7c478bd9Sstevel@tonic-gate exit(1); 646*7c478bd9Sstevel@tonic-gate } 647*7c478bd9Sstevel@tonic-gate np->first.l = statb.st_mtime; 648*7c478bd9Sstevel@tonic-gate np->second.i = '+'; 649*7c478bd9Sstevel@tonic-gate break; 650*7c478bd9Sstevel@tonic-gate } 651*7c478bd9Sstevel@tonic-gate 652*7c478bd9Sstevel@tonic-gate case PRUNE: 653*7c478bd9Sstevel@tonic-gate case NOUSER: 654*7c478bd9Sstevel@tonic-gate case NOGRP: 655*7c478bd9Sstevel@tonic-gate break; 656*7c478bd9Sstevel@tonic-gate case FSTYPE: 657*7c478bd9Sstevel@tonic-gate np->first.cp = b; 658*7c478bd9Sstevel@tonic-gate break; 659*7c478bd9Sstevel@tonic-gate case LS: 660*7c478bd9Sstevel@tonic-gate (*actionp)++; 661*7c478bd9Sstevel@tonic-gate break; 662*7c478bd9Sstevel@tonic-gate case XATTR: 663*7c478bd9Sstevel@tonic-gate break; 664*7c478bd9Sstevel@tonic-gate case ACL: 665*7c478bd9Sstevel@tonic-gate break; 666*7c478bd9Sstevel@tonic-gate } 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate oldnp = np++; 669*7c478bd9Sstevel@tonic-gate oldnp->next = np; 670*7c478bd9Sstevel@tonic-gate } 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate if ((*av) || (wasop)) 673*7c478bd9Sstevel@tonic-gate goto err; 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate if (paren_cnt != 0) { 676*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: unmatched '('\n"), 677*7c478bd9Sstevel@tonic-gate cmdname); 678*7c478bd9Sstevel@tonic-gate exit(1); 679*7c478bd9Sstevel@tonic-gate } 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate /* just before returning, save next free node from the list */ 682*7c478bd9Sstevel@tonic-gate freenode = oldnp->next; 683*7c478bd9Sstevel@tonic-gate oldnp->next = 0; 684*7c478bd9Sstevel@tonic-gate return (av-argv); 685*7c478bd9Sstevel@tonic-gate err: 686*7c478bd9Sstevel@tonic-gate if (*av) 687*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 688*7c478bd9Sstevel@tonic-gate gettext("%s: bad option %s\n"), cmdname, *av); 689*7c478bd9Sstevel@tonic-gate else 690*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: bad option\n"), cmdname); 691*7c478bd9Sstevel@tonic-gate usage(); 692*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 693*7c478bd9Sstevel@tonic-gate } 694*7c478bd9Sstevel@tonic-gate 695*7c478bd9Sstevel@tonic-gate /* 696*7c478bd9Sstevel@tonic-gate * print out a usage message 697*7c478bd9Sstevel@tonic-gate */ 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate static void 700*7c478bd9Sstevel@tonic-gate usage() 701*7c478bd9Sstevel@tonic-gate { 702*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 703*7c478bd9Sstevel@tonic-gate gettext("%s: [-H | -L] path-list predicate-list\n"), cmdname); 704*7c478bd9Sstevel@tonic-gate exit(1); 705*7c478bd9Sstevel@tonic-gate } 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate /* 708*7c478bd9Sstevel@tonic-gate * This is the function that gets executed at each node 709*7c478bd9Sstevel@tonic-gate */ 710*7c478bd9Sstevel@tonic-gate 711*7c478bd9Sstevel@tonic-gate static int 712*7c478bd9Sstevel@tonic-gate execute(name, statb, type, state) 713*7c478bd9Sstevel@tonic-gate char *name; 714*7c478bd9Sstevel@tonic-gate struct stat *statb; 715*7c478bd9Sstevel@tonic-gate int type; 716*7c478bd9Sstevel@tonic-gate struct FTW *state; 717*7c478bd9Sstevel@tonic-gate { 718*7c478bd9Sstevel@tonic-gate struct Node *np = topnode; 719*7c478bd9Sstevel@tonic-gate int val; 720*7c478bd9Sstevel@tonic-gate time_t t; 721*7c478bd9Sstevel@tonic-gate long l; 722*7c478bd9Sstevel@tonic-gate long long ll; 723*7c478bd9Sstevel@tonic-gate int not = 1; 724*7c478bd9Sstevel@tonic-gate char *filename; 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate if (type == FTW_NS) { 727*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: stat() error %s: %s\n"), 728*7c478bd9Sstevel@tonic-gate cmdname, name, strerror(errno)); 729*7c478bd9Sstevel@tonic-gate error = 1; 730*7c478bd9Sstevel@tonic-gate return (0); 731*7c478bd9Sstevel@tonic-gate } else if (type == FTW_DNR) { 732*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: cannot read dir %s: %s\n"), 733*7c478bd9Sstevel@tonic-gate cmdname, name, strerror(errno)); 734*7c478bd9Sstevel@tonic-gate error = 1; 735*7c478bd9Sstevel@tonic-gate return (0); 736*7c478bd9Sstevel@tonic-gate } else if (type == FTW_SLN && lflag == 0) { 737*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 738*7c478bd9Sstevel@tonic-gate gettext("%s: cannot follow symbolic link %s: %s\n"), 739*7c478bd9Sstevel@tonic-gate cmdname, name, strerror(errno)); 740*7c478bd9Sstevel@tonic-gate error = 1; 741*7c478bd9Sstevel@tonic-gate return (0); 742*7c478bd9Sstevel@tonic-gate } 743*7c478bd9Sstevel@tonic-gate 744*7c478bd9Sstevel@tonic-gate while (np) { 745*7c478bd9Sstevel@tonic-gate switch (np->action) { 746*7c478bd9Sstevel@tonic-gate case NOT: 747*7c478bd9Sstevel@tonic-gate not = !not; 748*7c478bd9Sstevel@tonic-gate np = np->next; 749*7c478bd9Sstevel@tonic-gate continue; 750*7c478bd9Sstevel@tonic-gate 751*7c478bd9Sstevel@tonic-gate case AND: 752*7c478bd9Sstevel@tonic-gate np = np->next; 753*7c478bd9Sstevel@tonic-gate continue; 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate case OR: 756*7c478bd9Sstevel@tonic-gate if (np->first.np == np) { 757*7c478bd9Sstevel@tonic-gate /* 758*7c478bd9Sstevel@tonic-gate * handle naked OR (no term on left hand side) 759*7c478bd9Sstevel@tonic-gate */ 760*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 761*7c478bd9Sstevel@tonic-gate gettext("%s: invalid -o construction\n"), 762*7c478bd9Sstevel@tonic-gate cmdname); 763*7c478bd9Sstevel@tonic-gate exit(2); 764*7c478bd9Sstevel@tonic-gate } 765*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 766*7c478bd9Sstevel@tonic-gate case LPAREN: { 767*7c478bd9Sstevel@tonic-gate struct Node *save = topnode; 768*7c478bd9Sstevel@tonic-gate topnode = np->first.np; 769*7c478bd9Sstevel@tonic-gate (void) execute(name, statb, type, state); 770*7c478bd9Sstevel@tonic-gate val = lastval; 771*7c478bd9Sstevel@tonic-gate topnode = save; 772*7c478bd9Sstevel@tonic-gate if (np->action == OR) { 773*7c478bd9Sstevel@tonic-gate if (val) 774*7c478bd9Sstevel@tonic-gate return (0); 775*7c478bd9Sstevel@tonic-gate val = 1; 776*7c478bd9Sstevel@tonic-gate } 777*7c478bd9Sstevel@tonic-gate break; 778*7c478bd9Sstevel@tonic-gate } 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate case LOCAL: { 781*7c478bd9Sstevel@tonic-gate int nremfs; 782*7c478bd9Sstevel@tonic-gate val = 1; 783*7c478bd9Sstevel@tonic-gate /* 784*7c478bd9Sstevel@tonic-gate * If file system type matches the remote 785*7c478bd9Sstevel@tonic-gate * file system type, then it is not local. 786*7c478bd9Sstevel@tonic-gate */ 787*7c478bd9Sstevel@tonic-gate for (nremfs = 0; nremfs < fstype_index; nremfs++) { 788*7c478bd9Sstevel@tonic-gate if (strcmp(remote_fstypes[nremfs], 789*7c478bd9Sstevel@tonic-gate statb->st_fstype) == 0) { 790*7c478bd9Sstevel@tonic-gate val = 0; 791*7c478bd9Sstevel@tonic-gate break; 792*7c478bd9Sstevel@tonic-gate } 793*7c478bd9Sstevel@tonic-gate } 794*7c478bd9Sstevel@tonic-gate break; 795*7c478bd9Sstevel@tonic-gate } 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate case TYPE: 798*7c478bd9Sstevel@tonic-gate l = (long)statb->st_mode&S_IFMT; 799*7c478bd9Sstevel@tonic-gate goto num; 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate case PERM: 802*7c478bd9Sstevel@tonic-gate l = (long)statb->st_mode&07777; 803*7c478bd9Sstevel@tonic-gate if (np->second.i == '-') 804*7c478bd9Sstevel@tonic-gate val = ((l&np->first.l) == np->first.l); 805*7c478bd9Sstevel@tonic-gate else 806*7c478bd9Sstevel@tonic-gate val = (l == np->first.l); 807*7c478bd9Sstevel@tonic-gate break; 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate case INUM: 810*7c478bd9Sstevel@tonic-gate ll = (long long)statb->st_ino; 811*7c478bd9Sstevel@tonic-gate goto llnum; 812*7c478bd9Sstevel@tonic-gate case NEWER: 813*7c478bd9Sstevel@tonic-gate l = statb->st_mtime; 814*7c478bd9Sstevel@tonic-gate goto num; 815*7c478bd9Sstevel@tonic-gate case ATIME: 816*7c478bd9Sstevel@tonic-gate t = statb->st_atime; 817*7c478bd9Sstevel@tonic-gate goto days; 818*7c478bd9Sstevel@tonic-gate case CTIME: 819*7c478bd9Sstevel@tonic-gate t = statb->st_ctime; 820*7c478bd9Sstevel@tonic-gate goto days; 821*7c478bd9Sstevel@tonic-gate case MTIME: 822*7c478bd9Sstevel@tonic-gate t = statb->st_mtime; 823*7c478bd9Sstevel@tonic-gate days: 824*7c478bd9Sstevel@tonic-gate l = (now-t)/A_DAY; 825*7c478bd9Sstevel@tonic-gate goto num; 826*7c478bd9Sstevel@tonic-gate case CSIZE: 827*7c478bd9Sstevel@tonic-gate ll = (long long)statb->st_size; 828*7c478bd9Sstevel@tonic-gate goto llnum; 829*7c478bd9Sstevel@tonic-gate case SIZE: 830*7c478bd9Sstevel@tonic-gate ll = (long long)round(statb->st_size, BLKSIZ)/BLKSIZ; 831*7c478bd9Sstevel@tonic-gate goto llnum; 832*7c478bd9Sstevel@tonic-gate case F_USER: 833*7c478bd9Sstevel@tonic-gate l = (long)statb->st_uid; 834*7c478bd9Sstevel@tonic-gate goto num; 835*7c478bd9Sstevel@tonic-gate case F_GROUP: 836*7c478bd9Sstevel@tonic-gate l = (long)statb->st_gid; 837*7c478bd9Sstevel@tonic-gate goto num; 838*7c478bd9Sstevel@tonic-gate case LINKS: 839*7c478bd9Sstevel@tonic-gate l = (long)statb->st_nlink; 840*7c478bd9Sstevel@tonic-gate goto num; 841*7c478bd9Sstevel@tonic-gate llnum: 842*7c478bd9Sstevel@tonic-gate if (np->second.i == '+') 843*7c478bd9Sstevel@tonic-gate val = (ll > np->first.ll); 844*7c478bd9Sstevel@tonic-gate else if (np->second.i == '-') 845*7c478bd9Sstevel@tonic-gate val = (ll < np->first.ll); 846*7c478bd9Sstevel@tonic-gate else 847*7c478bd9Sstevel@tonic-gate val = (ll == np->first.ll); 848*7c478bd9Sstevel@tonic-gate break; 849*7c478bd9Sstevel@tonic-gate num: 850*7c478bd9Sstevel@tonic-gate if (np->second.i == '+') 851*7c478bd9Sstevel@tonic-gate val = (l > np->first.l); 852*7c478bd9Sstevel@tonic-gate else if (np->second.i == '-') 853*7c478bd9Sstevel@tonic-gate val = (l < np->first.l); 854*7c478bd9Sstevel@tonic-gate else 855*7c478bd9Sstevel@tonic-gate val = (l == np->first.l); 856*7c478bd9Sstevel@tonic-gate break; 857*7c478bd9Sstevel@tonic-gate case OK: 858*7c478bd9Sstevel@tonic-gate val = ok(name, np->first.ap); 859*7c478bd9Sstevel@tonic-gate break; 860*7c478bd9Sstevel@tonic-gate case EXEC: 861*7c478bd9Sstevel@tonic-gate val = doexec(name, np->first.ap); 862*7c478bd9Sstevel@tonic-gate break; 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate case VARARGS: { 865*7c478bd9Sstevel@tonic-gate struct Arglist *ap = np->first.vp; 866*7c478bd9Sstevel@tonic-gate char *cp; 867*7c478bd9Sstevel@tonic-gate cp = ap->nextstr - (strlen(name)+1); 868*7c478bd9Sstevel@tonic-gate if (cp >= (char *)(ap->nextvar+3)) { 869*7c478bd9Sstevel@tonic-gate /* there is room just copy the name */ 870*7c478bd9Sstevel@tonic-gate val = 1; 871*7c478bd9Sstevel@tonic-gate (void) strcpy(cp, name); 872*7c478bd9Sstevel@tonic-gate *ap->nextvar++ = cp; 873*7c478bd9Sstevel@tonic-gate ap->nextstr = cp; 874*7c478bd9Sstevel@tonic-gate } else { 875*7c478bd9Sstevel@tonic-gate /* no more room, exec command */ 876*7c478bd9Sstevel@tonic-gate *ap->nextvar++ = name; 877*7c478bd9Sstevel@tonic-gate *ap->nextvar = 0; 878*7c478bd9Sstevel@tonic-gate val = 1; 879*7c478bd9Sstevel@tonic-gate varexecrc = doexec((char *)0, ap->arglist); 880*7c478bd9Sstevel@tonic-gate ap->nextstr = ap->end; 881*7c478bd9Sstevel@tonic-gate ap->nextvar = ap->firstvar; 882*7c478bd9Sstevel@tonic-gate } 883*7c478bd9Sstevel@tonic-gate break; 884*7c478bd9Sstevel@tonic-gate } 885*7c478bd9Sstevel@tonic-gate 886*7c478bd9Sstevel@tonic-gate case DEPTH: 887*7c478bd9Sstevel@tonic-gate case MOUNT: 888*7c478bd9Sstevel@tonic-gate case FOLLOW: 889*7c478bd9Sstevel@tonic-gate val = 1; 890*7c478bd9Sstevel@tonic-gate break; 891*7c478bd9Sstevel@tonic-gate 892*7c478bd9Sstevel@tonic-gate case NAME: { 893*7c478bd9Sstevel@tonic-gate /* 894*7c478bd9Sstevel@tonic-gate * XPG4 find should not treat a leading '.' in a 895*7c478bd9Sstevel@tonic-gate * filename specially for pattern matching. 896*7c478bd9Sstevel@tonic-gate * /usr/bin/find will not pattern match a leading 897*7c478bd9Sstevel@tonic-gate * '.' in a filename, unless '.' is explicitly 898*7c478bd9Sstevel@tonic-gate * specified. 899*7c478bd9Sstevel@tonic-gate */ 900*7c478bd9Sstevel@tonic-gate #ifdef XPG4 901*7c478bd9Sstevel@tonic-gate val = !fnmatch(np->first.cp, 902*7c478bd9Sstevel@tonic-gate name+state->base, 0); 903*7c478bd9Sstevel@tonic-gate #else 904*7c478bd9Sstevel@tonic-gate val = !fnmatch(np->first.cp, 905*7c478bd9Sstevel@tonic-gate name+state->base, FNM_PERIOD); 906*7c478bd9Sstevel@tonic-gate #endif 907*7c478bd9Sstevel@tonic-gate break; 908*7c478bd9Sstevel@tonic-gate } 909*7c478bd9Sstevel@tonic-gate 910*7c478bd9Sstevel@tonic-gate case PRUNE: 911*7c478bd9Sstevel@tonic-gate if (type == FTW_D) 912*7c478bd9Sstevel@tonic-gate state->quit = FTW_PRUNE; 913*7c478bd9Sstevel@tonic-gate val = 1; 914*7c478bd9Sstevel@tonic-gate break; 915*7c478bd9Sstevel@tonic-gate case NOUSER: 916*7c478bd9Sstevel@tonic-gate val = ((getpwuid(statb->st_uid)) == 0); 917*7c478bd9Sstevel@tonic-gate break; 918*7c478bd9Sstevel@tonic-gate case NOGRP: 919*7c478bd9Sstevel@tonic-gate val = ((getgrgid(statb->st_gid)) == 0); 920*7c478bd9Sstevel@tonic-gate break; 921*7c478bd9Sstevel@tonic-gate case FSTYPE: 922*7c478bd9Sstevel@tonic-gate val = (strcmp(np->first.cp, statb->st_fstype) == 0); 923*7c478bd9Sstevel@tonic-gate break; 924*7c478bd9Sstevel@tonic-gate case CPIO: 925*7c478bd9Sstevel@tonic-gate output = (FILE *)np->first.l; 926*7c478bd9Sstevel@tonic-gate (void) fprintf(output, "%s\n", name); 927*7c478bd9Sstevel@tonic-gate val = 1; 928*7c478bd9Sstevel@tonic-gate break; 929*7c478bd9Sstevel@tonic-gate case PRINT: 930*7c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%s\n", name); 931*7c478bd9Sstevel@tonic-gate val = 1; 932*7c478bd9Sstevel@tonic-gate break; 933*7c478bd9Sstevel@tonic-gate case LS: 934*7c478bd9Sstevel@tonic-gate (void) list(name, statb); 935*7c478bd9Sstevel@tonic-gate val = 1; 936*7c478bd9Sstevel@tonic-gate break; 937*7c478bd9Sstevel@tonic-gate case XATTR: 938*7c478bd9Sstevel@tonic-gate filename = gettail(name); 939*7c478bd9Sstevel@tonic-gate val = (pathconf(filename, _PC_XATTR_EXISTS) == 1); 940*7c478bd9Sstevel@tonic-gate break; 941*7c478bd9Sstevel@tonic-gate case ACL: 942*7c478bd9Sstevel@tonic-gate /* 943*7c478bd9Sstevel@tonic-gate * Need to get the tail of the file name, since we have 944*7c478bd9Sstevel@tonic-gate * already chdir()ed into the directory (performed in 945*7c478bd9Sstevel@tonic-gate * nftw()) of the file 946*7c478bd9Sstevel@tonic-gate */ 947*7c478bd9Sstevel@tonic-gate filename = gettail(name); 948*7c478bd9Sstevel@tonic-gate val = (acl(filename, GETACLCNT, 0, NULL) > 949*7c478bd9Sstevel@tonic-gate MIN_ACL_ENTRIES); 950*7c478bd9Sstevel@tonic-gate break; 951*7c478bd9Sstevel@tonic-gate } 952*7c478bd9Sstevel@tonic-gate /* 953*7c478bd9Sstevel@tonic-gate * evaluate 'val' and 'not' (exclusive-or) 954*7c478bd9Sstevel@tonic-gate * if no inversion (not == 1), return only when val == 0 955*7c478bd9Sstevel@tonic-gate * (primary not true). Otherwise, invert the primary 956*7c478bd9Sstevel@tonic-gate * and return when the primary is true. 957*7c478bd9Sstevel@tonic-gate * 'Lastval' saves the last result (fail or pass) when 958*7c478bd9Sstevel@tonic-gate * returning back to the calling routine. 959*7c478bd9Sstevel@tonic-gate */ 960*7c478bd9Sstevel@tonic-gate if (val^not) { 961*7c478bd9Sstevel@tonic-gate lastval = 0; 962*7c478bd9Sstevel@tonic-gate return (0); 963*7c478bd9Sstevel@tonic-gate } 964*7c478bd9Sstevel@tonic-gate lastval = 1; 965*7c478bd9Sstevel@tonic-gate not = 1; 966*7c478bd9Sstevel@tonic-gate np = np->next; 967*7c478bd9Sstevel@tonic-gate } 968*7c478bd9Sstevel@tonic-gate return (0); 969*7c478bd9Sstevel@tonic-gate } 970*7c478bd9Sstevel@tonic-gate 971*7c478bd9Sstevel@tonic-gate /* 972*7c478bd9Sstevel@tonic-gate * code for the -ok option 973*7c478bd9Sstevel@tonic-gate */ 974*7c478bd9Sstevel@tonic-gate 975*7c478bd9Sstevel@tonic-gate static int 976*7c478bd9Sstevel@tonic-gate ok(name, argv) 977*7c478bd9Sstevel@tonic-gate char *name; 978*7c478bd9Sstevel@tonic-gate char *argv[]; 979*7c478bd9Sstevel@tonic-gate { 980*7c478bd9Sstevel@tonic-gate int c, yes = 0; 981*7c478bd9Sstevel@tonic-gate 982*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); /* to flush possible `-print' */ 983*7c478bd9Sstevel@tonic-gate 984*7c478bd9Sstevel@tonic-gate if ((*argv != dummyarg) && (strcmp(*argv, name))) 985*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "< %s ... %s >? ", *argv, name); 986*7c478bd9Sstevel@tonic-gate else 987*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "< {} ... %s >? ", name); 988*7c478bd9Sstevel@tonic-gate 989*7c478bd9Sstevel@tonic-gate (void) fflush(stderr); 990*7c478bd9Sstevel@tonic-gate if ((c = tolower(getchar())) == *nl_langinfo(YESSTR)) 991*7c478bd9Sstevel@tonic-gate yes = 1; 992*7c478bd9Sstevel@tonic-gate while (c != '\n') 993*7c478bd9Sstevel@tonic-gate if (c == EOF) 994*7c478bd9Sstevel@tonic-gate exit(2); 995*7c478bd9Sstevel@tonic-gate else 996*7c478bd9Sstevel@tonic-gate c = getchar(); 997*7c478bd9Sstevel@tonic-gate return (yes? doexec(name, argv): 0); 998*7c478bd9Sstevel@tonic-gate } 999*7c478bd9Sstevel@tonic-gate 1000*7c478bd9Sstevel@tonic-gate /* 1001*7c478bd9Sstevel@tonic-gate * execute argv with {} replaced by name 1002*7c478bd9Sstevel@tonic-gate */ 1003*7c478bd9Sstevel@tonic-gate 1004*7c478bd9Sstevel@tonic-gate static int 1005*7c478bd9Sstevel@tonic-gate doexec(name, argv) 1006*7c478bd9Sstevel@tonic-gate char *name; 1007*7c478bd9Sstevel@tonic-gate char *argv[]; 1008*7c478bd9Sstevel@tonic-gate { 1009*7c478bd9Sstevel@tonic-gate char *cp; 1010*7c478bd9Sstevel@tonic-gate char **av = argv; 1011*7c478bd9Sstevel@tonic-gate int dummyseen = 0; 1012*7c478bd9Sstevel@tonic-gate int r = 0; 1013*7c478bd9Sstevel@tonic-gate pid_t pid; 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); /* to flush possible `-print' */ 1016*7c478bd9Sstevel@tonic-gate if (name) { 1017*7c478bd9Sstevel@tonic-gate while (cp = *av++) { 1018*7c478bd9Sstevel@tonic-gate if (cp == dummyarg) { 1019*7c478bd9Sstevel@tonic-gate dummyseen = 1; 1020*7c478bd9Sstevel@tonic-gate av[-1] = name; 1021*7c478bd9Sstevel@tonic-gate } 1022*7c478bd9Sstevel@tonic-gate 1023*7c478bd9Sstevel@tonic-gate } 1024*7c478bd9Sstevel@tonic-gate } 1025*7c478bd9Sstevel@tonic-gate if (argv[0] == NULL) /* null command line */ 1026*7c478bd9Sstevel@tonic-gate return (r); 1027*7c478bd9Sstevel@tonic-gate 1028*7c478bd9Sstevel@tonic-gate if (pid = fork()) { 1029*7c478bd9Sstevel@tonic-gate while (wait(&r) != pid); 1030*7c478bd9Sstevel@tonic-gate } else /* child */ { 1031*7c478bd9Sstevel@tonic-gate (void) execvp(argv[0], argv); 1032*7c478bd9Sstevel@tonic-gate exit(1); 1033*7c478bd9Sstevel@tonic-gate } 1034*7c478bd9Sstevel@tonic-gate if (name && dummyseen) { 1035*7c478bd9Sstevel@tonic-gate for (av = argv; cp = *av++; ) { 1036*7c478bd9Sstevel@tonic-gate if (cp == name) 1037*7c478bd9Sstevel@tonic-gate av[-1] = dummyarg; 1038*7c478bd9Sstevel@tonic-gate } 1039*7c478bd9Sstevel@tonic-gate } 1040*7c478bd9Sstevel@tonic-gate 1041*7c478bd9Sstevel@tonic-gate return (!r); 1042*7c478bd9Sstevel@tonic-gate } 1043*7c478bd9Sstevel@tonic-gate 1044*7c478bd9Sstevel@tonic-gate 1045*7c478bd9Sstevel@tonic-gate /* 1046*7c478bd9Sstevel@tonic-gate * Table lookup routine 1047*7c478bd9Sstevel@tonic-gate */ 1048*7c478bd9Sstevel@tonic-gate static struct Args * 1049*7c478bd9Sstevel@tonic-gate lookup(word) 1050*7c478bd9Sstevel@tonic-gate char *word; 1051*7c478bd9Sstevel@tonic-gate { 1052*7c478bd9Sstevel@tonic-gate struct Args *argp = commands; 1053*7c478bd9Sstevel@tonic-gate int second; 1054*7c478bd9Sstevel@tonic-gate if (word == 0 || *word == 0) 1055*7c478bd9Sstevel@tonic-gate return (0); 1056*7c478bd9Sstevel@tonic-gate second = word[1]; 1057*7c478bd9Sstevel@tonic-gate while (*argp->name) { 1058*7c478bd9Sstevel@tonic-gate if (second == argp->name[1] && strcmp(word, argp->name) == 0) 1059*7c478bd9Sstevel@tonic-gate return (argp); 1060*7c478bd9Sstevel@tonic-gate argp++; 1061*7c478bd9Sstevel@tonic-gate } 1062*7c478bd9Sstevel@tonic-gate return (0); 1063*7c478bd9Sstevel@tonic-gate } 1064*7c478bd9Sstevel@tonic-gate 1065*7c478bd9Sstevel@tonic-gate 1066*7c478bd9Sstevel@tonic-gate /* 1067*7c478bd9Sstevel@tonic-gate * Get space for variable length argument list 1068*7c478bd9Sstevel@tonic-gate */ 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate static struct Arglist * 1071*7c478bd9Sstevel@tonic-gate varargs(com) 1072*7c478bd9Sstevel@tonic-gate char **com; 1073*7c478bd9Sstevel@tonic-gate { 1074*7c478bd9Sstevel@tonic-gate struct Arglist *ap; 1075*7c478bd9Sstevel@tonic-gate int n; 1076*7c478bd9Sstevel@tonic-gate char **ep; 1077*7c478bd9Sstevel@tonic-gate if (varsize == 0) { 1078*7c478bd9Sstevel@tonic-gate n = 2*sizeof (char **); 1079*7c478bd9Sstevel@tonic-gate for (ep = environ; *ep; ep++) 1080*7c478bd9Sstevel@tonic-gate n += (strlen(*ep)+sizeof (ep) + 1); 1081*7c478bd9Sstevel@tonic-gate varsize = sizeof (struct Arglist)+ARG_MAX-PATH_MAX-n-1; 1082*7c478bd9Sstevel@tonic-gate } 1083*7c478bd9Sstevel@tonic-gate ap = (struct Arglist *)malloc(varsize+1); 1084*7c478bd9Sstevel@tonic-gate ap->end = (char *)ap + varsize; 1085*7c478bd9Sstevel@tonic-gate ap->nextstr = ap->end; 1086*7c478bd9Sstevel@tonic-gate ap->nextvar = ap->arglist; 1087*7c478bd9Sstevel@tonic-gate while (*ap->nextvar++ = *com++); 1088*7c478bd9Sstevel@tonic-gate ap->nextvar--; 1089*7c478bd9Sstevel@tonic-gate ap->firstvar = ap->nextvar; 1090*7c478bd9Sstevel@tonic-gate ap->next = lastlist; 1091*7c478bd9Sstevel@tonic-gate lastlist = ap; 1092*7c478bd9Sstevel@tonic-gate return (ap); 1093*7c478bd9Sstevel@tonic-gate } 1094*7c478bd9Sstevel@tonic-gate 1095*7c478bd9Sstevel@tonic-gate /* 1096*7c478bd9Sstevel@tonic-gate * filter command support 1097*7c478bd9Sstevel@tonic-gate * fork and exec cmd(argv) according to mode: 1098*7c478bd9Sstevel@tonic-gate * 1099*7c478bd9Sstevel@tonic-gate * "r" with fp as stdin of cmd (default stdin), cmd stdout returned 1100*7c478bd9Sstevel@tonic-gate * "w" with fp as stdout of cmd (default stdout), cmd stdin returned 1101*7c478bd9Sstevel@tonic-gate */ 1102*7c478bd9Sstevel@tonic-gate 1103*7c478bd9Sstevel@tonic-gate #define CMDERR ((1<<8)-1) /* command error exit code */ 1104*7c478bd9Sstevel@tonic-gate #define MAXCMDS 8 /* max # simultaneous cmdopen()'s */ 1105*7c478bd9Sstevel@tonic-gate 1106*7c478bd9Sstevel@tonic-gate static struct /* info for each cmdopen() */ 1107*7c478bd9Sstevel@tonic-gate { 1108*7c478bd9Sstevel@tonic-gate FILE *fp; /* returned by cmdopen() */ 1109*7c478bd9Sstevel@tonic-gate pid_t pid; /* pid used by cmdopen() */ 1110*7c478bd9Sstevel@tonic-gate } cmdproc[MAXCMDS]; 1111*7c478bd9Sstevel@tonic-gate 1112*7c478bd9Sstevel@tonic-gate static FILE * 1113*7c478bd9Sstevel@tonic-gate cmdopen(cmd, argv, mode, fp) 1114*7c478bd9Sstevel@tonic-gate char *cmd; 1115*7c478bd9Sstevel@tonic-gate char **argv; 1116*7c478bd9Sstevel@tonic-gate char *mode; 1117*7c478bd9Sstevel@tonic-gate FILE *fp; 1118*7c478bd9Sstevel@tonic-gate { 1119*7c478bd9Sstevel@tonic-gate int proc; 1120*7c478bd9Sstevel@tonic-gate int cmdfd; 1121*7c478bd9Sstevel@tonic-gate int usrfd; 1122*7c478bd9Sstevel@tonic-gate int pio[2]; 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate switch (*mode) { 1125*7c478bd9Sstevel@tonic-gate case 'r': 1126*7c478bd9Sstevel@tonic-gate cmdfd = 1; 1127*7c478bd9Sstevel@tonic-gate usrfd = 0; 1128*7c478bd9Sstevel@tonic-gate break; 1129*7c478bd9Sstevel@tonic-gate case 'w': 1130*7c478bd9Sstevel@tonic-gate cmdfd = 0; 1131*7c478bd9Sstevel@tonic-gate usrfd = 1; 1132*7c478bd9Sstevel@tonic-gate break; 1133*7c478bd9Sstevel@tonic-gate default: 1134*7c478bd9Sstevel@tonic-gate return (0); 1135*7c478bd9Sstevel@tonic-gate } 1136*7c478bd9Sstevel@tonic-gate 1137*7c478bd9Sstevel@tonic-gate for (proc = 0; proc < MAXCMDS; proc++) 1138*7c478bd9Sstevel@tonic-gate if (!cmdproc[proc].fp) 1139*7c478bd9Sstevel@tonic-gate break; 1140*7c478bd9Sstevel@tonic-gate if (proc >= MAXCMDS) 1141*7c478bd9Sstevel@tonic-gate return (0); 1142*7c478bd9Sstevel@tonic-gate 1143*7c478bd9Sstevel@tonic-gate if (pipe(pio)) 1144*7c478bd9Sstevel@tonic-gate return (0); 1145*7c478bd9Sstevel@tonic-gate 1146*7c478bd9Sstevel@tonic-gate switch (cmdproc[proc].pid = fork()) { 1147*7c478bd9Sstevel@tonic-gate case -1: 1148*7c478bd9Sstevel@tonic-gate return (0); 1149*7c478bd9Sstevel@tonic-gate case 0: 1150*7c478bd9Sstevel@tonic-gate if (fp && fileno(fp) != usrfd) { 1151*7c478bd9Sstevel@tonic-gate (void) close(usrfd); 1152*7c478bd9Sstevel@tonic-gate if (dup2(fileno(fp), usrfd) != usrfd) 1153*7c478bd9Sstevel@tonic-gate _exit(CMDERR); 1154*7c478bd9Sstevel@tonic-gate (void) close(fileno(fp)); 1155*7c478bd9Sstevel@tonic-gate } 1156*7c478bd9Sstevel@tonic-gate (void) close(cmdfd); 1157*7c478bd9Sstevel@tonic-gate if (dup2(pio[cmdfd], cmdfd) != cmdfd) 1158*7c478bd9Sstevel@tonic-gate _exit(CMDERR); 1159*7c478bd9Sstevel@tonic-gate (void) close(pio[cmdfd]); 1160*7c478bd9Sstevel@tonic-gate (void) close(pio[usrfd]); 1161*7c478bd9Sstevel@tonic-gate (void) execvp(cmd, argv); 1162*7c478bd9Sstevel@tonic-gate if (errno == ENOEXEC) { 1163*7c478bd9Sstevel@tonic-gate char **p; 1164*7c478bd9Sstevel@tonic-gate char **v; 1165*7c478bd9Sstevel@tonic-gate 1166*7c478bd9Sstevel@tonic-gate /* 1167*7c478bd9Sstevel@tonic-gate * assume cmd is a shell script 1168*7c478bd9Sstevel@tonic-gate */ 1169*7c478bd9Sstevel@tonic-gate 1170*7c478bd9Sstevel@tonic-gate p = argv; 1171*7c478bd9Sstevel@tonic-gate while (*p++); 1172*7c478bd9Sstevel@tonic-gate if (v = (char **)malloc((p - argv + 1) * 1173*7c478bd9Sstevel@tonic-gate sizeof (char **))) { 1174*7c478bd9Sstevel@tonic-gate p = v; 1175*7c478bd9Sstevel@tonic-gate *p++ = cmd; 1176*7c478bd9Sstevel@tonic-gate if (*argv) argv++; 1177*7c478bd9Sstevel@tonic-gate while (*p++ = *argv++); 1178*7c478bd9Sstevel@tonic-gate (void) execv(getshell(), v); 1179*7c478bd9Sstevel@tonic-gate } 1180*7c478bd9Sstevel@tonic-gate } 1181*7c478bd9Sstevel@tonic-gate _exit(CMDERR); 1182*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1183*7c478bd9Sstevel@tonic-gate default: 1184*7c478bd9Sstevel@tonic-gate (void) close(pio[cmdfd]); 1185*7c478bd9Sstevel@tonic-gate return (cmdproc[proc].fp = fdopen(pio[usrfd], mode)); 1186*7c478bd9Sstevel@tonic-gate } 1187*7c478bd9Sstevel@tonic-gate } 1188*7c478bd9Sstevel@tonic-gate 1189*7c478bd9Sstevel@tonic-gate /* 1190*7c478bd9Sstevel@tonic-gate * close a stream opened by cmdopen() 1191*7c478bd9Sstevel@tonic-gate * -1 returned if cmdopen() had a problem 1192*7c478bd9Sstevel@tonic-gate * otherwise exit() status of command is returned 1193*7c478bd9Sstevel@tonic-gate */ 1194*7c478bd9Sstevel@tonic-gate 1195*7c478bd9Sstevel@tonic-gate static int 1196*7c478bd9Sstevel@tonic-gate cmdclose(fp) 1197*7c478bd9Sstevel@tonic-gate FILE *fp; 1198*7c478bd9Sstevel@tonic-gate { 1199*7c478bd9Sstevel@tonic-gate int i; 1200*7c478bd9Sstevel@tonic-gate pid_t p, pid; 1201*7c478bd9Sstevel@tonic-gate int status; 1202*7c478bd9Sstevel@tonic-gate 1203*7c478bd9Sstevel@tonic-gate for (i = 0; i < MAXCMDS; i++) 1204*7c478bd9Sstevel@tonic-gate if (fp == cmdproc[i].fp) break; 1205*7c478bd9Sstevel@tonic-gate if (i >= MAXCMDS) 1206*7c478bd9Sstevel@tonic-gate return (-1); 1207*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 1208*7c478bd9Sstevel@tonic-gate cmdproc[i].fp = 0; 1209*7c478bd9Sstevel@tonic-gate pid = cmdproc[i].pid; 1210*7c478bd9Sstevel@tonic-gate while ((p = wait(&status)) != pid && p != (pid_t)-1); 1211*7c478bd9Sstevel@tonic-gate if (p == pid) { 1212*7c478bd9Sstevel@tonic-gate status = (status >> 8) & CMDERR; 1213*7c478bd9Sstevel@tonic-gate if (status == CMDERR) 1214*7c478bd9Sstevel@tonic-gate status = -1; 1215*7c478bd9Sstevel@tonic-gate } 1216*7c478bd9Sstevel@tonic-gate else 1217*7c478bd9Sstevel@tonic-gate status = -1; 1218*7c478bd9Sstevel@tonic-gate return (status); 1219*7c478bd9Sstevel@tonic-gate } 1220*7c478bd9Sstevel@tonic-gate 1221*7c478bd9Sstevel@tonic-gate /* 1222*7c478bd9Sstevel@tonic-gate * return pointer to the full path name of the shell 1223*7c478bd9Sstevel@tonic-gate * 1224*7c478bd9Sstevel@tonic-gate * SHELL is read from the environment and must start with / 1225*7c478bd9Sstevel@tonic-gate * 1226*7c478bd9Sstevel@tonic-gate * if set-uid or set-gid then the executable and its containing 1227*7c478bd9Sstevel@tonic-gate * directory must not be writable by the real user 1228*7c478bd9Sstevel@tonic-gate * 1229*7c478bd9Sstevel@tonic-gate * /usr/bin/sh is returned by default 1230*7c478bd9Sstevel@tonic-gate */ 1231*7c478bd9Sstevel@tonic-gate 1232*7c478bd9Sstevel@tonic-gate char * 1233*7c478bd9Sstevel@tonic-gate getshell() 1234*7c478bd9Sstevel@tonic-gate { 1235*7c478bd9Sstevel@tonic-gate char *s; 1236*7c478bd9Sstevel@tonic-gate char *sh; 1237*7c478bd9Sstevel@tonic-gate uid_t u; 1238*7c478bd9Sstevel@tonic-gate int j; 1239*7c478bd9Sstevel@tonic-gate 1240*7c478bd9Sstevel@tonic-gate if (((sh = getenv("SHELL")) != 0) && *sh == '/') { 1241*7c478bd9Sstevel@tonic-gate if (u = getuid()) { 1242*7c478bd9Sstevel@tonic-gate if ((u != geteuid() || getgid() != getegid()) && 1243*7c478bd9Sstevel@tonic-gate !access(sh, 2)) 1244*7c478bd9Sstevel@tonic-gate goto defshell; 1245*7c478bd9Sstevel@tonic-gate s = strrchr(sh, '/'); 1246*7c478bd9Sstevel@tonic-gate *s = 0; 1247*7c478bd9Sstevel@tonic-gate j = access(sh, 2); 1248*7c478bd9Sstevel@tonic-gate *s = '/'; 1249*7c478bd9Sstevel@tonic-gate if (!j) goto defshell; 1250*7c478bd9Sstevel@tonic-gate } 1251*7c478bd9Sstevel@tonic-gate return (sh); 1252*7c478bd9Sstevel@tonic-gate } 1253*7c478bd9Sstevel@tonic-gate defshell: 1254*7c478bd9Sstevel@tonic-gate return ("/usr/bin/sh"); 1255*7c478bd9Sstevel@tonic-gate } 1256*7c478bd9Sstevel@tonic-gate 1257*7c478bd9Sstevel@tonic-gate /* 1258*7c478bd9Sstevel@tonic-gate * the following functions implement the added "-ls" option 1259*7c478bd9Sstevel@tonic-gate */ 1260*7c478bd9Sstevel@tonic-gate 1261*7c478bd9Sstevel@tonic-gate #include <utmpx.h> 1262*7c478bd9Sstevel@tonic-gate #include <sys/mkdev.h> 1263*7c478bd9Sstevel@tonic-gate 1264*7c478bd9Sstevel@tonic-gate struct utmpx utmpx; 1265*7c478bd9Sstevel@tonic-gate #define NMAX (sizeof (utmpx.ut_name)) 1266*7c478bd9Sstevel@tonic-gate #define SCPYN(a, b) (void) strncpy(a, b, NMAX) 1267*7c478bd9Sstevel@tonic-gate 1268*7c478bd9Sstevel@tonic-gate #define NUID 64 1269*7c478bd9Sstevel@tonic-gate #define NGID 64 1270*7c478bd9Sstevel@tonic-gate 1271*7c478bd9Sstevel@tonic-gate static struct ncache { 1272*7c478bd9Sstevel@tonic-gate int id; 1273*7c478bd9Sstevel@tonic-gate char name[NMAX+1]; 1274*7c478bd9Sstevel@tonic-gate } nc[NUID], gc[NGID]; 1275*7c478bd9Sstevel@tonic-gate 1276*7c478bd9Sstevel@tonic-gate /* 1277*7c478bd9Sstevel@tonic-gate * This function assumes that the password file is hashed 1278*7c478bd9Sstevel@tonic-gate * (or some such) to allow fast access based on a name key. 1279*7c478bd9Sstevel@tonic-gate */ 1280*7c478bd9Sstevel@tonic-gate static char * 1281*7c478bd9Sstevel@tonic-gate getname(uid_t uid) 1282*7c478bd9Sstevel@tonic-gate { 1283*7c478bd9Sstevel@tonic-gate struct passwd *pw; 1284*7c478bd9Sstevel@tonic-gate int cp; 1285*7c478bd9Sstevel@tonic-gate 1286*7c478bd9Sstevel@tonic-gate #if (((NUID) & ((NUID) - 1)) != 0) 1287*7c478bd9Sstevel@tonic-gate cp = uid % (NUID); 1288*7c478bd9Sstevel@tonic-gate #else 1289*7c478bd9Sstevel@tonic-gate cp = uid & ((NUID) - 1); 1290*7c478bd9Sstevel@tonic-gate #endif 1291*7c478bd9Sstevel@tonic-gate if (uid >= 0 && nc[cp].id == uid && nc[cp].name[0]) 1292*7c478bd9Sstevel@tonic-gate return (nc[cp].name); 1293*7c478bd9Sstevel@tonic-gate pw = getpwuid(uid); 1294*7c478bd9Sstevel@tonic-gate if (!pw) 1295*7c478bd9Sstevel@tonic-gate return (0); 1296*7c478bd9Sstevel@tonic-gate nc[cp].id = uid; 1297*7c478bd9Sstevel@tonic-gate SCPYN(nc[cp].name, pw->pw_name); 1298*7c478bd9Sstevel@tonic-gate return (nc[cp].name); 1299*7c478bd9Sstevel@tonic-gate } 1300*7c478bd9Sstevel@tonic-gate 1301*7c478bd9Sstevel@tonic-gate /* 1302*7c478bd9Sstevel@tonic-gate * This function assumes that the group file is hashed 1303*7c478bd9Sstevel@tonic-gate * (or some such) to allow fast access based on a name key. 1304*7c478bd9Sstevel@tonic-gate */ 1305*7c478bd9Sstevel@tonic-gate static char * 1306*7c478bd9Sstevel@tonic-gate getgroup(gid_t gid) 1307*7c478bd9Sstevel@tonic-gate { 1308*7c478bd9Sstevel@tonic-gate struct group *gr; 1309*7c478bd9Sstevel@tonic-gate int cp; 1310*7c478bd9Sstevel@tonic-gate 1311*7c478bd9Sstevel@tonic-gate #if (((NGID) & ((NGID) - 1)) != 0) 1312*7c478bd9Sstevel@tonic-gate cp = gid % (NGID); 1313*7c478bd9Sstevel@tonic-gate #else 1314*7c478bd9Sstevel@tonic-gate cp = gid & ((NGID) - 1); 1315*7c478bd9Sstevel@tonic-gate #endif 1316*7c478bd9Sstevel@tonic-gate if (gid >= 0 && gc[cp].id == gid && gc[cp].name[0]) 1317*7c478bd9Sstevel@tonic-gate return (gc[cp].name); 1318*7c478bd9Sstevel@tonic-gate gr = getgrgid(gid); 1319*7c478bd9Sstevel@tonic-gate if (!gr) 1320*7c478bd9Sstevel@tonic-gate return (0); 1321*7c478bd9Sstevel@tonic-gate gc[cp].id = gid; 1322*7c478bd9Sstevel@tonic-gate SCPYN(gc[cp].name, gr->gr_name); 1323*7c478bd9Sstevel@tonic-gate return (gc[cp].name); 1324*7c478bd9Sstevel@tonic-gate } 1325*7c478bd9Sstevel@tonic-gate 1326*7c478bd9Sstevel@tonic-gate #define permoffset(who) ((who) * 3) 1327*7c478bd9Sstevel@tonic-gate #define permission(who, type) ((type) >> permoffset(who)) 1328*7c478bd9Sstevel@tonic-gate #define kbytes(bytes) (((bytes) + 1023) / 1024) 1329*7c478bd9Sstevel@tonic-gate 1330*7c478bd9Sstevel@tonic-gate static int 1331*7c478bd9Sstevel@tonic-gate list(file, stp) 1332*7c478bd9Sstevel@tonic-gate char *file; 1333*7c478bd9Sstevel@tonic-gate struct stat *stp; 1334*7c478bd9Sstevel@tonic-gate { 1335*7c478bd9Sstevel@tonic-gate char pmode[32], uname[32], gname[32], fsize[32], ftime[32]; 1336*7c478bd9Sstevel@tonic-gate 1337*7c478bd9Sstevel@tonic-gate 1338*7c478bd9Sstevel@tonic-gate /* 1339*7c478bd9Sstevel@tonic-gate * Each line below contains the relevant permission (column 1) and character 1340*7c478bd9Sstevel@tonic-gate * shown when the corresponding execute bit is either clear (column 2) 1341*7c478bd9Sstevel@tonic-gate * or set (column 3) 1342*7c478bd9Sstevel@tonic-gate * These permissions are as shown by ls(1b) 1343*7c478bd9Sstevel@tonic-gate */ 1344*7c478bd9Sstevel@tonic-gate static long special[] = { S_ISUID, 'S', 's', 1345*7c478bd9Sstevel@tonic-gate S_ISGID, 'S', 's', 1346*7c478bd9Sstevel@tonic-gate S_ISVTX, 'T', 't' }; 1347*7c478bd9Sstevel@tonic-gate 1348*7c478bd9Sstevel@tonic-gate static time_t sixmonthsago = -1; 1349*7c478bd9Sstevel@tonic-gate #ifdef S_IFLNK 1350*7c478bd9Sstevel@tonic-gate char flink[MAXPATHLEN + 1]; 1351*7c478bd9Sstevel@tonic-gate #endif 1352*7c478bd9Sstevel@tonic-gate int who; 1353*7c478bd9Sstevel@tonic-gate char *cp; 1354*7c478bd9Sstevel@tonic-gate char *tailname; 1355*7c478bd9Sstevel@tonic-gate time_t now; 1356*7c478bd9Sstevel@tonic-gate long long ksize; 1357*7c478bd9Sstevel@tonic-gate 1358*7c478bd9Sstevel@tonic-gate if (file == NULL || stp == NULL) 1359*7c478bd9Sstevel@tonic-gate return (-1); 1360*7c478bd9Sstevel@tonic-gate 1361*7c478bd9Sstevel@tonic-gate (void) time(&now); 1362*7c478bd9Sstevel@tonic-gate if (sixmonthsago == -1) 1363*7c478bd9Sstevel@tonic-gate sixmonthsago = now - 6L*30L*24L*60L*60L; 1364*7c478bd9Sstevel@tonic-gate 1365*7c478bd9Sstevel@tonic-gate switch (stp->st_mode & S_IFMT) { 1366*7c478bd9Sstevel@tonic-gate #ifdef S_IFDIR 1367*7c478bd9Sstevel@tonic-gate case S_IFDIR: /* directory */ 1368*7c478bd9Sstevel@tonic-gate pmode[0] = 'd'; 1369*7c478bd9Sstevel@tonic-gate break; 1370*7c478bd9Sstevel@tonic-gate #endif 1371*7c478bd9Sstevel@tonic-gate #ifdef S_IFCHR 1372*7c478bd9Sstevel@tonic-gate case S_IFCHR: /* character special */ 1373*7c478bd9Sstevel@tonic-gate pmode[0] = 'c'; 1374*7c478bd9Sstevel@tonic-gate break; 1375*7c478bd9Sstevel@tonic-gate #endif 1376*7c478bd9Sstevel@tonic-gate #ifdef S_IFBLK 1377*7c478bd9Sstevel@tonic-gate case S_IFBLK: /* block special */ 1378*7c478bd9Sstevel@tonic-gate pmode[0] = 'b'; 1379*7c478bd9Sstevel@tonic-gate break; 1380*7c478bd9Sstevel@tonic-gate #endif 1381*7c478bd9Sstevel@tonic-gate #ifdef S_IFIFO 1382*7c478bd9Sstevel@tonic-gate case S_IFIFO: /* fifo special */ 1383*7c478bd9Sstevel@tonic-gate pmode[0] = 'p'; 1384*7c478bd9Sstevel@tonic-gate break; 1385*7c478bd9Sstevel@tonic-gate #endif 1386*7c478bd9Sstevel@tonic-gate #ifdef S_IFLNK 1387*7c478bd9Sstevel@tonic-gate case S_IFLNK: /* symbolic link */ 1388*7c478bd9Sstevel@tonic-gate pmode[0] = 'l'; 1389*7c478bd9Sstevel@tonic-gate break; 1390*7c478bd9Sstevel@tonic-gate #endif 1391*7c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK 1392*7c478bd9Sstevel@tonic-gate case S_IFSOCK: /* socket */ 1393*7c478bd9Sstevel@tonic-gate pmode[0] = 's'; 1394*7c478bd9Sstevel@tonic-gate break; 1395*7c478bd9Sstevel@tonic-gate #endif 1396*7c478bd9Sstevel@tonic-gate #ifdef S_IFDOOR 1397*7c478bd9Sstevel@tonic-gate case S_IFDOOR: /* door */ 1398*7c478bd9Sstevel@tonic-gate pmode[0] = 'D'; 1399*7c478bd9Sstevel@tonic-gate break; 1400*7c478bd9Sstevel@tonic-gate #endif 1401*7c478bd9Sstevel@tonic-gate #ifdef S_IFREG 1402*7c478bd9Sstevel@tonic-gate case S_IFREG: /* regular */ 1403*7c478bd9Sstevel@tonic-gate pmode[0] = '-'; 1404*7c478bd9Sstevel@tonic-gate break; 1405*7c478bd9Sstevel@tonic-gate #endif 1406*7c478bd9Sstevel@tonic-gate default: 1407*7c478bd9Sstevel@tonic-gate pmode[0] = '?'; 1408*7c478bd9Sstevel@tonic-gate break; 1409*7c478bd9Sstevel@tonic-gate } 1410*7c478bd9Sstevel@tonic-gate 1411*7c478bd9Sstevel@tonic-gate for (who = 0; who < 3; who++) { 1412*7c478bd9Sstevel@tonic-gate int is_exec = stp->st_mode & permission(who, S_IEXEC)? 1 : 0; 1413*7c478bd9Sstevel@tonic-gate 1414*7c478bd9Sstevel@tonic-gate if (stp->st_mode & permission(who, S_IREAD)) 1415*7c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 1] = 'r'; 1416*7c478bd9Sstevel@tonic-gate else 1417*7c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 1] = '-'; 1418*7c478bd9Sstevel@tonic-gate 1419*7c478bd9Sstevel@tonic-gate if (stp->st_mode & permission(who, S_IWRITE)) 1420*7c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 2] = 'w'; 1421*7c478bd9Sstevel@tonic-gate else 1422*7c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 2] = '-'; 1423*7c478bd9Sstevel@tonic-gate 1424*7c478bd9Sstevel@tonic-gate if (stp->st_mode & special[who * 3]) 1425*7c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 3] = 1426*7c478bd9Sstevel@tonic-gate special[who * 3 + 1 + is_exec]; 1427*7c478bd9Sstevel@tonic-gate else if (is_exec) 1428*7c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 3] = 'x'; 1429*7c478bd9Sstevel@tonic-gate else 1430*7c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 3] = '-'; 1431*7c478bd9Sstevel@tonic-gate } 1432*7c478bd9Sstevel@tonic-gate 1433*7c478bd9Sstevel@tonic-gate /* 1434*7c478bd9Sstevel@tonic-gate * Need to get the tail of the file name, since we have 1435*7c478bd9Sstevel@tonic-gate * already chdir()ed into the directory of the file 1436*7c478bd9Sstevel@tonic-gate */ 1437*7c478bd9Sstevel@tonic-gate 1438*7c478bd9Sstevel@tonic-gate tailname = gettail(file); 1439*7c478bd9Sstevel@tonic-gate 1440*7c478bd9Sstevel@tonic-gate if (acl(tailname, GETACLCNT, 0, NULL) > MIN_ACL_ENTRIES) 1441*7c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 1] = '+'; 1442*7c478bd9Sstevel@tonic-gate else 1443*7c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 1] = ' '; 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate pmode[permoffset(who) + 2] = '\0'; 1446*7c478bd9Sstevel@tonic-gate 1447*7c478bd9Sstevel@tonic-gate /* 1448*7c478bd9Sstevel@tonic-gate * Prepare uname and gname. Always add a space afterwards 1449*7c478bd9Sstevel@tonic-gate * to keep columns from running together. 1450*7c478bd9Sstevel@tonic-gate */ 1451*7c478bd9Sstevel@tonic-gate cp = getname(stp->st_uid); 1452*7c478bd9Sstevel@tonic-gate if (cp != NULL) 1453*7c478bd9Sstevel@tonic-gate (void) sprintf(uname, "%-8s ", cp); 1454*7c478bd9Sstevel@tonic-gate else 1455*7c478bd9Sstevel@tonic-gate (void) sprintf(uname, "%-8ld ", stp->st_uid); 1456*7c478bd9Sstevel@tonic-gate 1457*7c478bd9Sstevel@tonic-gate cp = getgroup(stp->st_gid); 1458*7c478bd9Sstevel@tonic-gate if (cp != NULL) 1459*7c478bd9Sstevel@tonic-gate (void) sprintf(gname, "%-8s ", cp); 1460*7c478bd9Sstevel@tonic-gate else 1461*7c478bd9Sstevel@tonic-gate (void) sprintf(gname, "%-8ld ", stp->st_gid); 1462*7c478bd9Sstevel@tonic-gate 1463*7c478bd9Sstevel@tonic-gate if (pmode[0] == 'b' || pmode[0] == 'c') 1464*7c478bd9Sstevel@tonic-gate (void) sprintf(fsize, "%3ld,%4ld", 1465*7c478bd9Sstevel@tonic-gate major(stp->st_rdev), minor(stp->st_rdev)); 1466*7c478bd9Sstevel@tonic-gate else { 1467*7c478bd9Sstevel@tonic-gate (void) sprintf(fsize, (stp->st_size < 100000000) ? 1468*7c478bd9Sstevel@tonic-gate "%8lld" : "%lld", stp->st_size); 1469*7c478bd9Sstevel@tonic-gate #ifdef S_IFLNK 1470*7c478bd9Sstevel@tonic-gate if (pmode[0] == 'l') { 1471*7c478bd9Sstevel@tonic-gate 1472*7c478bd9Sstevel@tonic-gate 1473*7c478bd9Sstevel@tonic-gate who = readlink(tailname, flink, sizeof (flink) - 1); 1474*7c478bd9Sstevel@tonic-gate 1475*7c478bd9Sstevel@tonic-gate if (who >= 0) 1476*7c478bd9Sstevel@tonic-gate flink[who] = '\0'; 1477*7c478bd9Sstevel@tonic-gate else 1478*7c478bd9Sstevel@tonic-gate flink[0] = '\0'; 1479*7c478bd9Sstevel@tonic-gate } 1480*7c478bd9Sstevel@tonic-gate #endif 1481*7c478bd9Sstevel@tonic-gate } 1482*7c478bd9Sstevel@tonic-gate 1483*7c478bd9Sstevel@tonic-gate cp = ctime(&stp->st_mtime); 1484*7c478bd9Sstevel@tonic-gate if (stp->st_mtime < sixmonthsago || stp->st_mtime > now) 1485*7c478bd9Sstevel@tonic-gate (void) sprintf(ftime, "%-7.7s %-4.4s", cp + 4, cp + 20); 1486*7c478bd9Sstevel@tonic-gate else 1487*7c478bd9Sstevel@tonic-gate (void) sprintf(ftime, "%-12.12s", cp + 4); 1488*7c478bd9Sstevel@tonic-gate 1489*7c478bd9Sstevel@tonic-gate (void) printf((stp->st_ino < 100000) ? "%5llu " : 1490*7c478bd9Sstevel@tonic-gate "%llu ", stp->st_ino); /* inode # */ 1491*7c478bd9Sstevel@tonic-gate #ifdef S_IFSOCK 1492*7c478bd9Sstevel@tonic-gate ksize = (long long) kbytes(ldbtob(stp->st_blocks)); /* kbytes */ 1493*7c478bd9Sstevel@tonic-gate #else 1494*7c478bd9Sstevel@tonic-gate ksize = (long long) kbytes(stp->st_size); /* kbytes */ 1495*7c478bd9Sstevel@tonic-gate #endif 1496*7c478bd9Sstevel@tonic-gate (void) printf((ksize < 10000) ? "%4lld " : "%lld ", ksize); 1497*7c478bd9Sstevel@tonic-gate (void) printf("%s %2ld %s%s%s %s %s%s%s\n", 1498*7c478bd9Sstevel@tonic-gate pmode, /* protection */ 1499*7c478bd9Sstevel@tonic-gate stp->st_nlink, /* # of links */ 1500*7c478bd9Sstevel@tonic-gate uname, /* owner */ 1501*7c478bd9Sstevel@tonic-gate gname, /* group */ 1502*7c478bd9Sstevel@tonic-gate fsize, /* # of bytes */ 1503*7c478bd9Sstevel@tonic-gate ftime, /* modify time */ 1504*7c478bd9Sstevel@tonic-gate file, /* name */ 1505*7c478bd9Sstevel@tonic-gate #ifdef S_IFLNK 1506*7c478bd9Sstevel@tonic-gate (pmode[0] == 'l') ? " -> " : "", 1507*7c478bd9Sstevel@tonic-gate (pmode[0] == 'l') ? flink : "" /* symlink */ 1508*7c478bd9Sstevel@tonic-gate #else 1509*7c478bd9Sstevel@tonic-gate "", 1510*7c478bd9Sstevel@tonic-gate "" 1511*7c478bd9Sstevel@tonic-gate #endif 1512*7c478bd9Sstevel@tonic-gate ); 1513*7c478bd9Sstevel@tonic-gate 1514*7c478bd9Sstevel@tonic-gate return (0); 1515*7c478bd9Sstevel@tonic-gate } 1516*7c478bd9Sstevel@tonic-gate 1517*7c478bd9Sstevel@tonic-gate static char * 1518*7c478bd9Sstevel@tonic-gate new_string(char *s) 1519*7c478bd9Sstevel@tonic-gate { 1520*7c478bd9Sstevel@tonic-gate char *p = strdup(s); 1521*7c478bd9Sstevel@tonic-gate 1522*7c478bd9Sstevel@tonic-gate if (p) 1523*7c478bd9Sstevel@tonic-gate return (p); 1524*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: out of memory\n"), cmdname); 1525*7c478bd9Sstevel@tonic-gate exit(1); 1526*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1527*7c478bd9Sstevel@tonic-gate } 1528*7c478bd9Sstevel@tonic-gate 1529*7c478bd9Sstevel@tonic-gate /* 1530*7c478bd9Sstevel@tonic-gate * Read remote file system types from REMOTE_FS into the 1531*7c478bd9Sstevel@tonic-gate * remote_fstypes array. 1532*7c478bd9Sstevel@tonic-gate */ 1533*7c478bd9Sstevel@tonic-gate static void 1534*7c478bd9Sstevel@tonic-gate init_remote_fs() 1535*7c478bd9Sstevel@tonic-gate { 1536*7c478bd9Sstevel@tonic-gate FILE *fp; 1537*7c478bd9Sstevel@tonic-gate char line_buf[LINEBUF_SIZE]; 1538*7c478bd9Sstevel@tonic-gate 1539*7c478bd9Sstevel@tonic-gate if ((fp = fopen(REMOTE_FS, "r")) == NULL) { 1540*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1541*7c478bd9Sstevel@tonic-gate gettext("%s: Warning: can't open %s, ignored\n"), 1542*7c478bd9Sstevel@tonic-gate REMOTE_FS, cmdname); 1543*7c478bd9Sstevel@tonic-gate /* Use default string name for NFS */ 1544*7c478bd9Sstevel@tonic-gate remote_fstypes[fstype_index++] = "nfs"; 1545*7c478bd9Sstevel@tonic-gate return; 1546*7c478bd9Sstevel@tonic-gate } 1547*7c478bd9Sstevel@tonic-gate 1548*7c478bd9Sstevel@tonic-gate while (fgets(line_buf, sizeof (line_buf), fp) != NULL) { 1549*7c478bd9Sstevel@tonic-gate char buf[LINEBUF_SIZE]; 1550*7c478bd9Sstevel@tonic-gate 1551*7c478bd9Sstevel@tonic-gate /* LINTED - unbounded string specifier */ 1552*7c478bd9Sstevel@tonic-gate (void) sscanf(line_buf, "%s", buf); 1553*7c478bd9Sstevel@tonic-gate remote_fstypes[fstype_index++] = new_string(buf); 1554*7c478bd9Sstevel@tonic-gate 1555*7c478bd9Sstevel@tonic-gate if (fstype_index == N_FSTYPES) 1556*7c478bd9Sstevel@tonic-gate break; 1557*7c478bd9Sstevel@tonic-gate } 1558*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 1559*7c478bd9Sstevel@tonic-gate } 1560*7c478bd9Sstevel@tonic-gate 1561*7c478bd9Sstevel@tonic-gate #define NPERM 30 /* Largest machine */ 1562*7c478bd9Sstevel@tonic-gate 1563*7c478bd9Sstevel@tonic-gate /* 1564*7c478bd9Sstevel@tonic-gate * The PERM struct is the machine that builds permissions. The p_special 1565*7c478bd9Sstevel@tonic-gate * field contains what permissions need to be checked at run-time in 1566*7c478bd9Sstevel@tonic-gate * getmode(). This is one of 'X', 'u', 'g', or 'o'. It contains '\0' to 1567*7c478bd9Sstevel@tonic-gate * indicate normal processing. 1568*7c478bd9Sstevel@tonic-gate */ 1569*7c478bd9Sstevel@tonic-gate typedef struct PERMST { 1570*7c478bd9Sstevel@tonic-gate ushort_t p_who; /* Range of permission (e.g. ugo) */ 1571*7c478bd9Sstevel@tonic-gate ushort_t p_perm; /* Bits to turn on, off, assign */ 1572*7c478bd9Sstevel@tonic-gate uchar_t p_op; /* Operation: + - = */ 1573*7c478bd9Sstevel@tonic-gate uchar_t p_special; /* Special handling? */ 1574*7c478bd9Sstevel@tonic-gate } PERMST; 1575*7c478bd9Sstevel@tonic-gate 1576*7c478bd9Sstevel@tonic-gate #ifndef S_ISVTX 1577*7c478bd9Sstevel@tonic-gate #define S_ISVTX 0 /* Not .1 */ 1578*7c478bd9Sstevel@tonic-gate #endif 1579*7c478bd9Sstevel@tonic-gate 1580*7c478bd9Sstevel@tonic-gate /* Mask values */ 1581*7c478bd9Sstevel@tonic-gate #define P_A (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) /* allbits */ 1582*7c478bd9Sstevel@tonic-gate #define P_U (S_ISUID|S_ISVTX|S_IRWXU) /* user */ 1583*7c478bd9Sstevel@tonic-gate #define P_G (S_ISGID|S_ISVTX|S_IRWXG) /* group */ 1584*7c478bd9Sstevel@tonic-gate #define P_O (S_ISVTX|S_IRWXO) /* other */ 1585*7c478bd9Sstevel@tonic-gate 1586*7c478bd9Sstevel@tonic-gate static int iswho(int c); 1587*7c478bd9Sstevel@tonic-gate static int isop(int c); 1588*7c478bd9Sstevel@tonic-gate static int isperm(PERMST *pp, int c); 1589*7c478bd9Sstevel@tonic-gate 1590*7c478bd9Sstevel@tonic-gate static PERMST machine[NPERM]; /* Permission construction machine */ 1591*7c478bd9Sstevel@tonic-gate static PERMST *endp; /* Last used PERM structure */ 1592*7c478bd9Sstevel@tonic-gate 1593*7c478bd9Sstevel@tonic-gate static uint_t nowho; /* No who for this mode (DOS kludge) */ 1594*7c478bd9Sstevel@tonic-gate 1595*7c478bd9Sstevel@tonic-gate /* 1596*7c478bd9Sstevel@tonic-gate * Read an ASCII string containing the symbolic/octal mode and 1597*7c478bd9Sstevel@tonic-gate * compile an automaton that recognizes it. The return value 1598*7c478bd9Sstevel@tonic-gate * is NULL if everything is OK, otherwise it is -1. 1599*7c478bd9Sstevel@tonic-gate */ 1600*7c478bd9Sstevel@tonic-gate static int 1601*7c478bd9Sstevel@tonic-gate readmode(ascmode) 1602*7c478bd9Sstevel@tonic-gate const char *ascmode; 1603*7c478bd9Sstevel@tonic-gate { 1604*7c478bd9Sstevel@tonic-gate const char *amode = ascmode; 1605*7c478bd9Sstevel@tonic-gate PERMST *pp; 1606*7c478bd9Sstevel@tonic-gate int seen_X; 1607*7c478bd9Sstevel@tonic-gate 1608*7c478bd9Sstevel@tonic-gate nowho = 0; 1609*7c478bd9Sstevel@tonic-gate seen_X = 0; 1610*7c478bd9Sstevel@tonic-gate pp = &machine[0]; 1611*7c478bd9Sstevel@tonic-gate if (*amode >= '0' && *amode <= '7') { 1612*7c478bd9Sstevel@tonic-gate int mode; 1613*7c478bd9Sstevel@tonic-gate 1614*7c478bd9Sstevel@tonic-gate mode = 0; 1615*7c478bd9Sstevel@tonic-gate while (*amode >= '0' && *amode <= '7') 1616*7c478bd9Sstevel@tonic-gate mode = (mode<<3) + *amode++ - '0'; 1617*7c478bd9Sstevel@tonic-gate if (*amode != '\0') 1618*7c478bd9Sstevel@tonic-gate return (-1); 1619*7c478bd9Sstevel@tonic-gate #if S_ISUID != 04000 || S_ISGID != 02000 || \ 1620*7c478bd9Sstevel@tonic-gate S_IRUSR != 0400 || S_IWUSR != 0200 || S_IXUSR != 0100 || \ 1621*7c478bd9Sstevel@tonic-gate S_IRGRP != 0040 || S_IWGRP != 0020 || S_IXGRP != 0010 || \ 1622*7c478bd9Sstevel@tonic-gate S_IROTH != 0004 || S_IWOTH != 0002 || S_IXOTH != 0001 1623*7c478bd9Sstevel@tonic-gate /* 1624*7c478bd9Sstevel@tonic-gate * There is no requirement of the octal mode bits being 1625*7c478bd9Sstevel@tonic-gate * the same as the S_ macros. 1626*7c478bd9Sstevel@tonic-gate */ 1627*7c478bd9Sstevel@tonic-gate { 1628*7c478bd9Sstevel@tonic-gate mode_t mapping[] = { 1629*7c478bd9Sstevel@tonic-gate S_IXOTH, S_IWOTH, S_IROTH, 1630*7c478bd9Sstevel@tonic-gate S_IXGRP, S_IWGRP, S_IRGRP, 1631*7c478bd9Sstevel@tonic-gate S_IXUSR, S_IWUSR, S_IRUSR, 1632*7c478bd9Sstevel@tonic-gate S_ISGID, S_ISUID, 1633*7c478bd9Sstevel@tonic-gate 0 1634*7c478bd9Sstevel@tonic-gate }; 1635*7c478bd9Sstevel@tonic-gate int i, newmode = 0; 1636*7c478bd9Sstevel@tonic-gate 1637*7c478bd9Sstevel@tonic-gate for (i = 0; mapping[i] != 0; i++) 1638*7c478bd9Sstevel@tonic-gate if (mode & (1<<i)) 1639*7c478bd9Sstevel@tonic-gate newmode |= mapping[i]; 1640*7c478bd9Sstevel@tonic-gate mode = newmode; 1641*7c478bd9Sstevel@tonic-gate } 1642*7c478bd9Sstevel@tonic-gate #endif 1643*7c478bd9Sstevel@tonic-gate pp->p_who = P_A; 1644*7c478bd9Sstevel@tonic-gate pp->p_perm = mode; 1645*7c478bd9Sstevel@tonic-gate pp->p_op = '='; 1646*7c478bd9Sstevel@tonic-gate } else for (;;) { 1647*7c478bd9Sstevel@tonic-gate int t; 1648*7c478bd9Sstevel@tonic-gate int who = 0; 1649*7c478bd9Sstevel@tonic-gate 1650*7c478bd9Sstevel@tonic-gate while ((t = iswho(*amode)) != 0) { 1651*7c478bd9Sstevel@tonic-gate ++amode; 1652*7c478bd9Sstevel@tonic-gate who |= t; 1653*7c478bd9Sstevel@tonic-gate } 1654*7c478bd9Sstevel@tonic-gate if (who == 0) { 1655*7c478bd9Sstevel@tonic-gate mode_t currmask; 1656*7c478bd9Sstevel@tonic-gate (void) umask(currmask = umask((mode_t)0)); 1657*7c478bd9Sstevel@tonic-gate 1658*7c478bd9Sstevel@tonic-gate /* 1659*7c478bd9Sstevel@tonic-gate * If no who specified, must use contents of 1660*7c478bd9Sstevel@tonic-gate * umask to determine which bits to flip. This 1661*7c478bd9Sstevel@tonic-gate * is POSIX/V7/BSD behaviour, but not SVID. 1662*7c478bd9Sstevel@tonic-gate */ 1663*7c478bd9Sstevel@tonic-gate who = (~currmask)&P_A; 1664*7c478bd9Sstevel@tonic-gate ++nowho; 1665*7c478bd9Sstevel@tonic-gate } else 1666*7c478bd9Sstevel@tonic-gate nowho = 0; 1667*7c478bd9Sstevel@tonic-gate samewho: 1668*7c478bd9Sstevel@tonic-gate if (!isop(pp->p_op = *amode++)) 1669*7c478bd9Sstevel@tonic-gate return (-1); 1670*7c478bd9Sstevel@tonic-gate pp->p_perm = 0; 1671*7c478bd9Sstevel@tonic-gate pp->p_special = 0; 1672*7c478bd9Sstevel@tonic-gate while ((t = isperm(pp, *amode)) != 0) { 1673*7c478bd9Sstevel@tonic-gate if (pp->p_special == 'X') { 1674*7c478bd9Sstevel@tonic-gate seen_X = 1; 1675*7c478bd9Sstevel@tonic-gate 1676*7c478bd9Sstevel@tonic-gate if (pp->p_perm != 0) { 1677*7c478bd9Sstevel@tonic-gate ushort_t op; 1678*7c478bd9Sstevel@tonic-gate 1679*7c478bd9Sstevel@tonic-gate /* 1680*7c478bd9Sstevel@tonic-gate * Remember the 'who' for the previous 1681*7c478bd9Sstevel@tonic-gate * transformation. 1682*7c478bd9Sstevel@tonic-gate */ 1683*7c478bd9Sstevel@tonic-gate pp->p_who = who; 1684*7c478bd9Sstevel@tonic-gate pp->p_special = 0; 1685*7c478bd9Sstevel@tonic-gate 1686*7c478bd9Sstevel@tonic-gate op = pp->p_op; 1687*7c478bd9Sstevel@tonic-gate 1688*7c478bd9Sstevel@tonic-gate /* Keep 'X' separate */ 1689*7c478bd9Sstevel@tonic-gate ++pp; 1690*7c478bd9Sstevel@tonic-gate pp->p_special = 'X'; 1691*7c478bd9Sstevel@tonic-gate pp->p_op = op; 1692*7c478bd9Sstevel@tonic-gate } 1693*7c478bd9Sstevel@tonic-gate } else if (seen_X) { 1694*7c478bd9Sstevel@tonic-gate ushort_t op; 1695*7c478bd9Sstevel@tonic-gate 1696*7c478bd9Sstevel@tonic-gate /* Remember the 'who' for the X */ 1697*7c478bd9Sstevel@tonic-gate pp->p_who = who; 1698*7c478bd9Sstevel@tonic-gate 1699*7c478bd9Sstevel@tonic-gate op = pp->p_op; 1700*7c478bd9Sstevel@tonic-gate 1701*7c478bd9Sstevel@tonic-gate /* Keep 'X' separate */ 1702*7c478bd9Sstevel@tonic-gate ++pp; 1703*7c478bd9Sstevel@tonic-gate pp->p_perm = 0; 1704*7c478bd9Sstevel@tonic-gate pp->p_special = 0; 1705*7c478bd9Sstevel@tonic-gate pp->p_op = op; 1706*7c478bd9Sstevel@tonic-gate } 1707*7c478bd9Sstevel@tonic-gate ++amode; 1708*7c478bd9Sstevel@tonic-gate pp->p_perm |= t; 1709*7c478bd9Sstevel@tonic-gate } 1710*7c478bd9Sstevel@tonic-gate 1711*7c478bd9Sstevel@tonic-gate /* 1712*7c478bd9Sstevel@tonic-gate * These returned 0, but were actually parsed, so 1713*7c478bd9Sstevel@tonic-gate * don't look at them again. 1714*7c478bd9Sstevel@tonic-gate */ 1715*7c478bd9Sstevel@tonic-gate switch (pp->p_special) { 1716*7c478bd9Sstevel@tonic-gate case 'u': 1717*7c478bd9Sstevel@tonic-gate case 'g': 1718*7c478bd9Sstevel@tonic-gate case 'o': 1719*7c478bd9Sstevel@tonic-gate ++amode; 1720*7c478bd9Sstevel@tonic-gate break; 1721*7c478bd9Sstevel@tonic-gate } 1722*7c478bd9Sstevel@tonic-gate pp->p_who = who; 1723*7c478bd9Sstevel@tonic-gate switch (*amode) { 1724*7c478bd9Sstevel@tonic-gate case '\0': 1725*7c478bd9Sstevel@tonic-gate break; 1726*7c478bd9Sstevel@tonic-gate 1727*7c478bd9Sstevel@tonic-gate case ',': 1728*7c478bd9Sstevel@tonic-gate ++amode; 1729*7c478bd9Sstevel@tonic-gate ++pp; 1730*7c478bd9Sstevel@tonic-gate continue; 1731*7c478bd9Sstevel@tonic-gate 1732*7c478bd9Sstevel@tonic-gate default: 1733*7c478bd9Sstevel@tonic-gate ++pp; 1734*7c478bd9Sstevel@tonic-gate goto samewho; 1735*7c478bd9Sstevel@tonic-gate } 1736*7c478bd9Sstevel@tonic-gate break; 1737*7c478bd9Sstevel@tonic-gate } 1738*7c478bd9Sstevel@tonic-gate endp = pp; 1739*7c478bd9Sstevel@tonic-gate return (NULL); 1740*7c478bd9Sstevel@tonic-gate } 1741*7c478bd9Sstevel@tonic-gate 1742*7c478bd9Sstevel@tonic-gate /* 1743*7c478bd9Sstevel@tonic-gate * Given a character from the mode, return the associated 1744*7c478bd9Sstevel@tonic-gate * value as who (user designation) mask or 0 if this isn't valid. 1745*7c478bd9Sstevel@tonic-gate */ 1746*7c478bd9Sstevel@tonic-gate static int 1747*7c478bd9Sstevel@tonic-gate iswho(c) 1748*7c478bd9Sstevel@tonic-gate int c; 1749*7c478bd9Sstevel@tonic-gate { 1750*7c478bd9Sstevel@tonic-gate switch (c) { 1751*7c478bd9Sstevel@tonic-gate case 'a': 1752*7c478bd9Sstevel@tonic-gate return (P_A); 1753*7c478bd9Sstevel@tonic-gate 1754*7c478bd9Sstevel@tonic-gate case 'u': 1755*7c478bd9Sstevel@tonic-gate return (P_U); 1756*7c478bd9Sstevel@tonic-gate 1757*7c478bd9Sstevel@tonic-gate case 'g': 1758*7c478bd9Sstevel@tonic-gate return (P_G); 1759*7c478bd9Sstevel@tonic-gate 1760*7c478bd9Sstevel@tonic-gate case 'o': 1761*7c478bd9Sstevel@tonic-gate return (P_O); 1762*7c478bd9Sstevel@tonic-gate 1763*7c478bd9Sstevel@tonic-gate default: 1764*7c478bd9Sstevel@tonic-gate return (0); 1765*7c478bd9Sstevel@tonic-gate } 1766*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1767*7c478bd9Sstevel@tonic-gate } 1768*7c478bd9Sstevel@tonic-gate 1769*7c478bd9Sstevel@tonic-gate /* 1770*7c478bd9Sstevel@tonic-gate * Return non-zero if this is a valid op code 1771*7c478bd9Sstevel@tonic-gate * in a symbolic mode. 1772*7c478bd9Sstevel@tonic-gate */ 1773*7c478bd9Sstevel@tonic-gate static int 1774*7c478bd9Sstevel@tonic-gate isop(c) 1775*7c478bd9Sstevel@tonic-gate int c; 1776*7c478bd9Sstevel@tonic-gate { 1777*7c478bd9Sstevel@tonic-gate switch (c) { 1778*7c478bd9Sstevel@tonic-gate case '+': 1779*7c478bd9Sstevel@tonic-gate case '-': 1780*7c478bd9Sstevel@tonic-gate case '=': 1781*7c478bd9Sstevel@tonic-gate return (1); 1782*7c478bd9Sstevel@tonic-gate 1783*7c478bd9Sstevel@tonic-gate default: 1784*7c478bd9Sstevel@tonic-gate return (0); 1785*7c478bd9Sstevel@tonic-gate } 1786*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1787*7c478bd9Sstevel@tonic-gate } 1788*7c478bd9Sstevel@tonic-gate 1789*7c478bd9Sstevel@tonic-gate /* 1790*7c478bd9Sstevel@tonic-gate * Return the permission bits implied by this character or 0 1791*7c478bd9Sstevel@tonic-gate * if it isn't valid. Also returns 0 when the pseudo-permissions 'u', 'g', or 1792*7c478bd9Sstevel@tonic-gate * 'o' are used, and sets pp->p_special to the one used. 1793*7c478bd9Sstevel@tonic-gate */ 1794*7c478bd9Sstevel@tonic-gate static int 1795*7c478bd9Sstevel@tonic-gate isperm(pp, c) 1796*7c478bd9Sstevel@tonic-gate PERMST *pp; 1797*7c478bd9Sstevel@tonic-gate int c; 1798*7c478bd9Sstevel@tonic-gate { 1799*7c478bd9Sstevel@tonic-gate switch (c) { 1800*7c478bd9Sstevel@tonic-gate case 'u': 1801*7c478bd9Sstevel@tonic-gate case 'g': 1802*7c478bd9Sstevel@tonic-gate case 'o': 1803*7c478bd9Sstevel@tonic-gate pp->p_special = c; 1804*7c478bd9Sstevel@tonic-gate return (0); 1805*7c478bd9Sstevel@tonic-gate 1806*7c478bd9Sstevel@tonic-gate case 'r': 1807*7c478bd9Sstevel@tonic-gate return (S_IRUSR|S_IRGRP|S_IROTH); 1808*7c478bd9Sstevel@tonic-gate 1809*7c478bd9Sstevel@tonic-gate case 'w': 1810*7c478bd9Sstevel@tonic-gate return (S_IWUSR|S_IWGRP|S_IWOTH); 1811*7c478bd9Sstevel@tonic-gate 1812*7c478bd9Sstevel@tonic-gate case 'x': 1813*7c478bd9Sstevel@tonic-gate return (S_IXUSR|S_IXGRP|S_IXOTH); 1814*7c478bd9Sstevel@tonic-gate 1815*7c478bd9Sstevel@tonic-gate #if S_ISVTX != 0 1816*7c478bd9Sstevel@tonic-gate case 't': 1817*7c478bd9Sstevel@tonic-gate return (S_ISVTX); 1818*7c478bd9Sstevel@tonic-gate #endif 1819*7c478bd9Sstevel@tonic-gate 1820*7c478bd9Sstevel@tonic-gate case 'X': 1821*7c478bd9Sstevel@tonic-gate pp->p_special = 'X'; 1822*7c478bd9Sstevel@tonic-gate return (S_IXUSR|S_IXGRP|S_IXOTH); 1823*7c478bd9Sstevel@tonic-gate 1824*7c478bd9Sstevel@tonic-gate #if S_ISVTX != 0 1825*7c478bd9Sstevel@tonic-gate case 'a': 1826*7c478bd9Sstevel@tonic-gate return (S_ISVTX); 1827*7c478bd9Sstevel@tonic-gate #endif 1828*7c478bd9Sstevel@tonic-gate 1829*7c478bd9Sstevel@tonic-gate case 'h': 1830*7c478bd9Sstevel@tonic-gate return (S_ISUID); 1831*7c478bd9Sstevel@tonic-gate 1832*7c478bd9Sstevel@tonic-gate /* 1833*7c478bd9Sstevel@tonic-gate * This change makes: 1834*7c478bd9Sstevel@tonic-gate * chmod +s file 1835*7c478bd9Sstevel@tonic-gate * set the system bit on dos but means that 1836*7c478bd9Sstevel@tonic-gate * chmod u+s file 1837*7c478bd9Sstevel@tonic-gate * chmod g+s file 1838*7c478bd9Sstevel@tonic-gate * chmod a+s file 1839*7c478bd9Sstevel@tonic-gate * are all like UNIX. 1840*7c478bd9Sstevel@tonic-gate */ 1841*7c478bd9Sstevel@tonic-gate case 's': 1842*7c478bd9Sstevel@tonic-gate return (nowho ? S_ISGID : S_ISGID|S_ISUID); 1843*7c478bd9Sstevel@tonic-gate 1844*7c478bd9Sstevel@tonic-gate default: 1845*7c478bd9Sstevel@tonic-gate return (0); 1846*7c478bd9Sstevel@tonic-gate } 1847*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 1848*7c478bd9Sstevel@tonic-gate } 1849*7c478bd9Sstevel@tonic-gate 1850*7c478bd9Sstevel@tonic-gate /* 1851*7c478bd9Sstevel@tonic-gate * Execute the automaton that is created by readmode() 1852*7c478bd9Sstevel@tonic-gate * to generate the final mode that will be used. This 1853*7c478bd9Sstevel@tonic-gate * code is passed a starting mode that is usually the original 1854*7c478bd9Sstevel@tonic-gate * mode of the file being changed (or 0). Note that this mode must contain 1855*7c478bd9Sstevel@tonic-gate * the file-type bits as well, so that S_ISDIR will succeed on directories. 1856*7c478bd9Sstevel@tonic-gate */ 1857*7c478bd9Sstevel@tonic-gate static mode_t 1858*7c478bd9Sstevel@tonic-gate getmode(mode_t startmode) 1859*7c478bd9Sstevel@tonic-gate { 1860*7c478bd9Sstevel@tonic-gate PERMST *pp; 1861*7c478bd9Sstevel@tonic-gate mode_t temp; 1862*7c478bd9Sstevel@tonic-gate mode_t perm; 1863*7c478bd9Sstevel@tonic-gate 1864*7c478bd9Sstevel@tonic-gate for (pp = &machine[0]; pp <= endp; ++pp) { 1865*7c478bd9Sstevel@tonic-gate perm = (mode_t)0; 1866*7c478bd9Sstevel@tonic-gate /* 1867*7c478bd9Sstevel@tonic-gate * For the special modes 'u', 'g' and 'o', the named portion 1868*7c478bd9Sstevel@tonic-gate * of the mode refers to after the previous clause has been 1869*7c478bd9Sstevel@tonic-gate * processed, while the 'X' mode refers to the contents of the 1870*7c478bd9Sstevel@tonic-gate * mode before any clauses have been processed. 1871*7c478bd9Sstevel@tonic-gate * 1872*7c478bd9Sstevel@tonic-gate * References: P1003.2/D11.2, Section 4.7.7, 1873*7c478bd9Sstevel@tonic-gate * lines 2568-2570, 2578-2583 1874*7c478bd9Sstevel@tonic-gate */ 1875*7c478bd9Sstevel@tonic-gate switch (pp->p_special) { 1876*7c478bd9Sstevel@tonic-gate case 'u': 1877*7c478bd9Sstevel@tonic-gate temp = startmode & S_IRWXU; 1878*7c478bd9Sstevel@tonic-gate if (temp & (S_IRUSR|S_IRGRP|S_IROTH)) 1879*7c478bd9Sstevel@tonic-gate perm |= ((S_IRUSR|S_IRGRP|S_IROTH) & 1880*7c478bd9Sstevel@tonic-gate pp->p_who); 1881*7c478bd9Sstevel@tonic-gate if (temp & (S_IWUSR|S_IWGRP|S_IWOTH)) 1882*7c478bd9Sstevel@tonic-gate perm |= ((S_IWUSR|S_IWGRP|S_IWOTH) & pp->p_who); 1883*7c478bd9Sstevel@tonic-gate if (temp & (S_IXUSR|S_IXGRP|S_IXOTH)) 1884*7c478bd9Sstevel@tonic-gate perm |= ((S_IXUSR|S_IXGRP|S_IXOTH) & pp->p_who); 1885*7c478bd9Sstevel@tonic-gate break; 1886*7c478bd9Sstevel@tonic-gate 1887*7c478bd9Sstevel@tonic-gate case 'g': 1888*7c478bd9Sstevel@tonic-gate temp = startmode & S_IRWXG; 1889*7c478bd9Sstevel@tonic-gate if (temp & (S_IRUSR|S_IRGRP|S_IROTH)) 1890*7c478bd9Sstevel@tonic-gate perm |= ((S_IRUSR|S_IRGRP|S_IROTH) & pp->p_who); 1891*7c478bd9Sstevel@tonic-gate if (temp & (S_IWUSR|S_IWGRP|S_IWOTH)) 1892*7c478bd9Sstevel@tonic-gate perm |= ((S_IWUSR|S_IWGRP|S_IWOTH) & pp->p_who); 1893*7c478bd9Sstevel@tonic-gate if (temp & (S_IXUSR|S_IXGRP|S_IXOTH)) 1894*7c478bd9Sstevel@tonic-gate perm |= ((S_IXUSR|S_IXGRP|S_IXOTH) & pp->p_who); 1895*7c478bd9Sstevel@tonic-gate break; 1896*7c478bd9Sstevel@tonic-gate 1897*7c478bd9Sstevel@tonic-gate case 'o': 1898*7c478bd9Sstevel@tonic-gate temp = startmode & S_IRWXO; 1899*7c478bd9Sstevel@tonic-gate if (temp & (S_IRUSR|S_IRGRP|S_IROTH)) 1900*7c478bd9Sstevel@tonic-gate perm |= ((S_IRUSR|S_IRGRP|S_IROTH) & pp->p_who); 1901*7c478bd9Sstevel@tonic-gate if (temp & (S_IWUSR|S_IWGRP|S_IWOTH)) 1902*7c478bd9Sstevel@tonic-gate perm |= ((S_IWUSR|S_IWGRP|S_IWOTH) & pp->p_who); 1903*7c478bd9Sstevel@tonic-gate if (temp & (S_IXUSR|S_IXGRP|S_IXOTH)) 1904*7c478bd9Sstevel@tonic-gate perm |= ((S_IXUSR|S_IXGRP|S_IXOTH) & pp->p_who); 1905*7c478bd9Sstevel@tonic-gate break; 1906*7c478bd9Sstevel@tonic-gate 1907*7c478bd9Sstevel@tonic-gate case 'X': 1908*7c478bd9Sstevel@tonic-gate perm = pp->p_perm; 1909*7c478bd9Sstevel@tonic-gate break; 1910*7c478bd9Sstevel@tonic-gate 1911*7c478bd9Sstevel@tonic-gate default: 1912*7c478bd9Sstevel@tonic-gate perm = pp->p_perm; 1913*7c478bd9Sstevel@tonic-gate break; 1914*7c478bd9Sstevel@tonic-gate } 1915*7c478bd9Sstevel@tonic-gate switch (pp->p_op) { 1916*7c478bd9Sstevel@tonic-gate case '-': 1917*7c478bd9Sstevel@tonic-gate startmode &= ~(perm & pp->p_who); 1918*7c478bd9Sstevel@tonic-gate break; 1919*7c478bd9Sstevel@tonic-gate 1920*7c478bd9Sstevel@tonic-gate case '=': 1921*7c478bd9Sstevel@tonic-gate startmode &= ~pp->p_who; 1922*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1923*7c478bd9Sstevel@tonic-gate case '+': 1924*7c478bd9Sstevel@tonic-gate startmode |= (perm & pp->p_who); 1925*7c478bd9Sstevel@tonic-gate break; 1926*7c478bd9Sstevel@tonic-gate } 1927*7c478bd9Sstevel@tonic-gate } 1928*7c478bd9Sstevel@tonic-gate return (startmode); 1929*7c478bd9Sstevel@tonic-gate } 1930*7c478bd9Sstevel@tonic-gate 1931*7c478bd9Sstevel@tonic-gate /* 1932*7c478bd9Sstevel@tonic-gate * Returns the last component of a path name, unless it is 1933*7c478bd9Sstevel@tonic-gate * an absolute path, in which case it returns the whole path 1934*7c478bd9Sstevel@tonic-gate */ 1935*7c478bd9Sstevel@tonic-gate static char 1936*7c478bd9Sstevel@tonic-gate *gettail(char *fname) 1937*7c478bd9Sstevel@tonic-gate { 1938*7c478bd9Sstevel@tonic-gate char *base = fname; 1939*7c478bd9Sstevel@tonic-gate 1940*7c478bd9Sstevel@tonic-gate if (*fname != '/') { 1941*7c478bd9Sstevel@tonic-gate if ((base = strrchr(fname, '/')) != NULL) 1942*7c478bd9Sstevel@tonic-gate base++; 1943*7c478bd9Sstevel@tonic-gate else 1944*7c478bd9Sstevel@tonic-gate base = fname; 1945*7c478bd9Sstevel@tonic-gate } 1946*7c478bd9Sstevel@tonic-gate return (base); 1947*7c478bd9Sstevel@tonic-gate } 1948