X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/6c57dc2bbbbb440d8d18bf6f635f4eca58a59f2d..89fb65086543e1d25e13c77570ea8bfa44ec4f48:/usr/src/usr.bin/find/find.c diff --git a/usr/src/usr.bin/find/find.c b/usr/src/usr.bin/find/find.c index 2199f6b678..3e5e6c791c 100644 --- a/usr/src/usr.bin/find/find.c +++ b/usr/src/usr.bin/find/find.c @@ -1,1214 +1,221 @@ -#ifndef lint -static char *sccsid = "@(#)find.c 4.17 (Berkeley) %G%"; -#endif - -#include -#include -#include -#include - -#define A_DAY 86400L /* a day full of seconds */ -#define EQ(x, y) (strcmp(x, y)==0) - -int Randlast; -char Pathname[MAXPATHLEN+1]; - -#define MAXNODES 100 - -struct anode { - int (*F)(); - struct anode *L, *R; -} Node[MAXNODES]; -int Nn; /* number of nodes */ -char *Fname; -long Now; -int Argc, - Ai, - Pi; -char **Argv; -/* cpio stuff */ -int Cpio; -short *Buf, *Dbuf, *Wp; -int Bufsize = 5120; -int Wct = 2560; - -long Newer; - -int Xdev = 1; /* true if SHOULD cross devices (file systems) */ -struct stat Devstat; /* stats of each argument path's file system */ - -struct stat Statb; - -struct anode *exp(), - *e1(), - *e2(), - *e3(), - *mk(); -char *nxtarg(); -char Home[MAXPATHLEN + 1]; -long Blocks; -char *rindex(); -char *sbrk(); - -/* - * SEE ALSO: updatedb, bigram.c, code.c - * Usenix ;login:, February/March, 1983, p. 8. - * - * REVISIONS: James A. Woods, Informatics General Corporation, - * NASA Ames Research Center, 6/81. +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. * - * The second form searches a pre-computed filelist - * (constructed nightly by /usr/lib/crontab) which is - * compressed by updatedb (v.i.z.) The effect of - * find - * is similar to - * find / +0 -name "**" -print - * but much faster. + * This code is derived from software contributed to Berkeley by + * Cimarron D. Taylor of the University of California, Berkeley. * - * 8/82 faster yet + incorporation of bigram coding -- jaw - * - * 1/83 incorporate glob-style matching -- jaw + * %sccs.include.redist.c% */ -#define AMES 1 -main(argc, argv) - int argc; - char *argv[]; -{ - struct anode *exlist; - int paths; - register char *cp, *sp = 0; -#ifdef SUID_PWD - FILE *pwd, *popen(); -#endif +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1990 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ -#ifdef AMES - if (argc < 2) { - fprintf(stderr, - "Usage: find name, or find path-list predicate-list\n"); - exit(1); - } - if (argc == 2) { - fastfind(argv[1]); - exit(0); - } -#endif - time(&Now); -#ifdef SUID_PWD - pwd = popen("pwd", "r"); - fgets(Home, sizeof Home, pwd); - pclose(pwd); - Home[strlen(Home) - 1] = '\0'; -#else - if (getwd(Home) == NULL) { - fprintf(stderr, "find: Can't get current working directory\n"); - exit(1); - } -#endif - Argc = argc; Argv = argv; - if(argc<3) { -usage: fprintf(stderr, "Usage: find path-list predicate-list\n"); - exit(1); - } - for(Ai = paths = 1; Ai < (argc-1); ++Ai, ++paths) - if(*Argv[Ai] == '-' || EQ(Argv[Ai], "(") || EQ(Argv[Ai], "!")) - break; - if(paths == 1) /* no path-list */ - goto usage; - if(!(exlist = exp())) { /* parse and compile the arguments */ - fprintf(stderr, "find: parsing error\n"); - exit(1); - } - if(Ai\n", s); - exit(1); - } - Buf = (short *)sbrk(512); - Wp = Dbuf = (short *)sbrk(5120); - return(mk(cpio, (struct anode *)0, (struct anode *)0)); - } - else if(EQ(a, "-newer")) { - if(stat(b, &Statb) < 0) { - fprintf(stderr, "find: cannot access < %s >\n", b); - exit(1); - } - Newer = Statb.st_mtime; - return mk(newer, (struct anode *)0, (struct anode *)0); - } -err: fprintf(stderr, "find: bad option < %s >\n", a); - exit(1); -} -struct anode *mk(f, l, r) -int (*f)(); -struct anode *l, *r; -{ - if (Nn >= MAXNODES) { - fprintf(stderr, "find: Too many options\n"); - exit(1); - } +#ifndef lint +static char sccsid[] = "@(#)find.c 4.32 (Berkeley) %G%"; +#endif /* not lint */ - Node[Nn].F = f; - Node[Nn].L = l; - Node[Nn].R = r; - return(&(Node[Nn++])); -} - -char *nxtarg() { /* get next arg from command line */ - static strikes = 0; - - if(strikes==3) { - fprintf(stderr, "find: incomplete statement\n"); - exit(1); - } - if(Ai>=Argc) { - strikes++; - Ai = Argc + 1; - return(""); - } - return(Argv[Ai++]); -} - -/* execution time functions */ -and(p) -register struct anode *p; -{ - return(((*p->L->F)(p->L)) && ((*p->R->F)(p->R))?1:0); -} -or(p) -register struct anode *p; -{ - return(((*p->L->F)(p->L)) || ((*p->R->F)(p->R))?1:0); -} -not(p) -register struct anode *p; -{ - return( !((*p->L->F)(p->L))); -} -glob(p) -register struct { int f; char *pat; } *p; -{ - return(gmatch(Fname, p->pat)); -} -print(p) -struct anode *p; -{ - puts(Pathname); - return(1); -} -mtime(p) -register struct { int f, t, s; } *p; -{ - return(scomp((int)((Now - Statb.st_mtime) / A_DAY), p->t, p->s)); -} -atime(p) -register struct { int f, t, s; } *p; -{ - return(scomp((int)((Now - Statb.st_atime) / A_DAY), p->t, p->s)); -} -user(p) -register struct { int f, u, s; } *p; -{ - return(scomp(Statb.st_uid, p->u, p->s)); -} -nouser(p) -struct anode *p; -{ - char *getname(); - - return (getname(Statb.st_uid) == NULL); -} -ino(p) -register struct { int f, u, s; } *p; -{ - return(scomp((int)Statb.st_ino, p->u, p->s)); -} -group(p) -register struct { int f, u; } *p; -{ - return(p->u == Statb.st_gid); -} -nogroup(p) -struct anode *p; -{ - char *getgroup(); - - return (getgroup(Statb.st_gid) == NULL); -} -links(p) -register struct { int f, link, s; } *p; -{ - return(scomp(Statb.st_nlink, p->link, p->s)); -} -size(p) -register struct { int f, sz, s; } *p; -{ - return(scomp((int)((Statb.st_size+511)>>9), p->sz, p->s)); -} -perm(p) -register struct { int f, per, s; } *p; -{ - register i; - i = (p->s=='-') ? p->per : 07777; /* '-' means only arg bits */ - return((Statb.st_mode & i & 07777) == p->per); -} -type(p) -register struct { int f, per, s; } *p; -{ - return((Statb.st_mode&S_IFMT)==p->per); -} -exeq(p) -register struct { int f, com; } *p; -{ - fflush(stdout); /* to flush possible `-print' */ - return(doex(p->com)); -} -ok(p) -struct { int f, com; } *p; -{ - char c; int yes; - yes = 0; - fflush(stdout); /* to flush possible `-print' */ - fprintf(stderr, "< %s ... %s > ? ", Argv[p->com], Pathname); - fflush(stderr); - if((c=getchar())=='y') yes = 1; - while(c!='\n') c = getchar(); - if(yes) return(doex(p->com)); - return(0); -} - -#define MKSHORT(v, lv) {U.l=1L;if(U.c[0]) U.l=lv, v[0]=U.s[1], v[1]=U.s[0]; else U.l=lv, v[0]=U.s[0], v[1]=U.s[1];} -union { long l; short s[2]; char c[4]; } U; -long mklong(v) -short v[]; -{ - U.l = 1; - if(U.c[0] /* VAX */) - U.s[0] = v[1], U.s[1] = v[0]; - else - U.s[0] = v[0], U.s[1] = v[1]; - return U.l; -} -cpio(p) -struct anode *p; -{ -#define MAGIC 070707 - struct header { - short h_magic, - h_dev, - h_ino, - h_mode, - h_uid, - h_gid, - h_nlink, - h_rdev; - short h_mtime[2]; - short h_namesize; - short h_filesize[2]; - char h_name[256]; - } hdr; - register ifile, ct; - static long fsz; - register i; - - hdr.h_magic = MAGIC; - strcpy(hdr.h_name, !strncmp(Pathname, "./", 2)? Pathname+2: Pathname); - hdr.h_namesize = strlen(hdr.h_name) + 1; - hdr.h_uid = Statb.st_uid; - hdr.h_gid = Statb.st_gid; - hdr.h_dev = Statb.st_dev; - hdr.h_ino = Statb.st_ino; - hdr.h_mode = Statb.st_mode; - MKSHORT(hdr.h_mtime, Statb.st_mtime); - hdr.h_nlink = Statb.st_nlink; - fsz = hdr.h_mode & S_IFREG? Statb.st_size: 0L; - MKSHORT(hdr.h_filesize, fsz); - hdr.h_rdev = Statb.st_rdev; - if(EQ(hdr.h_name, "TRAILER!!!")) { - bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize); - for(i = 0; i < 10; ++i) - bwrite(Buf, 512); - return; - } - if(!mklong(hdr.h_filesize)) - return; - if((ifile = open(Fname, 0)) < 0) { -cerror: - fprintf(stderr, "find: cannot copy < %s >\n", hdr.h_name); - return; - } - bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize); - for(fsz = mklong(hdr.h_filesize); fsz > 0; fsz -= 512) { - ct = fsz>512? 512: fsz; - if(read(ifile, (char *)Buf, ct) < 0) - goto cerror; - bwrite(Buf, ct); - } - close(ifile); - return; -} -newer(p) -struct anode *p; -{ - return Statb.st_mtime > Newer; -} -ls(p) -struct anode *p; -{ - list(Pathname, &Statb); - return (1); -} -dummy(p) -struct anode *p; -{ - /* dummy */ - return (1); -} +#include +#include +#include +#include +#include +#include +#include "find.h" -/* support functions */ -scomp(a, b, s) /* funny signed compare */ -register a, b; -register char s; -{ - if(s == '+') - return(a > b); - if(s == '-') - return(a < (b * -1)); - return(a == b); -} +FTS *tree; /* pointer to top of FTS hierarchy */ +time_t now; /* time find was run */ +int ftsoptions; /* options passed to ftsopen() */ +int deprecated; /* old or new syntax */ +int depth; /* set by -depth option */ +int output_specified; /* one of -print, -ok or -exec was specified */ -doex(com) +main(argc, argv) + int argc; + char **argv; { - register np; - register char *na; - static char *nargv[50]; - static ccode; - register int w, pid, omask; - - ccode = np = 0; - while (na=Argv[com++]) { - if(np >= sizeof nargv / sizeof *nargv - 1) break; - if(strcmp(na, ";")==0) break; - if(strcmp(na, "{}")==0) nargv[np++] = Pathname; - else nargv[np++] = na; - } - nargv[np] = 0; - if (np==0) return(9); - switch (pid = vfork()) { - case -1: - perror("find: Can't fork"); - exit(1); - break; + PLAN *plan; + char **p, **paths; + PLAN *find_formplan(); + time_t time(); + + (void)time(&now); /* initialize the time-of-day */ - case 0: - chdir(Home); - execvp(nargv[0], nargv, np); - write(2, "find: Can't execute ", 20); - perror(nargv[0]); - /* - * Kill ourselves; our exit status will be a suicide - * note indicating we couldn't do the "exec". - */ - kill(getpid(), SIGUSR1); - break; + if (argc < 2) + usage(); - default: - omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)); - while ((w = wait(&ccode)) != pid && w != -1) - ; - (void) sigsetmask(omask); - if ((ccode & 0177) == SIGUSR1) - exit(1); - return (ccode != 0 ? 0 : 1); - } -} - -getunum(f, s) char *f, *s; { /* find user/group name and return number */ - register i; - register char *sp; - register c; - char str[20]; - FILE *pin; + paths = argv; + ftsoptions = FTS_NOSTAT|FTS_PHYSICAL; - i = -1; - pin = fopen(f, "r"); - c = '\n'; /* prime with a CR */ - do { - if(c=='\n') { - sp = str; - while((c = *sp++ = getc(pin)) != ':') - if(c == EOF) goto RET; - *--sp = '\0'; - if(EQ(str, s)) { - while((c=getc(pin)) != ':') - if(c == EOF) goto RET; - sp = str; - while((*sp = getc(pin)) != ':') sp++; - *sp = '\0'; - i = atoi(str); - goto RET; + /* + * if arguments start with an option, treat it like new syntax; + * otherwise, if has a "-option" anywhere (which isn't an argument + * to another command) treat it as old syntax. + */ + if (argv[1][0] != '-') + for (p = argv + 1; *p; ++p) { + if (!strcmp(*p, "exec") || !strcmp(*p, "ok")) { + while (p[1] && strcmp(*++p, ";")); + continue; } - } - } while((c = getc(pin)) != EOF); - RET: - fclose(pin); - return(i); -} - -descend(name, fname, exlist) - struct anode *exlist; - char *name, *fname; -{ - DIR *dir = NULL; - register struct direct *dp; - register char *c1; - int rv = 0; - char *endofname; - - if (lstat(fname, &Statb)<0) { - fprintf(stderr, "find: bad status < %s >\n", name); - return(0); - } - (*exlist->F)(exlist); - if((Statb.st_mode&S_IFMT)!=S_IFDIR || - !Xdev && Devstat.st_dev != Statb.st_dev) - return(1); - - for (c1 = name; *c1; ++c1); - if (*(c1-1) == '/') - --c1; - endofname = c1; - - if (chdir(fname) == -1) - return(0); - if ((dir = opendir(".")) == NULL) { - fprintf(stderr, "find: cannot open < %s >\n", name); - rv = 0; - goto ret; - } - for (dp = readdir(dir); dp != NULL; dp = readdir(dir)) { - if ((dp->d_name[0]=='.' && dp->d_name[1]=='\0') || - (dp->d_name[0]=='.' && dp->d_name[1]=='.' && dp->d_name[2]=='\0')) - continue; - c1 = endofname; - *c1++ = '/'; - strcpy(c1, dp->d_name); - Fname = endofname+1; - if(!descend(name, Fname, exlist)) { - *endofname = '\0'; - chdir(Home); - if(chdir(Pathname) == -1) { - fprintf(stderr, "find: bad directory tree\n"); - exit(1); + if (**p == '-') { + deprecated = 1; + oldsyntax(&argv); + break; } } - } - rv = 1; -ret: - if(dir) - closedir(dir); - if(chdir("..") == -1) { - *endofname = '\0'; - fprintf(stderr, "find: bad directory <%s>\n", name); - rv = 1; - } - return(rv); + if (!deprecated) + newsyntax(argc, &argv); + + plan = find_formplan(argv); /* execution plan */ + find_execute(plan, paths); } -gmatch(s, p) /* string match as in glob */ -register char *s, *p; -{ - if (*s=='.' && *p!='.') return(0); - return amatch(s, p); -} - -amatch(s, p) -register char *s, *p; +/* + * find_formplan -- + * process the command line and create a "plan" corresponding to the + * command arguments. + */ +PLAN * +find_formplan(argv) + char **argv; { - register cc; - int scc, k; - int c, lc; + PLAN *plan, *tail, *new; + PLAN *c_print(), *find_create(), *find_squish_not(), *find_squish_or(); + PLAN *find_squish_paren(); - scc = *s; - lc = 077777; - switch (c = *p) { - - case '[': - k = 0; - while (cc = *++p) { - switch (cc) { - - case ']': - if (k) - return(amatch(++s, ++p)); - else - return(0); - - case '-': - cc = p[1]; - k |= lc <= scc && scc <= cc; - } - if (scc==(lc=cc)) k++; + /* + * for each argument in the command line, determine what kind of node + * it is, create the appropriate node type and add the new plan node + * to the end of the existing plan. The resulting plan is a linked + * list of plan nodes. For example, the string: + * + * % find . -name foo -newer bar -print + * + * results in the plan: + * + * [-name foo]--> [-newer bar]--> [-print] + * + * in this diagram, `[-name foo]' represents the plan node generated + * by c_name() with an argument of foo and `-->' represents the + * plan->next pointer. + */ + for (plan = NULL; *argv;) { + if (!(new = find_create(&argv))) + continue; + if (plan == NULL) + tail = plan = new; + else { + tail->next = new; + tail = new; } - return(0); - - case '?': - caseq: - if(scc) return(amatch(++s, ++p)); - return(0); - case '*': - return(umatch(s, ++p)); - case 0: - return(!scc); } - if (c==scc) goto caseq; - return(0); -} - -umatch(s, p) -register char *s, *p; -{ - if(*p==0) return(1); - while(*s) - if (amatch(s++, p)) return(1); - return(0); -} - -bwrite(rp, c) -register short *rp; -register c; -{ - register short *wp = Wp; - - c = (c+1) >> 1; - while(c--) { - if(!Wct) { -again: - if(write(Cpio, (char *)Dbuf, Bufsize)<0) { - Cpio = chgreel(1, Cpio); - goto again; - } - Wct = Bufsize >> 1; - wp = Dbuf; - ++Blocks; + + /* + * if the user didn't specify one of -print, -ok or -exec, then -print + * is assumed so we add a -print node on the end. It is possible that + * the user might want the -print someplace else on the command line, + * but there's no way to know that. + */ + if (!output_specified) { + new = c_print(); + if (plan == NULL) + tail = plan = new; + else { + tail->next = new; + tail = new; } - *wp++ = *rp++; - --Wct; } - Wp = wp; -} -chgreel(x, fl) -{ - register f; - char str[22]; - FILE *devtty; - struct stat statb; - extern errno; - - fprintf(stderr, "find: errno: %d, ", errno); - fprintf(stderr, "find: can't %s\n", x? "write output": "read input"); - fstat(fl, &statb); - if((statb.st_mode&S_IFMT) != S_IFCHR) - exit(1); -again: - fprintf(stderr, "If you want to go on, type device/file name %s\n", - "when ready"); - devtty = fopen("/dev/tty", "r"); - fgets(str, 20, devtty); - str[strlen(str) - 1] = '\0'; - if(!*str) - exit(1); - close(fl); - if((f = open(str, x? 1: 0)) < 0) { - fprintf(stderr, "That didn't work"); - fclose(devtty); - goto again; - } - return f; -} - -#ifdef AMES + + /* + * the command line has been completely processed into a search plan + * except for the (, ), !, and -o operators. Rearrange the plan so + * that the portions of the plan which are affected by the operators + * are moved into operator nodes themselves. For example: + * + * [!]--> [-name foo]--> [-print] + * + * becomes + * + * [! [-name foo] ]--> [-print] + * + * and + * + * [(]--> [-depth]--> [-name foo]--> [)]--> [-print] + * + * becomes + * + * [expr [-depth]-->[-name foo] ]--> [-print] + * + * operators are handled in order of precedence. + */ + + plan = find_squish_paren(plan); /* ()'s */ + plan = find_squish_not(plan); /* !'s */ + plan = find_squish_or(plan); /* -o's */ + return(plan); +} + /* - * 'fastfind' scans a file list for the full pathname of a file - * given only a piece of the name. The list has been processed with - * with "front-compression" and bigram coding. Front compression reduces - * space by a factor of 4-5, bigram coding by a further 20-25%. - * The codes are: - * - * 0-28 likeliest differential counts + offset to make nonnegative - * 30 escape code for out-of-range count to follow in next word - * 128-255 bigram codes, (128 most common, as determined by 'updatedb') - * 32-127 single character (printable) ascii residue - * - * A novel two-tiered string search technique is employed: - * - * First, a metacharacter-free subpattern and partial pathname is - * matched BACKWARDS to avoid full expansion of the pathname list. - * The time savings is 40-50% over forward matching, which cannot efficiently - * handle overlapped search patterns and compressed path residue. - * - * Then, the actual shell glob-style regular expression (if in this form) - * is matched against the candidate pathnames using the slower routines - * provided in the standard 'find'. + * find_execute -- + * take a search plan and an array of search paths and executes the plan + * over all FTSENT's returned for the given search paths. */ - -#define FCODES "/usr/lib/find/find.codes" -#define YES 1 -#define NO 0 -#define OFFSET 14 -#define ESCCODE 30 - -fastfind ( pathpart ) - char pathpart[]; -{ - register char *p, *s; - register int c; - char *q, *index(), *patprep(); - int i, count = 0, globflag; - FILE *fp, *fopen(); - char *patend, *cutoff; - char path[1024]; - char bigram1[128], bigram2[128]; - int found = NO; - - if ( (fp = fopen ( FCODES, "r" )) == NULL ) { - fprintf ( stderr, "find: can't open %s\n", FCODES ); - exit ( 1 ); - } - for ( i = 0; i < 128; i++ ) - bigram1[i] = getc ( fp ), bigram2[i] = getc ( fp ); - - if ( index ( pathpart, '*' ) || index ( pathpart, '?' ) || index ( pathpart, '[' ) ) - globflag = YES; - patend = patprep ( pathpart ); - - c = getc ( fp ); - for ( ; ; ) { - - count += ( (c == ESCCODE) ? getw ( fp ) : c ) - OFFSET; - - for ( p = path + count; (c = getc ( fp )) > ESCCODE; ) /* overlay old path */ - if ( c < 0200 ) - *p++ = c; - else /* bigrams are parity-marked */ - *p++ = bigram1[c & 0177], *p++ = bigram2[c & 0177]; - if ( c == EOF ) - break; - *p-- = NULL; - cutoff = ( found ? path : path + count); - - for ( found = NO, s = p; s >= cutoff; s-- ) - if ( *s == *patend ) { /* fast first char check */ - for ( p = patend - 1, q = s - 1; *p != NULL; p--, q-- ) - if ( *q != *p ) - break; - if ( *p == NULL ) { /* success on fast match */ - found = YES; - if ( globflag == NO || amatch ( path, pathpart ) ) - puts ( path ); - break; - } - } +find_execute(plan, paths) + PLAN *plan; /* search plan */ + char **paths; /* array of pathnames to traverse */ +{ + FTSENT *entry; /* current fts entry */ + PLAN *p; + + if (!(tree = ftsopen(paths, ftsoptions, NULL))) { + (void)fprintf(stderr, "find: ftsopen: %s.\n", strerror(errno)); + exit(1); } -} - -/* - extract last glob-free subpattern in name for fast pre-match; - prepend '\0' for backwards match; return end of new pattern -*/ -static char globfree[100]; - -char * -patprep ( name ) - char *name; -{ - register char *p, *endmark; - register char *subp = globfree; - - *subp++ = '\0'; - p = name + strlen ( name ) - 1; - /* - skip trailing metacharacters (and [] ranges) - */ - for ( ; p >= name; p-- ) - if ( index ( "*?", *p ) == 0 ) + while (entry = ftsread(tree)) { + switch(entry->fts_info) { + case FTS_DNR: + (void)fprintf(stderr, + "find: %s: unable to read.\n", entry->fts_path); + continue; + case FTS_DNX: + (void)fprintf(stderr, + "find: %s: unable to search.\n", entry->fts_path); + continue; + case FTS_ERR: + (void)fprintf(stderr, + "find: %s: %s.\n", entry->fts_path, + strerror(errno)); + continue; + case FTS_D: + if (depth) + continue; break; - if ( p < name ) - p = name; - if ( *p == ']' ) - for ( p--; p >= name; p-- ) - if ( *p == '[' ) { - p--; - break; - } - if ( p < name ) - p = name; - /* - if pattern has only metacharacters, - check every path (force '/' search) - */ - if ( (p == name) && index ( "?*[]", *p ) != 0 ) - *subp++ = '/'; - else { - for ( endmark = p; p >= name; p-- ) - if ( index ( "]*?", *p ) != 0 ) - break; - for ( ++p; (p <= endmark) && subp < (globfree + sizeof ( globfree )); ) - *subp++ = *p++; - } - *subp = '\0'; - return ( --subp ); -} -#endif - -/* rest should be done with nameserver or database */ - -#include -#include -#include - -struct utmp utmp; -#define NMAX (sizeof (utmp.ut_name)) -#define SCPYN(a, b) strncpy(a, b, NMAX) - -#define NUID 64 -#define NGID 300 - -struct ncache { - int uid; - char name[NMAX+1]; -} nc[NUID]; -char outrangename[NMAX+1]; -int outrangeuid = -1; -char groups[NGID][NMAX+1]; -char outrangegroup[NMAX+1]; -int outrangegid = -1; - -/* - * This function assumes that the password file is hashed - * (or some such) to allow fast access based on a name key. - * If this isn't true, duplicate the code for getgroup(). - */ -char * -getname(uid) -{ - register struct passwd *pw; - struct passwd *getpwent(); - register int cp; - extern int _pw_stayopen; - - _pw_stayopen = 1; - -#if (((NUID) & ((NUID) - 1)) != 0) - cp = uid % (NUID); -#else - cp = uid & ((NUID) - 1); -#endif - if (uid >= 0 && nc[cp].uid == uid && nc[cp].name[0]) - return (nc[cp].name); - pw = getpwuid(uid); - if (!pw) - return (0); - nc[cp].uid = uid; - SCPYN(nc[cp].name, pw->pw_name); - return (nc[cp].name); -} - -char * -getgroup(gid) -{ - register struct group *gr; - static init; - struct group *getgrent(); - - if (gid >= 0 && gid < NGID && groups[gid][0]) - return (&groups[gid][0]); - if (gid >= 0 && gid == outrangegid) - return (outrangegroup); -rescan: - if (init == 2) { - if (gid < NGID) - return (0); - setgrent(); - while (gr = getgrent()) { - if (gr->gr_gid != gid) + case FTS_DC: + (void)fprintf(stderr, + "find: directory cycle: %s.\n", entry->fts_path); + continue; + case FTS_DP: + if (!depth) + continue; + case FTS_NS: + if (!(ftsoptions & FTS_NOSTAT)) { + (void)fprintf(stderr, + "find: can't stat: %s.\n", entry->fts_path); continue; - outrangegid = gr->gr_gid; - SCPYN(outrangegroup, gr->gr_name); - endgrent(); - return (outrangegroup); - } - endgrent(); - return (0); - } - if (init == 0) - setgrent(), init = 1; - while (gr = getgrent()) { - if (gr->gr_gid < 0 || gr->gr_gid >= NGID) { - if (gr->gr_gid == gid) { - outrangegid = gr->gr_gid; - SCPYN(outrangegroup, gr->gr_name); - return (outrangegroup); } - continue; + break; } - if (groups[gr->gr_gid][0]) - continue; - SCPYN(groups[gr->gr_gid], gr->gr_name); - if (gr->gr_gid == gid) - return (&groups[gid][0]); - } - init = 2; - goto rescan; -} - -int -getuid(username) - char *username; -{ - register struct passwd *pw; - struct passwd *getpwnam(); -#ifndef NO_PW_STAYOPEN - extern int _pw_stayopen; - - _pw_stayopen = 1; -#endif - - pw = getpwnam(username); - if (pw != NULL) - return (pw->pw_uid); - else - return (-1); -} - -int -getgid(groupname) - char *groupname; -{ - register struct group *gr; - struct group *getgrnam(); - - gr = getgrnam(groupname); - if (gr != NULL) - return (gr->gr_gid); - else - return (-1); -} - -#define permoffset(who) ((who) * 3) -#define permission(who, type) ((type) >> permoffset(who)) -#define kbytes(bytes) (((bytes) + 1023) / 1024) - -list(file, stp) - char *file; - register struct stat *stp; -{ - char pmode[32], uname[32], gname[32], fsize[32], ftime[32]; - char *getname(), *getgroup(), *ctime(); - static long special[] = { S_ISUID, 's', S_ISGID, 's', S_ISVTX, 't' }; - static time_t sixmonthsago = -1; -#ifdef S_IFLNK - char flink[MAXPATHLEN + 1]; -#endif - register int who; - register char *cp; - time_t now; - - if (file == NULL || stp == NULL) - return (-1); - - time(&now); - if (sixmonthsago == -1) - sixmonthsago = now - 6L*30L*24L*60L*60L; - - switch (stp->st_mode & S_IFMT) { -#ifdef S_IFDIR - case S_IFDIR: /* directory */ - pmode[0] = 'd'; - break; -#endif -#ifdef S_IFCHR - case S_IFCHR: /* character special */ - pmode[0] = 'c'; - break; -#endif -#ifdef S_IFBLK - case S_IFBLK: /* block special */ - pmode[0] = 'b'; - break; -#endif -#ifdef S_IFLNK - case S_IFLNK: /* symbolic link */ - pmode[0] = 'l'; - break; -#endif -#ifdef S_IFSOCK - case S_IFSOCK: /* socket */ - pmode[0] = 's'; - break; -#endif -#ifdef S_IFREG - case S_IFREG: /* regular */ -#endif - default: - pmode[0] = '-'; - break; - } - - for (who = 0; who < 3; who++) { - if (stp->st_mode & permission(who, S_IREAD)) - pmode[permoffset(who) + 1] = 'r'; - else - pmode[permoffset(who) + 1] = '-'; - - if (stp->st_mode & permission(who, S_IWRITE)) - pmode[permoffset(who) + 2] = 'w'; - else - pmode[permoffset(who) + 2] = '-'; - - if (stp->st_mode & special[who * 2]) - pmode[permoffset(who) + 3] = special[who * 2 + 1]; - else if (stp->st_mode & permission(who, S_IEXEC)) - pmode[permoffset(who) + 3] = 'x'; - else - pmode[permoffset(who) + 3] = '-'; - } - pmode[permoffset(who) + 1] = '\0'; - cp = getname(stp->st_uid); - if (cp != NULL) - sprintf(uname, "%-9.9s", cp); - else - sprintf(uname, "%-9d", stp->st_uid); - - cp = getgroup(stp->st_gid); - if (cp != NULL) - sprintf(gname, "%-9.9s", cp); - else - sprintf(gname, "%-9d", stp->st_gid); - - if (pmode[0] == 'b' || pmode[0] == 'c') - sprintf(fsize, "%3d,%4d", - major(stp->st_rdev), minor(stp->st_rdev)); - else { - sprintf(fsize, "%8ld", stp->st_size); -#ifdef S_IFLNK - if (pmode[0] == 'l') { - /* - * Need to get the tail of the file name, since we have - * already chdir()ed into the directory of the file - */ - cp = rindex(file, '/'); - if (cp == NULL) - cp = file; - else - cp++; - who = readlink(cp, flink, sizeof flink - 1); - if (who >= 0) - flink[who] = '\0'; - else - flink[0] = '\0'; - } -#endif + /* + * call all the functions in the execution plan until one is + * false or all have been executed. This is where we do all + * the work specified by the user on the command line. + */ + for (p = plan; p && (p->eval)(p, entry); p = p->next); } - - cp = ctime(&stp->st_mtime); - if (stp->st_mtime < sixmonthsago || stp->st_mtime > now) - sprintf(ftime, "%-7.7s %-4.4s", cp + 4, cp + 20); - else - sprintf(ftime, "%-12.12s", cp + 4); - - printf("%5lu %4ld %s %2d %s%s%s %s %s%s%s\n", - stp->st_ino, /* inode # */ -#ifdef S_IFSOCK - (long) kbytes(dbtob(stp->st_blocks)), /* kbytes */ -#else - (long) kbytes(stp->st_size), /* kbytes */ -#endif - pmode, /* protection */ - stp->st_nlink, /* # of links */ - uname, /* owner */ - gname, /* group */ - fsize, /* # of bytes */ - ftime, /* modify time */ - file, /* name */ -#ifdef S_IFLNK - (pmode[0] == 'l') ? " -> " : "", - (pmode[0] == 'l') ? flink : "" /* symlink */ -#else - "", - "" -#endif - ); - - return (0); + (void)ftsclose(tree); }