X-Git-Url: https://git.saurik.com/apple/shell_cmds.git/blobdiff_plain/1a5bac7242b5267f816c85cfd03283a4f58392b3..e1a085bab7df5bb0af9b495e350271357a7cd388:/find/function.c diff --git a/find/function.c b/find/function.c index eb2c65a..0e6028e 100644 --- a/find/function.c +++ b/find/function.c @@ -36,21 +36,21 @@ #ifndef lint #if 0 -static const char sccsid[] = "@(#)function.c 8.10 (Berkeley) 5/4/95"; -#else -static const char rcsid[] = - "$FreeBSD: src/usr.bin/find/function.c,v 1.22.2.9 2001/09/19 09:44:24 ru Exp $"; +static const char sccsid[] = "@(#)function.c 8.10 (Berkeley) 5/4/95"; #endif #endif /* not lint */ +#include +__FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.58 2006/05/27 18:27:41 krion Exp $"); + #include #include #include +#include +#include #include #include #include -#include -#include #include #include @@ -58,24 +58,34 @@ static const char rcsid[] = #include #include #include +#include #include #include #include #include #include #include +#include #include "find.h" #ifdef __APPLE__ -#include "get_compat.h" +#include +#include #else #define COMPAT_MODE(func, mode) 1 #endif -time_t get_date __P((char *date, struct timeb *now)); +static PLAN *palloc(OPTION *); +static long long find_parsenum(PLAN *, const char *, char *, char *); +static long long find_parsetime(PLAN *, const char *, char *); +static char *nextarg(OPTION *, char ***); + +extern char **environ; + +static PLAN *lastexecplus = NULL; -#define COMPARE(a, b) { \ +#define COMPARE(a, b) do { \ switch (plan->flags & F_ELG_MASK) { \ case F_EQUAL: \ return (a == b); \ @@ -86,11 +96,10 @@ time_t get_date __P((char *date, struct timeb *now)); default: \ abort(); \ } \ -} +} while(0) static PLAN * -palloc(option) - OPTION *option; +palloc(OPTION *option) { PLAN *new; @@ -107,9 +116,7 @@ palloc(option) * Parse a string of the form [+-]# and return the value. */ static long long -find_parsenum(plan, option, vp, endch) - PLAN *plan; - char *option, *vp, *endch; +find_parsenum(PLAN *plan, const char *option, char *vp, char *endch) { long long value; char *endchar, *str; /* Pointer to character ending conversion. */ @@ -138,22 +145,94 @@ find_parsenum(plan, option, vp, endch) value = strtoq(str, &endchar, 10); if (value == 0 && endchar == str) errx(1, "%s: %s: illegal numeric value", option, vp); - if (endchar[0] && (endch == NULL || endchar[0] != *endch)) + if (endchar[0] && endch == NULL) errx(1, "%s: %s: illegal trailing character", option, vp); if (endch) *endch = endchar[0]; return value; } +/* + * find_parsetime -- + * Parse a string of the form [+-]([0-9]+[smhdw]?)+ and return the value. + */ +static long long +find_parsetime(PLAN *plan, const char *option, char *vp) +{ + long long secs, value; + char *str, *unit; /* Pointer to character ending conversion. */ + + /* Determine comparison from leading + or -. */ + str = vp; + switch (*str) { + case '+': + ++str; + plan->flags |= F_GREATER; + break; + case '-': + ++str; + plan->flags |= F_LESSTHAN; + break; + default: + plan->flags |= F_EQUAL; + break; + } + + value = strtoq(str, &unit, 10); + if (value == 0 && unit == str) { + errx(1, "%s: %s: illegal time value", option, vp); + /* NOTREACHED */ + } + if (*unit == '\0') + return value; + + /* Units syntax. */ + secs = 0; + for (;;) { + switch(*unit) { + case 's': /* seconds */ + secs += value; + break; + case 'm': /* minutes */ + secs += value * 60; + break; + case 'h': /* hours */ + secs += value * 3600; + break; + case 'd': /* days */ + secs += value * 86400; + break; + case 'w': /* weeks */ + secs += value * 604800; + break; + default: + errx(1, "%s: %s: bad unit '%c'", option, vp, *unit); + /* NOTREACHED */ + } + str = unit + 1; + if (*str == '\0') /* EOS */ + break; + value = strtoq(str, &unit, 10); + if (value == 0 && unit == str) { + errx(1, "%s: %s: illegal time value", option, vp); + /* NOTREACHED */ + } + if (*unit == '\0') { + errx(1, "%s: %s: missing trailing unit", option, vp); + /* NOTREACHED */ + } + } + plan->flags |= F_EXACTTIME; + return secs; +} + /* * nextarg -- * Check that another argument still exists, return a pointer to it, * and increment the argument vector pointer. */ static char * -nextarg(option, argvp) - OPTION *option; - char ***argvp; +nextarg(OPTION *option, char ***argvp) { char *arg; @@ -164,10 +243,10 @@ nextarg(option, argvp) } /* nextarg() */ /* - * The value of n for the inode times (atime, ctime, and mtime) is a range, - * i.e. n matches from (n - 1) to n 24 hour periods. This interacts with - * -n, such that "-mtime -1" would be less than 0 days, which isn't what the - * user wanted. Correct so that -1 is "less than 1". + * The value of n for the inode times (atime, birthtime, ctime, mtime) is a + * range, i.e. n matches from (n - 1) to n 24 hour periods. This interacts + * with -n, such that "-mtime -1" would be less than 0 days, which isn't what + * the user wanted. Correct so that -1 is "less than 1". */ #define TIME_CORRECT(p) \ if (((p)->flags & F_ELG_MASK) == F_LESSTHAN) \ @@ -178,23 +257,23 @@ nextarg(option, argvp) * * True if the difference between the * file access time (-amin) + * file birth time (-Bmin) * last change of file status information (-cmin) * file modification time (-mmin) * and the current time is n min periods. */ int -f_Xmin(plan, entry) - PLAN *plan; - FTSENT *entry; +f_Xmin(PLAN *plan, FTSENT *entry) { - extern time_t now; - if (plan->flags & F_TIME_C) { COMPARE((now - entry->fts_statp->st_ctime + 60 - 1) / 60, plan->t_data); } else if (plan->flags & F_TIME_A) { COMPARE((now - entry->fts_statp->st_atime + 60 - 1) / 60, plan->t_data); + } else if (plan->flags & F_TIME_B) { + COMPARE((now - entry->fts_statp->st_birthtime + + 60 - 1) / 60, plan->t_data); } else { COMPARE((now - entry->fts_statp->st_mtime + 60 - 1) / 60, plan->t_data); @@ -202,9 +281,7 @@ f_Xmin(plan, entry) } PLAN * -c_Xmin(option, argvp) - OPTION *option; - char ***argvp; +c_Xmin(OPTION *option, char ***argvp) { char *nmins; PLAN *new; @@ -223,46 +300,45 @@ c_Xmin(option, argvp) * * True if the difference between the * file access time (-atime) + * file birth time (-Btime) * last change of file status information (-ctime) * file modification time (-mtime) * and the current time is n 24 hour periods. */ int -f_Xtime(plan, entry) - PLAN *plan; - FTSENT *entry; +f_Xtime(PLAN *plan, FTSENT *entry) { - extern time_t now; - - int fudge = COMPAT_MODE("bin/find", "unix2003") ? 0 : 86400 - 1; + time_t xtime; + + if (plan->flags & F_TIME_A) + xtime = entry->fts_statp->st_atime; + else if (plan->flags & F_TIME_B) + xtime = entry->fts_statp->st_birthtime; + else if (plan->flags & F_TIME_C) + xtime = entry->fts_statp->st_ctime; + else + xtime = entry->fts_statp->st_mtime; - if (plan->flags & F_TIME_C) { - COMPARE((now - entry->fts_statp->st_ctime + - fudge) / 86400, plan->t_data); - } else if (plan->flags & F_TIME_A) { - COMPARE((now - entry->fts_statp->st_atime + - fudge) / 86400, plan->t_data); - } else { - COMPARE((now - entry->fts_statp->st_mtime + - fudge) / 86400, plan->t_data); - } + if (COMPAT_MODE("bin/find", "unix2003") || plan->flags & F_EXACTTIME) + COMPARE((now - xtime) / 86400, plan->t_data); + else + COMPARE((now - xtime + 86400 - 1) / 86400, plan->t_data); } PLAN * -c_Xtime(option, argvp) - OPTION *option; - char ***argvp; +c_Xtime(OPTION *option, char ***argvp) { - char *ndays; + char *value; PLAN *new; - ndays = nextarg(option, argvp); + value = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; new = palloc(option); - new->t_data = find_parsenum(new, option->name, ndays, NULL); - TIME_CORRECT(new); + new->t_data = find_parsetime(new, option->name, value); + if (!(new->flags & F_EXACTTIME)) + TIME_CORRECT(new); return new; } @@ -276,9 +352,7 @@ c_Xtime(option, argvp) * find_execute() so their f_* functions are set to f_always_true(). */ PLAN * -c_mXXdepth(option, argvp) - OPTION *option; - char ***argvp; +c_mXXdepth(OPTION *option, char ***argvp) { char *dstr; PLAN *new; @@ -296,15 +370,64 @@ c_mXXdepth(option, argvp) return new; } +#ifndef __APPLE__ +/* + * -acl function -- + * + * Show files with EXTENDED ACL attributes. + */ +int +f_acl(PLAN *plan __unused, FTSENT *entry) +{ + int match, entries; + acl_entry_t ae; + acl_t facl; + + if (S_ISLNK(entry->fts_statp->st_mode)) + return 0; + if ((match = pathconf(entry->fts_accpath, _PC_ACL_EXTENDED)) <= 0) { + if (match < 0 && errno != EINVAL) + warn("%s", entry->fts_accpath); + else + return 0; + } + match = 0; + if ((facl = acl_get_file(entry->fts_accpath,ACL_TYPE_ACCESS)) != NULL) { + if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 1) { + /* + * POSIX.1e requires that ACLs of type ACL_TYPE_ACCESS + * must have at least three entries (owner, group, + * other). + */ + entries = 1; + while (acl_get_entry(facl, ACL_NEXT_ENTRY, &ae) == 1) { + if (++entries > 3) { + match = 1; + break; + } + } + } + acl_free(facl); + } else + warn("%s", entry->fts_accpath); + return match; +} + +PLAN * +c_acl(OPTION *option, char ***argvp __unused) +{ + ftsoptions &= ~FTS_NOSTAT; + return (palloc(option)); +} +#endif /* !__APPLE__ */ + /* * -delete functions -- * * True always. Makes its best shot and continues on regardless. */ int -f_delete(plan, entry) - PLAN *plan; - FTSENT *entry; +f_delete(PLAN *plan __unused, FTSENT *entry) { /* ignore these from fts */ if (strcmp(entry->fts_accpath, ".") == 0 || @@ -344,9 +467,7 @@ f_delete(plan, entry) } PLAN * -c_delete(option, argvp) - OPTION *option; - char ***argvp; +c_delete(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_NOSTAT; /* no optimise */ @@ -360,39 +481,72 @@ c_delete(option, argvp) /* - * -depth functions -- + * always_true -- * - * Always true, causes descent of the directory hierarchy to be done - * so that all entries in a directory are acted on before the directory - * itself. + * Always true, used for -maxdepth, -mindepth, -xdev and -follow */ int -f_always_true(plan, entry) - PLAN *plan; - FTSENT *entry; +f_always_true(PLAN *plan __unused, FTSENT *entry __unused) { return 1; } +/* + * -depth functions -- + * + * With argument: True if the file is at level n. + * Without argument: Always true, causes descent of the directory hierarchy + * to be done so that all entries in a directory are acted on before the + * directory itself. + */ +int +f_depth(PLAN *plan, FTSENT *entry) +{ + if (plan->flags & F_DEPTH) + COMPARE(entry->fts_level, plan->d_data); + else + return 1; +} + PLAN * -c_depth(option, argvp) - OPTION *option; - char ***argvp; +c_depth(OPTION *option, char ***argvp) { - isdepth = 1; + PLAN *new; + char *str; - return palloc(option); -} + new = palloc(option); + + str = **argvp; + if (str && !(new->flags & F_DEPTH)) { + /* skip leading + or - */ + if (*str == '+' || *str == '-') + str++; + /* skip sign */ + if (*str == '+' || *str == '-') + str++; + if (isdigit(*str)) + new->flags |= F_DEPTH; + } + if (new->flags & F_DEPTH) { /* -depth n */ + char *ndepth; + + ndepth = nextarg(option, argvp); + new->d_data = find_parsenum(new, option->name, ndepth, NULL); + } else { /* -d */ + isdepth = 1; + } + + return new; +} + /* * -empty functions -- * * True if the file or directory is empty */ int -f_empty(plan, entry) - PLAN *plan; - FTSENT *entry; +f_empty(PLAN *plan __unused, FTSENT *entry) { if (S_ISREG(entry->fts_statp->st_mode) && entry->fts_statp->st_size == 0) @@ -420,9 +574,7 @@ f_empty(plan, entry) } PLAN * -c_empty(option, argvp) - OPTION *option; - char ***argvp; +c_empty(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_NOSTAT; @@ -445,94 +597,45 @@ c_empty(option, argvp) * of the user before executing the utility. */ int -f_exec(plan, entry) - register PLAN *plan; - FTSENT *entry; +f_exec(PLAN *plan, FTSENT *entry) { - extern int dotfd; - register int cnt; + int cnt; pid_t pid; int status; - char *file = NULL; - static char **plus_path = NULL; - static int plus_path_cnt = 0; - static unsigned long exec_after = 0; - static unsigned long path_so_far = 0; - struct _ex saved_ex; - - if (entry) { - /* XXX - if file/dir ends in '/' this will not work -- can it? */ - if ((plan->flags & F_EXECDIR) && - (file = strrchr(entry->fts_path, '/'))) { + char *file; + + if (entry == NULL && plan->flags & F_EXECPLUS) { + if (plan->e_ppos == plan->e_pbnum) + return (1); + plan->e_argv[plan->e_ppos] = NULL; + goto doexec; + } + + /* XXX - if file/dir ends in '/' this will not work -- can it? */ + if ((plan->flags & F_EXECDIR) && \ + (file = strrchr(entry->fts_path, '/'))) file++; - } else { + else file = entry->fts_path; - } - - if (plan->flags & F_CLEANUP) { - plus_path = realloc(plus_path, sizeof(char *) * ++plus_path_cnt); - if (!plus_path) errx(1, "out of memory"); - plus_path[plus_path_cnt -1] = strdup(file); - if (!plus_path[plus_path_cnt -1]) errx(1, "out of memory"); - - path_so_far += sizeof(char *) + strlen(file); - - if (!exec_after) { - size_t l = sizeof(exec_after); - int rc = - sysctlbyname("kern.argmax", &exec_after, &l, NULL, NULL); - if (rc < 0) { - /* Something conservitave */ - exec_after = 16 * 1024; - } - } - if (path_so_far >= exec_after) { - return f_exec(plan, NULL); - } - return 1; - } + if (plan->flags & F_EXECPLUS) { + if ((plan->e_argv[plan->e_ppos] = strdup(file)) == NULL) + err(1, NULL); + plan->e_len[plan->e_ppos] = strlen(file); + plan->e_psize += plan->e_len[plan->e_ppos]; + if (++plan->e_ppos < plan->e_pnummax && + plan->e_psize < plan->e_psizemax) + return (1); + plan->e_argv[plan->e_ppos] = NULL; } else { - if (!plus_path) return 1; - saved_ex = plan->p_un.ex; - int new_len = 0; - int ocnt; - for(cnt = 0; plan->e_argv[cnt]; ++cnt) { - if (plan->e_len[cnt]) { - new_len += plus_path_cnt; - } else { - new_len++; - } - } - new_len++; - - plan->e_argv = malloc(sizeof(char *) * new_len); - if (!plan->e_argv) errx(1, "out of memory"); - - for(ocnt = cnt = 0; saved_ex._e_argv[ocnt]; ++ocnt) { - if (saved_ex._e_len[ocnt]) { - int ppi; - for(ppi = 0; ppi < plus_path_cnt; ++ppi) { - plan->e_argv[cnt++] = plus_path[ppi]; - } -#if 0 - memmove(plan->e_argv + cnt, *plus_path, - sizeof(char *) * plus_path_cnt); - cnt += plus_path_cnt; -#endif - } else { - plan->e_argv[cnt++] = saved_ex._e_argv[ocnt]; - } - } - plan->e_argv[cnt++] = NULL; + for (cnt = 0; plan->e_argv[cnt]; ++cnt) + if (plan->e_len[cnt]) + brace_subst(plan->e_orig[cnt], + &plan->e_argv[cnt], file, + plan->e_len[cnt]); } - if (!(plan->flags & F_CLEANUP)) for (cnt = 0; plan->e_argv[cnt]; ++cnt) - if (plan->e_len[cnt]) - brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt], - file, plan->e_len[cnt]); - - if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv)) +doexec: if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv)) return 0; /* make sure find output is interspersed correctly with subprocesses */ @@ -553,21 +656,15 @@ f_exec(plan, entry) warn("%s", plan->e_argv[0]); _exit(1); } - pid = waitpid(pid, &status, 0); - if (plus_path) { - int i; - for(i = 0; i < plus_path_cnt; ++i) { - free(plus_path[i]); - } - free(plus_path); - plus_path = NULL; - plus_path_cnt = 0; - plan->p_un.ex = saved_ex; - path_so_far = 0; - if (WIFEXITED(status) && WEXITSTATUS(status)) { - exit(WEXITSTATUS(status)); - } + if (plan->flags & F_EXECPLUS) { + while (--plan->e_ppos >= plan->e_pbnum) + free(plan->e_argv[plan->e_ppos]); + plan->e_ppos = plan->e_pbnum; + plan->e_psize = plan->e_pbsize; } + pid = waitpid(pid, &status, 0); + if (plan->flags & F_EXECPLUS && WIFEXITED(status) && WEXITSTATUS(status)) + _exit(WEXITSTATUS(status)); return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status)); } @@ -579,14 +676,12 @@ f_exec(plan, entry) * strings, but also flags meaning that the string has to be massaged. */ PLAN * -c_exec(option, argvp) - OPTION *option; - char ***argvp; +c_exec(OPTION *option, char ***argvp) { PLAN *new; /* node returned */ - register int cnt; - register char **argv, **ap, *p; - int plus_armed = 0; + long argmax; + int cnt, i; + char **argv, **ap, **ep, *p; /* XXX - was in c_execdir, but seems unnecessary!? ftsoptions &= ~FTS_NOSTAT; @@ -599,31 +694,56 @@ c_exec(option, argvp) for (ap = argv = *argvp;; ++ap) { if (!*ap) errx(1, - "%s: no terminating \";\"", option->name); - if (**ap == '{' && ap[0][1] == '}' && ap[0][2] == '\0') { - plus_armed = COMPAT_MODE("bin/find", "unix2003"); - continue; - } - if (**ap == ';') { + "%s: no terminating \";\" or \"+\"", option->name); + if (**ap == ';') break; - } - if (plus_armed && **ap == '+') { - new->flags |= F_CLEANUP; + if (**ap == '+' && ap != argv && strcmp(*(ap - 1), "{}") == 0) { + new->flags |= F_EXECPLUS; break; } - plus_armed = 0; } + if (ap == argv) + errx(1, "%s: no command specified", option->name); + cnt = ap - *argvp + 1; - new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *)); - new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *)); - new->e_len = (int *)emalloc((u_int)cnt * sizeof(int)); + if (new->flags & F_EXECPLUS) { + new->e_ppos = new->e_pbnum = cnt - 2; + if ((argmax = sysconf(_SC_ARG_MAX)) == -1) { + warn("sysconf(_SC_ARG_MAX)"); + argmax = _POSIX_ARG_MAX; + } + argmax -= 1024; + for (ep = environ; *ep != NULL; ep++) + argmax -= strlen(*ep) + 1 + sizeof(*ep); + argmax -= 1 + sizeof(*ep); + new->e_pnummax = argmax / 16; + argmax -= sizeof(char *) * new->e_pnummax; + if (argmax <= 0) + errx(1, "no space for arguments"); + new->e_psizemax = argmax; + new->e_pbsize = 0; + cnt += new->e_pnummax + 1; + new->e_next = lastexecplus; + lastexecplus = new; + } + if ((new->e_argv = malloc(cnt * sizeof(char *))) == NULL) + err(1, NULL); + if ((new->e_orig = malloc(cnt * sizeof(char *))) == NULL) + err(1, NULL); + if ((new->e_len = malloc(cnt * sizeof(int))) == NULL) + err(1, NULL); for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) { new->e_orig[cnt] = *argv; + if (new->flags & F_EXECPLUS) + new->e_pbsize += strlen(*argv) + 1; for (p = *argv; *p; ++p) - if (p[0] == '{' && p[1] == '}') { - new->e_argv[cnt] = emalloc((u_int)MAXPATHLEN); + if (!(new->flags & F_EXECPLUS) && p[0] == '{' && + p[1] == '}') { + if ((new->e_argv[cnt] = + malloc(MAXPATHLEN)) == NULL) + err(1, NULL); new->e_len[cnt] = MAXPATHLEN; break; } @@ -632,16 +752,38 @@ c_exec(option, argvp) new->e_len[cnt] = 0; } } + if (new->flags & F_EXECPLUS) { + new->e_psize = new->e_pbsize; + cnt--; + for (i = 0; i < new->e_pnummax; i++) { + new->e_argv[cnt] = NULL; + new->e_len[cnt] = 0; + cnt++; + } + argv = ap; + goto done; + } new->e_argv[cnt] = new->e_orig[cnt] = NULL; - *argvp = argv + 1; +done: *argvp = argv + 1; return new; } +/* Finish any pending -exec ... {} + functions. */ +void +finish_execplus() +{ + PLAN *p; + + p = lastexecplus; + while (p != NULL) { + (p->execute)(p, NULL); + p = p->e_next; + } +} + int -f_flags(plan, entry) - PLAN *plan; - FTSENT *entry; +f_flags(PLAN *plan, FTSENT *entry) { u_long flags; @@ -658,9 +800,7 @@ f_flags(plan, entry) } PLAN * -c_flags(option, argvp) - OPTION *option; - char ***argvp; +c_flags(OPTION *option, char ***argvp) { char *flags_str; PLAN *new; @@ -693,9 +833,7 @@ c_flags(option, argvp) * basis. */ PLAN * -c_follow(option, argvp) - OPTION *option; - char ***argvp; +c_follow(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_PHYSICAL; ftsoptions |= FTS_LOGICAL; @@ -709,22 +847,23 @@ c_follow(option, argvp) * True if the file is of a certain type. */ int -f_fstype(plan, entry) - PLAN *plan; - FTSENT *entry; +f_fstype(PLAN *plan, FTSENT *entry) { static dev_t curdev; /* need a guaranteed illegal dev value */ static int first = 1; struct statfs sb; static int val_type, val_flags; - char *p, save[2]; + char *p, save[2] = {0,0}; + + if ((plan->flags & F_MTMASK) == F_MTUNKNOWN) + return 0; /* Only check when we cross mount point. */ if (first || curdev != entry->fts_statp->st_dev) { curdev = entry->fts_statp->st_dev; /* - * Statfs follows symlinks; find wants the link's file system, + * Statfs follows symlinks; find wants the link's filesystem, * not where it points. */ if (entry->fts_info == FTS_SL || @@ -759,22 +898,19 @@ f_fstype(plan, entry) } switch (plan->flags & F_MTMASK) { case F_MTFLAG: - return (val_flags & plan->mt_data) != 0; + return val_flags & plan->mt_data; case F_MTTYPE: - return (val_type == plan->mt_data); + return val_type == plan->mt_data; default: abort(); } } -#if !defined(__NetBSD__) PLAN * -c_fstype(option, argvp) - OPTION *option; - char ***argvp; +c_fstype(OPTION *option, char ***argvp) { char *fsname; - register PLAN *new; + PLAN *new; struct vfsconf vfc; fsname = nextarg(option, argvp); @@ -808,10 +944,14 @@ c_fstype(option, argvp) break; } - errx(1, "%s: unknown file type", fsname); - /* NOTREACHED */ + /* + * We need to make filesystem checks for filesystems + * that exists but aren't in the kernel work. + */ + fprintf(stderr, "Warning: Unknown filesystem type %s\n", fsname); + new->flags |= F_MTUNKNOWN; + return new; } -#endif /* __NetBSD__ */ /* * -group gname functions -- @@ -821,17 +961,13 @@ c_fstype(option, argvp) * name, gname is taken as a group ID. */ int -f_group(plan, entry) - PLAN *plan; - FTSENT *entry; +f_group(PLAN *plan, FTSENT *entry) { - return entry->fts_statp->st_gid == plan->g_data; + COMPARE(entry->fts_statp->st_gid, plan->g_data); } PLAN * -c_group(option, argvp) - OPTION *option; - char ***argvp; +c_group(OPTION *option, char ***argvp) { char *gname; PLAN *new; @@ -841,15 +977,19 @@ c_group(option, argvp) gname = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; + new = palloc(option); g = getgrnam(gname); if (g == NULL) { + char* cp = gname; + if( gname[0] == '-' || gname[0] == '+' ) + gname++; gid = atoi(gname); if (gid == 0 && gname[0] != '0') errx(1, "%s: %s: no such group", option->name, gname); + gid = find_parsenum(new, option->name, cp, NULL); } else gid = g->gr_gid; - new = palloc(option); new->g_data = gid; return new; } @@ -860,17 +1000,13 @@ c_group(option, argvp) * True if the file has inode # n. */ int -f_inum(plan, entry) - PLAN *plan; - FTSENT *entry; +f_inum(PLAN *plan, FTSENT *entry) { COMPARE(entry->fts_statp->st_ino, plan->i_data); } PLAN * -c_inum(option, argvp) - OPTION *option; - char ***argvp; +c_inum(OPTION *option, char ***argvp) { char *inum_str; PLAN *new; @@ -889,17 +1025,13 @@ c_inum(option, argvp) * True if the file has n links. */ int -f_links(plan, entry) - PLAN *plan; - FTSENT *entry; +f_links(PLAN *plan, FTSENT *entry) { COMPARE(entry->fts_statp->st_nlink, plan->l_data); } PLAN * -c_links(option, argvp) - OPTION *option; - char ***argvp; +c_links(OPTION *option, char ***argvp) { char *nlinks; PLAN *new; @@ -918,18 +1050,14 @@ c_links(option, argvp) * Always true - prints the current entry to stdout in "ls" format. */ int -f_ls(plan, entry) - PLAN *plan; - FTSENT *entry; +f_ls(PLAN *plan __unused, FTSENT *entry) { printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp); return 1; } PLAN * -c_ls(option, argvp) - OPTION *option; - char ***argvp; +c_ls(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_NOSTAT; isoutput = 1; @@ -944,18 +1072,14 @@ c_ls(option, argvp) * matches pattern using Pattern Matching Notation S3.14 */ int -f_name(plan, entry) - PLAN *plan; - FTSENT *entry; +f_name(PLAN *plan, FTSENT *entry) { return !fnmatch(plan->c_data, entry->fts_name, plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0); } PLAN * -c_name(option, argvp) - OPTION *option; - char ***argvp; +c_name(OPTION *option, char ***argvp) { char *pattern; PLAN *new; @@ -974,22 +1098,20 @@ c_name(option, argvp) * file. */ int -f_newer(plan, entry) - PLAN *plan; - FTSENT *entry; +f_newer(PLAN *plan, FTSENT *entry) { if (plan->flags & F_TIME_C) return entry->fts_statp->st_ctime > plan->t_data; else if (plan->flags & F_TIME_A) return entry->fts_statp->st_atime > plan->t_data; + else if (plan->flags & F_TIME_B) + return entry->fts_statp->st_birthtime > plan->t_data; else return entry->fts_statp->st_mtime > plan->t_data; } PLAN * -c_newer(option, argvp) - OPTION *option; - char ***argvp; +c_newer(OPTION *option, char ***argvp) { char *fn_or_tspec; PLAN *new; @@ -1024,17 +1146,13 @@ c_newer(option, argvp) * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL. */ int -f_nogroup(plan, entry) - PLAN *plan; - FTSENT *entry; +f_nogroup(PLAN *plan __unused, FTSENT *entry) { return group_from_gid(entry->fts_statp->st_gid, 1) == NULL; } PLAN * -c_nogroup(option, argvp) - OPTION *option; - char ***argvp; +c_nogroup(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_NOSTAT; @@ -1048,17 +1166,13 @@ c_nogroup(option, argvp) * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL. */ int -f_nouser(plan, entry) - PLAN *plan; - FTSENT *entry; +f_nouser(PLAN *plan __unused, FTSENT *entry) { return user_from_uid(entry->fts_statp->st_uid, 1) == NULL; } PLAN * -c_nouser(option, argvp) - OPTION *option; - char ***argvp; +c_nouser(OPTION *option, char ***argvp __unused) { ftsoptions &= ~FTS_NOSTAT; @@ -1072,9 +1186,7 @@ c_nouser(option, argvp) * matches pattern using Pattern Matching Notation S3.14 */ int -f_path(plan, entry) - PLAN *plan; - FTSENT *entry; +f_path(PLAN *plan, FTSENT *entry) { return !fnmatch(plan->c_data, entry->fts_path, plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0); @@ -1090,9 +1202,7 @@ f_path(plan, entry) * symbolic mode. */ int -f_perm(plan, entry) - PLAN *plan; - FTSENT *entry; +f_perm(PLAN *plan, FTSENT *entry) { mode_t mode; @@ -1108,9 +1218,7 @@ f_perm(plan, entry) } PLAN * -c_perm(option, argvp) - OPTION *option; - char ***argvp; +c_perm(OPTION *option, char ***argvp) { char *perm; PLAN *new; @@ -1125,7 +1233,7 @@ c_perm(option, argvp) new->flags |= F_ATLEAST; ++perm; } else if (*perm == '+') { - if ((set = setmode(perm +1)) != NULL) { + if ((set = setmode(perm + 1)) != NULL) { new->flags |= F_ANY; ++perm; free(set); @@ -1143,22 +1251,18 @@ c_perm(option, argvp) /* * -print functions -- * - * Always true, causes the current pathame to be written to + * Always true, causes the current pathname to be written to * standard output. */ int -f_print(plan, entry) - PLAN *plan; - FTSENT *entry; +f_print(PLAN *plan __unused, FTSENT *entry) { (void)puts(entry->fts_path); return 1; } PLAN * -c_print(option, argvp) - OPTION *option; - char ***argvp; +c_print(OPTION *option, char ***argvp __unused) { isoutput = 1; @@ -1168,13 +1272,11 @@ c_print(option, argvp) /* * -print0 functions -- * - * Always true, causes the current pathame to be written to + * Always true, causes the current pathname to be written to * standard output followed by a NUL character */ int -f_print0(plan, entry) - PLAN *plan; - FTSENT *entry; +f_print0(PLAN *plan __unused, FTSENT *entry) { fputs(entry->fts_path, stdout); fputc('\0', stdout); @@ -1189,12 +1291,8 @@ f_print0(plan, entry) * Prune a portion of the hierarchy. */ int -f_prune(plan, entry) - PLAN *plan; - FTSENT *entry; +f_prune(PLAN *plan __unused, FTSENT *entry) { - extern FTS *tree; - if (fts_set(tree, entry, FTS_SKIP)) err(1, "%s", entry->fts_path); return 1; @@ -1209,12 +1307,10 @@ f_prune(plan, entry) * regular expression. */ int -f_regex(plan, entry) - PLAN *plan; - FTSENT *entry; +f_regex(PLAN *plan, FTSENT *entry) { char *str; - size_t len; + int len; regex_t *pre; regmatch_t pmatch; int errcode; @@ -1244,9 +1340,7 @@ f_regex(plan, entry) } PLAN * -c_regex(option, argvp) - OPTION *option; - char ***argvp; +c_regex(OPTION *option, char ***argvp) { PLAN *new; char *pattern; @@ -1276,9 +1370,7 @@ c_regex(option, argvp) /* c_simple covers c_prune, c_openparen, c_closeparen, c_not, c_or */ PLAN * -c_simple(option, argvp) - OPTION *option; - char ***argvp; +c_simple(OPTION *option, char ***argvp __unused) { return palloc(option); } @@ -1288,15 +1380,14 @@ c_simple(option, argvp) * * True if the file size in bytes, divided by an implementation defined * value and rounded up to the next integer, is n. If n is followed by - * a c, the size is in bytes. + * one of c k M G T P, the size is in bytes, kilobytes, + * megabytes, gigabytes, terabytes or petabytes respectively. */ #define FIND_SIZE 512 static int divsize = 1; int -f_size(plan, entry) - PLAN *plan; - FTSENT *entry; +f_size(PLAN *plan, FTSENT *entry) { off_t size; @@ -1306,13 +1397,12 @@ f_size(plan, entry) } PLAN * -c_size(option, argvp) - OPTION *option; - char ***argvp; +c_size(OPTION *option, char ***argvp) { char *size_str; PLAN *new; char endch; + off_t scale; size_str = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; @@ -1320,8 +1410,38 @@ c_size(option, argvp) new = palloc(option); endch = 'c'; new->o_data = find_parsenum(new, option->name, size_str, &endch); - if (endch == 'c') + if (endch != '\0') { divsize = 0; + + switch (endch) { + case 'c': /* characters */ + scale = 0x1LL; + break; + case 'k': /* kilobytes 1<<10 */ + scale = 0x400LL; + break; + case 'M': /* megabytes 1<<20 */ + scale = 0x100000LL; + break; + case 'G': /* gigabytes 1<<30 */ + scale = 0x40000000LL; + break; + case 'T': /* terabytes 1<<40 */ + scale = 0x1000000000LL; + break; + case 'P': /* petabytes 1<<50 */ + scale = 0x4000000000000LL; + break; + default: + errx(1, "%s: %s: illegal trailing character", + option->name, size_str); + break; + } + if (new->o_data > QUAD_MAX / scale) + errx(1, "%s: %s: value too large", + option->name, size_str); + new->o_data *= scale; + } return new; } @@ -1333,17 +1453,13 @@ c_size(option, argvp) * regular file or whiteout respectively. */ int -f_type(plan, entry) - PLAN *plan; - FTSENT *entry; +f_type(PLAN *plan, FTSENT *entry) { return (entry->fts_statp->st_mode & S_IFMT) == plan->m_data; } PLAN * -c_type(option, argvp) - OPTION *option; - char ***argvp; +c_type(OPTION *option, char ***argvp) { char *typestring; PLAN *new; @@ -1397,17 +1513,13 @@ c_type(option, argvp) * return a valid user name, uname is taken as a user ID. */ int -f_user(plan, entry) - PLAN *plan; - FTSENT *entry; +f_user(PLAN *plan, FTSENT *entry) { - return entry->fts_statp->st_uid == plan->u_data; + COMPARE(entry->fts_statp->st_uid, plan->u_data); } PLAN * -c_user(option, argvp) - OPTION *option; - char ***argvp; +c_user(OPTION *option, char ***argvp) { char *username; PLAN *new; @@ -1417,15 +1529,19 @@ c_user(option, argvp) username = nextarg(option, argvp); ftsoptions &= ~FTS_NOSTAT; + new = palloc(option); p = getpwnam(username); if (p == NULL) { + char* cp = username; + if( username[0] == '-' || username[0] == '+' ) + username++; uid = atoi(username); if (uid == 0 && username[0] != '0') errx(1, "%s: %s: no such user", option->name, username); + uid = find_parsenum(new, option->name, cp, NULL); } else uid = p->pw_uid; - new = palloc(option); new->u_data = uid; return new; } @@ -1433,13 +1549,11 @@ c_user(option, argvp) /* * -xdev functions -- * - * Always true, causes find not to decend past directories that have a + * Always true, causes find not to descend past directories that have a * different device ID (st_dev, see stat() S5.6.2 [POSIX.1]) */ PLAN * -c_xdev(option, argvp) - OPTION *option; - char ***argvp; +c_xdev(OPTION *option, char ***argvp __unused) { ftsoptions |= FTS_XDEV; @@ -1452,12 +1566,10 @@ c_xdev(option, argvp) * True if expression is true. */ int -f_expr(plan, entry) - PLAN *plan; - FTSENT *entry; +f_expr(PLAN *plan, FTSENT *entry) { - register PLAN *p; - register int state = 0; + PLAN *p; + int state = 0; for (p = plan->p_data[0]; p && (state = (p->execute)(p, entry)); p = p->next); @@ -1472,17 +1584,13 @@ f_expr(plan, entry) */ int -f_openparen(plan, entry) - PLAN *plan; - FTSENT *entry; +f_openparen(PLAN *plan __unused, FTSENT *entry __unused) { abort(); } int -f_closeparen(plan, entry) - PLAN *plan; - FTSENT *entry; +f_closeparen(PLAN *plan __unused, FTSENT *entry __unused) { abort(); } @@ -1494,9 +1602,7 @@ f_closeparen(plan, entry) * AND operator. Since AND is implicit, no node is allocated. */ PLAN * -c_and(option, argvp) - OPTION *option; - char ***argvp; +c_and(OPTION *option __unused, char ***argvp __unused) { return NULL; } @@ -1507,12 +1613,10 @@ c_and(option, argvp) * Negation of a primary; the unary NOT operator. */ int -f_not(plan, entry) - PLAN *plan; - FTSENT *entry; +f_not(PLAN *plan, FTSENT *entry) { - register PLAN *p; - register int state = 0; + PLAN *p; + int state = 0; for (p = plan->p_data[0]; p && (state = (p->execute)(p, entry)); p = p->next); @@ -1528,12 +1632,10 @@ f_not(plan, entry) * not evaluated if the first expression is true. */ int -f_or(plan, entry) - PLAN *plan; - FTSENT *entry; +f_or(PLAN *plan, FTSENT *entry) { - register PLAN *p; - register int state = 0; + PLAN *p; + int state = 0; for (p = plan->p_data[0]; p && (state = (p->execute)(p, entry)); p = p->next);