diff options
Diffstat (limited to 'usr.bin/find/function.c')
-rw-r--r-- | usr.bin/find/function.c | 1956 |
1 files changed, 0 insertions, 1956 deletions
diff --git a/usr.bin/find/function.c b/usr.bin/find/function.c deleted file mode 100644 index be880e9..0000000 --- a/usr.bin/find/function.c +++ /dev/null @@ -1,1956 +0,0 @@ -/* $NetBSD: function.c,v 1.77 2018/09/04 15:16:15 kre Exp $ */ - -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Cimarron D. Taylor of the University of California, Berkeley. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/ioctl.h> -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/statvfs.h> -#include <sys/wait.h> -#include <sys/mount.h> -#include <bsd/sys/time.h> - -#include <linux/fs.h> - -#include <dirent.h> -#include <err.h> -#include <errno.h> -#include <fnmatch.h> -#include <fts.h> -#include <grp.h> -#include <inttypes.h> -#include <limits.h> -#include <mntent.h> -#include <pwd.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <bsd/unistd.h> - -#include "find.h" - -#define COMPARE(a, b) { \ - switch (plan->flags) { \ - case F_EQUAL: \ - return (a == b); \ - case F_LESSTHAN: \ - return (a < b); \ - case F_GREATER: \ - return (a > b); \ - default: \ - abort(); \ - } \ -} - -static int64_t find_parsenum(PLAN *, const char *, const char *, char *); -static void run_f_exec(PLAN *); - int f_always_true(PLAN *, FTSENT *); - int f_amin(PLAN *, FTSENT *); - int f_anewer(PLAN *, FTSENT *); - int f_asince(PLAN *, FTSENT *); - int f_atime(PLAN *, FTSENT *); - int f_cmin(PLAN *, FTSENT *); - int f_cnewer(PLAN *, FTSENT *); - int f_csince(PLAN *, FTSENT *); - int f_ctime(PLAN *, FTSENT *); - int f_delete(PLAN *, FTSENT *); - int f_empty(PLAN *, FTSENT *); - int f_exec(PLAN *, FTSENT *); - int f_execdir(PLAN *, FTSENT *); - int f_false(PLAN *, FTSENT *); - int f_flags(PLAN *, FTSENT *); - int f_fprint(PLAN *, FTSENT *); - int f_fstype(PLAN *, FTSENT *); - int f_group(PLAN *, FTSENT *); - int f_iname(PLAN *, FTSENT *); - int f_inum(PLAN *, FTSENT *); - int f_links(PLAN *, FTSENT *); - int f_ls(PLAN *, FTSENT *); - int f_mindepth(PLAN *, FTSENT *); - int f_maxdepth(PLAN *, FTSENT *); - int f_mmin(PLAN *, FTSENT *); - int f_mtime(PLAN *, FTSENT *); - int f_name(PLAN *, FTSENT *); - int f_newer(PLAN *, FTSENT *); -/* - * Unimplemented Gnu findutils options - * - int f_newerBB(PLAN *, FTSENT *); - int f_newerBa(PLAN *, FTSENT *); - int f_newerBc(PLAN *, FTSENT *); - int f_newerBm(PLAN *, FTSENT *); - int f_newerBt(PLAN *, FTSENT *); - int f_neweraB(PLAN *, FTSENT *); - int f_newerac(PLAN *, FTSENT *); - int f_neweram(PLAN *, FTSENT *); - int f_newerca(PLAN *, FTSENT *); - int f_newercm(PLAN *, FTSENT *); - int f_newercB(PLAN *, FTSENT *); - int f_newermB(PLAN *, FTSENT *); - int f_newerma(PLAN *, FTSENT *); - int f_newermc(PLAN *, FTSENT *); - * - */ - int f_nogroup(PLAN *, FTSENT *); - int f_nouser(PLAN *, FTSENT *); - int f_path(PLAN *, FTSENT *); - int f_perm(PLAN *, FTSENT *); - int f_print(PLAN *, FTSENT *); - int f_print0(PLAN *, FTSENT *); - int f_printx(PLAN *, FTSENT *); - int f_prune(PLAN *, FTSENT *); - int f_regex(PLAN *, FTSENT *); - int f_since(PLAN *, FTSENT *); - int f_size(PLAN *, FTSENT *); - int f_type(PLAN *, FTSENT *); - int f_user(PLAN *, FTSENT *); - int f_not(PLAN *, FTSENT *); - int f_or(PLAN *, FTSENT *); -static PLAN *c_regex_common(char ***, int, enum ntype, bool); -static PLAN *palloc(enum ntype, int (*)(PLAN *, FTSENT *)); - -extern int dotfd; -extern FTS *tree; -extern time_t now; - -/* - * find_parsenum -- - * Parse a string of the form [+-]# and return the value. - */ -static int64_t -find_parsenum(PLAN *plan, const char *option, const char *vp, char *endch) -{ - int64_t value; - const char *str; - char *endchar; /* 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; - } - - /* - * Convert the string with strtol(). Note, if strtol() returns zero - * and endchar points to the beginning of the string we know we have - * a syntax error. - */ - value = strtoll(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)) - errx(1, "%s: %s: illegal trailing character", option, vp); - if (endch) - *endch = endchar[0]; - return (value); -} - -/* - * find_parsedate -- - * - * Validate the timestamp argument or report an error - */ -static time_t -find_parsedate(PLAN *plan, const char *option, const char *vp) -{ - time_t timestamp; - - errno = 0; - timestamp = parsedate(vp, NULL, NULL); - if (timestamp == -1 && errno != 0) - errx(1, "%s: %s: invalid timestamp value", option, vp); - return timestamp; -} - -/* - * 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". - */ -#define TIME_CORRECT(p, ttype) \ - if ((p)->type == ttype && (p)->flags == F_LESSTHAN) \ - ++((p)->t_data); - -/* - * -amin n functions -- - * - * True if the difference between the file access time and the - * current time is n 1 minute periods. - */ -int -f_amin(PLAN *plan, FTSENT *entry) -{ -#define SECSPERMIN 60 - COMPARE((now - entry->fts_statp->st_atime + - SECSPERMIN - 1) / SECSPERMIN, plan->t_data); -} - -PLAN * -c_amin(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_AMIN, f_amin); - new->t_data = find_parsenum(new, opt, arg, NULL); - TIME_CORRECT(new, N_AMIN); - return (new); -} - -/* - * -anewer file functions -- - * - * True if the current file has been accessed more recently - * than the access time of the file named by the pathname - * file. - */ -int -f_anewer(PLAN *plan, FTSENT *entry) -{ - - return timespeccmp(&entry->fts_statp->st_atim, &plan->ts_data, >); -} - -PLAN * -c_anewer(char ***argvp, int isok, char *opt) -{ - char *filename = **argvp; - PLAN *new; - struct stat sb; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - if (stat(filename, &sb)) - err(1, "%s: %s", opt, filename); - new = palloc(N_ANEWER, f_anewer); - new->ts_data = sb.st_atim; - return (new); -} - -/* - * -asince "timestamp" functions -- - * - * True if the file access time is greater than the timestamp value - */ -int -f_asince(PLAN *plan, FTSENT *entry) -{ - COMPARE(entry->fts_statp->st_atime, plan->t_data); -} - -PLAN * -c_asince(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_ASINCE, f_asince); - new->t_data = find_parsedate(new, opt, arg); - new->flags = F_GREATER; - return (new); -} - -/* - * -atime n functions -- - * - * True if the difference between the file access time and the - * current time is n 24 hour periods. - */ -int -f_atime(PLAN *plan, FTSENT *entry) -{ -#define SECSPERDAY 24*60*60 - COMPARE((now - entry->fts_statp->st_atime + - SECSPERDAY - 1) / SECSPERDAY, plan->t_data); -} - -PLAN * -c_atime(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_ATIME, f_atime); - new->t_data = find_parsenum(new, opt, arg, NULL); - TIME_CORRECT(new, N_ATIME); - return (new); -} - -/* - * -cmin n functions -- - * - * True if the difference between the last change of file - * status information and the current time is n 24 hour periods. - */ -int -f_cmin(PLAN *plan, FTSENT *entry) -{ - COMPARE((now - entry->fts_statp->st_ctime + - SECSPERMIN - 1) / SECSPERMIN, plan->t_data); -} - -PLAN * -c_cmin(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_CMIN, f_cmin); - new->t_data = find_parsenum(new, opt, arg, NULL); - TIME_CORRECT(new, N_CMIN); - return (new); -} - -/* - * -cnewer file functions -- - * - * True if the current file has been changed more recently - * than the changed time of the file named by the pathname - * file. - */ -int -f_cnewer(PLAN *plan, FTSENT *entry) -{ - - return timespeccmp(&entry->fts_statp->st_ctim, &plan->ts_data, >); -} - -PLAN * -c_cnewer(char ***argvp, int isok, char *opt) -{ - char *filename = **argvp; - PLAN *new; - struct stat sb; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - if (stat(filename, &sb)) - err(1, "%s: %s ", opt, filename); - new = palloc(N_CNEWER, f_cnewer); - new->ts_data = sb.st_ctim; - return (new); -} - -/* - * -csince "timestamp" functions -- - * - * True if the file status change time is greater than the timestamp value - */ -int -f_csince(PLAN *plan, FTSENT *entry) -{ - COMPARE(entry->fts_statp->st_ctime, plan->t_data); -} - -PLAN * -c_csince(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_CSINCE, f_csince); - new->t_data = find_parsedate(new, opt, arg); - new->flags = F_GREATER; - return (new); -} - -/* - * -ctime n functions -- - * - * True if the difference between the last change of file - * status information and the current time is n 24 hour periods. - */ -int -f_ctime(PLAN *plan, FTSENT *entry) -{ - COMPARE((now - entry->fts_statp->st_ctime + - SECSPERDAY - 1) / SECSPERDAY, plan->t_data); -} - -PLAN * -c_ctime(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_CTIME, f_ctime); - new->t_data = find_parsenum(new, opt, arg, NULL); - TIME_CORRECT(new, N_CTIME); - return (new); -} - -/* - * -delete functions -- - * - * Always true. Makes its best shot and continues on regardless. - */ -int -f_delete(PLAN *plan, FTSENT *entry) -{ - int flags; - FILE *file; - /* ignore these from fts */ - if (strcmp(entry->fts_accpath, ".") == 0 || - strcmp(entry->fts_accpath, "..") == 0) - return 1; - - /* sanity check */ - if (isdepth == 0 || /* depth off */ - (ftsoptions & FTS_NOSTAT) || /* not stat()ing */ - !(ftsoptions & FTS_PHYSICAL) || /* physical off */ - (ftsoptions & FTS_LOGICAL)) /* or finally, logical on */ - errx(1, "-delete: insecure options got turned on"); - - /* Potentially unsafe - do not accept relative paths whatsoever */ - if (entry->fts_level > 0 && strchr(entry->fts_accpath, '/') != NULL) - errx(1, "-delete: %s: relative path potentially not safe", - entry->fts_accpath); - - file = fopen(entry->fts_name, "r"); - if (file == NULL) { - warn("couldn't check flags for %s", entry->fts_name); - } else { - ioctl(fileno(file), FS_IOC_GETFLAGS, &flags); - /* turn off immutable bit if running as root */ - if ((geteuid() == 0) && (flags & FS_IMMUTABLE_FL)) { - flags = flags & ~FS_IMMUTABLE_FL; - ioctl(fileno(file), FS_IOC_SETFLAGS, &flags); - } - } - - /* rmdir directories, unlink everything else */ - if (S_ISDIR(entry->fts_statp->st_mode)) { - if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY) - warn("-delete: rmdir(%s)", entry->fts_path); - } else { - if (unlink(entry->fts_accpath) < 0) - warn("-delete: unlink(%s)", entry->fts_path); - } - - /* "succeed" */ - return 1; -} - -PLAN * -c_delete(char ***argvp, int isok, char *opt) -{ - - ftsoptions &= ~FTS_NOSTAT; /* no optimize */ - ftsoptions |= FTS_PHYSICAL; /* disable -follow */ - ftsoptions &= ~FTS_LOGICAL; /* disable -follow */ - isoutput = 1; /* possible output */ - isdepth = 1; /* -depth implied */ - - return palloc(N_DELETE, f_delete); -} - -/* - * -depth functions -- - * - * 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_always_true(PLAN *plan, FTSENT *entry) -{ - - return (1); -} - -PLAN * -c_depth(char ***argvp, int isok, char *opt) -{ - isdepth = 1; - - return (palloc(N_DEPTH, f_always_true)); -} - -/* - * -empty functions -- - * - * True if the file or directory is empty - */ -int -f_empty(PLAN *plan, FTSENT *entry) -{ - if (S_ISREG(entry->fts_statp->st_mode) && - entry->fts_statp->st_size == 0) - return (1); - if (S_ISDIR(entry->fts_statp->st_mode)) { - struct dirent *dp; - int empty; - DIR *dir; - - empty = 1; - dir = opendir(entry->fts_accpath); - if (dir == NULL) - return (0); - for (dp = readdir(dir); dp; dp = readdir(dir)) - if (dp->d_name[0] != '.' || - (dp->d_name[1] != '\0' && - (dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) { - empty = 0; - break; - } - closedir(dir); - return (empty); - } - return (0); -} - -PLAN * -c_empty(char ***argvp, int isok, char *opt) -{ - ftsoptions &= ~FTS_NOSTAT; - - return (palloc(N_EMPTY, f_empty)); -} - -/* - * [-exec | -ok] utility [arg ... ] ; functions -- - * [-exec | -ok] utility [arg ... ] {} + functions -- - * - * If the end of the primary expression is delimited by a - * semicolon: true if the executed utility returns a zero value - * as exit status. If "{}" occurs anywhere, it gets replaced by - * the current pathname. - * - * If the end of the primary expression is delimited by a plus - * sign: always true. Pathnames for which the primary is - * evaluated shall be aggregated into sets. The utility will be - * executed once per set, with "{}" replaced by the entire set of - * pathnames (as if xargs). "{}" must appear last. - * - * The current directory for the execution of utility is the same - * as the current directory when the find utility was started. - * - * The primary -ok is different in that it requests affirmation - * of the user before executing the utility. - */ -int -f_exec(PLAN *plan, FTSENT *entry) -{ - size_t cnt; - int l; - pid_t pid; - int status; - - if (plan->flags & F_PLUSSET) { - /* - * Confirm sufficient buffer space, then copy the path - * to the buffer. - */ - l = strlen(entry->fts_path); - if (plan->ep_p + l < plan->ep_ebp) { - plan->ep_bxp[plan->ep_narg++] = - strcpy(plan->ep_p, entry->fts_path); - plan->ep_p += l + 1; - - if (plan->ep_narg == plan->ep_maxargs) - run_f_exec(plan); - } else { - /* - * Without sufficient space to copy in the next - * argument, run the command to empty out the - * buffer before re-attepting the copy. - */ - run_f_exec(plan); - if ((plan->ep_p + l < plan->ep_ebp)) { - plan->ep_bxp[plan->ep_narg++] - = strcpy(plan->ep_p, entry->fts_path); - plan->ep_p += l + 1; - } else - errx(1, "insufficient space for argument"); - } - return (1); - } else { - for (cnt = 0; plan->e_argv[cnt]; ++cnt) - if (plan->e_len[cnt]) - brace_subst(plan->e_orig[cnt], - &plan->e_argv[cnt], - entry->fts_path, - &plan->e_len[cnt]); - if (plan->flags & F_NEEDOK && !queryuser(plan->e_argv)) - return (0); - - /* Don't mix output of command with find output. */ - fflush(stdout); - fflush(stderr); - - switch (pid = vfork()) { - case -1: - err(1, "vfork"); - /* NOTREACHED */ - case 0: - if (fchdir(dotfd)) { - warn("chdir"); - _exit(1); - } - execvp(plan->e_argv[0], plan->e_argv); - warn("%s", plan->e_argv[0]); - _exit(1); - } - pid = waitpid(pid, &status, 0); - return (pid != -1 && WIFEXITED(status) - && !WEXITSTATUS(status)); - } -} - -static void -run_f_exec(PLAN *plan) -{ - pid_t pid; - int rval, status; - - /* Ensure arg list is null terminated. */ - plan->ep_bxp[plan->ep_narg] = NULL; - - /* Don't mix output of command with find output. */ - fflush(stdout); - fflush(stderr); - - switch (pid = vfork()) { - case -1: - err(1, "vfork"); - /* NOTREACHED */ - case 0: - if (fchdir(dotfd)) { - warn("chdir"); - _exit(1); - } - execvp(plan->e_argv[0], plan->e_argv); - warn("%s", plan->e_argv[0]); - _exit(1); - } - - /* Clear out the argument list. */ - plan->ep_narg = 0; - plan->ep_bxp[plan->ep_narg] = NULL; - /* As well as the argument buffer. */ - plan->ep_p = plan->ep_bbp; - *plan->ep_p = '\0'; - - pid = waitpid(pid, &status, 0); - if (WIFEXITED(status)) - rval = WEXITSTATUS(status); - else - rval = -1; - - /* - * If we have a non-zero exit status, preserve it so find(1) can - * later exit with it. - */ - if (rval) - plan->ep_rval = rval; -} - -/* - * c_exec -- - * build three parallel arrays, one with pointers to the strings passed - * on the command line, one with (possibly duplicated) pointers to the - * argv array, and one with integer values that are lengths of the - * strings, but also flags meaning that the string has to be massaged. - * - * If -exec ... {} +, use only the first array, but make it large - * enough to hold 5000 args (cf. src/usr.bin/xargs/xargs.c for a - * discussion), and then allocate ARG_MAX - 4K of space for args. - */ -PLAN * -c_exec(char ***argvp, int isok, char *opt) -{ - PLAN *new; /* node returned */ - size_t cnt; - int brace, lastbrace; - char **argv, **ap, *p; - - isoutput = 1; - - new = palloc(N_EXEC, f_exec); - if (isok) - new->flags |= F_NEEDOK; - - /* - * Terminate if we encounter an arg exactly equal to ";", or an - * arg exactly equal to "+" following an arg exactly equal to - * "{}". - */ - for (ap = argv = *argvp, brace = 0;; ++ap) { - if (!*ap) - errx(1, "%s: no terminating \";\" or \"+\"", opt); - lastbrace = brace; - brace = 0; - if (strcmp(*ap, "{}") == 0) - brace = 1; - if (strcmp(*ap, ";") == 0) - break; - if (strcmp(*ap, "+") == 0 && lastbrace) { - new->flags |= F_PLUSSET; - break; - } - } - - /* - * POSIX says -ok ... {} + "need not be supported," and it does - * not make much sense anyway. - */ - if (new->flags & F_NEEDOK && new->flags & F_PLUSSET) - errx(1, "%s: terminating \"+\" not permitted.", opt); - - if (new->flags & F_PLUSSET) { - size_t c, bufsize; - - cnt = ap - *argvp - 1; /* units are words */ - new->ep_maxargs = ARG_MAX / (sizeof (char *) + 16); - if (new->ep_maxargs > 5000) - new->ep_maxargs = 5000; - new->e_argv = malloc((cnt + new->ep_maxargs) - * sizeof(*new->e_argv)); - - /* We start stuffing arguments after the user's last one. */ - new->ep_bxp = &new->e_argv[cnt]; - new->ep_narg = 0; - - /* - * Count up the space of the user's arguments, and - * subtract that from what we allocate. - */ -#define MAXARG (ARG_MAX - 4 * 1024) - for (argv = *argvp, c = 0, cnt = 0; - argv < ap; - ++argv, ++cnt) { - c += strlen(*argv) + 1; - if (c >= MAXARG) - errx(1, "Arguments too long"); - new->e_argv[cnt] = *argv; - } - if (c + new->ep_maxargs * sizeof (char *) >= MAXARG) - errx(1, "Arguments too long"); - bufsize = MAXARG - c - new->ep_maxargs * sizeof (char *); - - /* - * Allocate, and then initialize current, base, and - * end pointers. - */ - new->ep_p = new->ep_bbp = malloc(bufsize + 1); - new->ep_ebp = new->ep_bbp + bufsize - 1; - new->ep_rval = 0; - } else { /* !F_PLUSSET */ - cnt = ap - *argvp + 1; - new->e_argv = malloc(cnt * sizeof(*new->e_argv)); - new->e_orig = malloc(cnt * sizeof(*new->e_orig)); - new->e_len = malloc(cnt * sizeof(*new->e_len)); - - for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) { - new->e_orig[cnt] = *argv; - for (p = *argv; *p; ++p) - if (p[0] == '{' && p[1] == '}') { - new->e_argv[cnt] = - malloc(MAXPATHLEN); - new->e_len[cnt] = MAXPATHLEN; - break; - } - if (!*p) { - new->e_argv[cnt] = *argv; - new->e_len[cnt] = 0; - } - } - new->e_orig[cnt] = NULL; - } - - new->e_argv[cnt] = NULL; - *argvp = argv + 1; - return (new); -} - -/* - * -execdir utility [arg ... ] ; functions -- - * - * True if the executed utility returns a zero value as exit status. - * The end of the primary expression is delimited by a semicolon. If - * "{}" occurs anywhere, it gets replaced by the unqualified pathname. - * The current directory for the execution of utility is the same as - * the directory where the file lives. - */ -int -f_execdir(PLAN *plan, FTSENT *entry) -{ - size_t cnt; - pid_t pid; - int status; - char *file; - - /* XXX - if file/dir ends in '/' this will not work -- can it? */ - if ((file = strrchr(entry->fts_path, '/'))) - file++; - else - file = entry->fts_path; - - 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]); - - /* don't mix output of command with find output */ - fflush(stdout); - fflush(stderr); - - switch (pid = vfork()) { - case -1: - err(1, "fork"); - /* NOTREACHED */ - case 0: - execvp(plan->e_argv[0], plan->e_argv); - warn("%s", plan->e_argv[0]); - _exit(1); - } - pid = waitpid(pid, &status, 0); - return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status)); -} - -/* - * c_execdir -- - * build three parallel arrays, one with pointers to the strings passed - * on the command line, one with (possibly duplicated) pointers to the - * argv array, and one with integer values that are lengths of the - * strings, but also flags meaning that the string has to be massaged. - */ -PLAN * -c_execdir(char ***argvp, int isok, char *opt) -{ - PLAN *new; /* node returned */ - size_t cnt; - char **argv, **ap, *p; - - ftsoptions &= ~FTS_NOSTAT; - isoutput = 1; - - new = palloc(N_EXECDIR, f_execdir); - - for (ap = argv = *argvp;; ++ap) { - if (!*ap) - errx(1, "%s: no terminating \";\"", opt); - if (**ap == ';') - break; - } - - cnt = ap - *argvp + 1; - new->e_argv = malloc(cnt * sizeof(*new->e_argv)); - new->e_orig = malloc(cnt * sizeof(*new->e_orig)); - new->e_len = malloc(cnt * sizeof(*new->e_len)); - - for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) { - new->e_orig[cnt] = *argv; - for (p = *argv; *p; ++p) - if (p[0] == '{' && p[1] == '}') { - new->e_argv[cnt] = malloc(MAXPATHLEN); - new->e_len[cnt] = MAXPATHLEN; - break; - } - if (!*p) { - new->e_argv[cnt] = *argv; - new->e_len[cnt] = 0; - } - } - new->e_argv[cnt] = new->e_orig[cnt] = NULL; - - *argvp = argv + 1; - return (new); -} - -PLAN * -c_exit(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - /* not technically true, but otherwise '-print' is implied */ - isoutput = 1; - - new = palloc(N_EXIT, f_always_true); - - if (arg) { - (*argvp)++; - new->exit_val = find_parsenum(new, opt, arg, NULL); - } else - new->exit_val = 0; - - return (new); -} - - -/* - * -false function - */ -int -f_false(PLAN *plan, FTSENT *entry) -{ - - return (0); -} - -PLAN * -c_false(char ***argvp, int isok, char *opt) -{ - return (palloc(N_FALSE, f_false)); -} - -/* - * -follow functions -- - * - * Always true, causes symbolic links to be followed on a global - * basis. - */ -PLAN * -c_follow(char ***argvp, int isok, char *opt) -{ - ftsoptions &= ~FTS_PHYSICAL; - ftsoptions |= FTS_LOGICAL; - - return (palloc(N_FOLLOW, f_always_true)); -} - -/* -fprint functions -- - * - * Causes the current pathame to be written to the defined output file. - */ -int -f_fprint(PLAN *plan, FTSENT *entry) -{ - - if (-1 == fprintf(plan->fprint_file, "%s\n", entry->fts_path)) - warn("fprintf"); - - return(1); - - /* no descriptors are closed; they will be closed by - operating system when this find command exits. */ -} - -PLAN * -c_fprint(char ***argvp, int isok, char *opt) -{ - PLAN *new; - - isoutput = 1; /* do not assume -print */ - - new = palloc(N_FPRINT, f_fprint); - - if (NULL == (new->fprint_file = fopen(**argvp, "w"))) - err(1, "%s: %s: cannot create file", opt, **argvp); - - (*argvp)++; - return (new); -} -#define MNT_RDONLY 0x01 -/* - * -fstype functions -- - * - * True if the file is of a certain type. - */ -int -f_fstype(PLAN *plan, FTSENT *entry) -{ - static char *fstype = NULL; - FILE *file; - struct mntent *mnt; - int flags; - char *filename = strdup(entry->fts_name); - char *temp = strrchr(filename, '/'); - temp[0] = '\0'; - - file = setmntent("/etc/mtab", "r"); - if (file == NULL) { - err(1, "couldn't read mount table"); - } - - while ((mnt = getmntent(file)) != NULL) { - if (!strncmp(mnt->mnt_dir, filename, strlen(mnt->mnt_dir))) { - fstype = strdup(mnt->mnt_type); - if (strstr(mnt->mnt_opts, MNTOPT_RO) != NULL) { - flags |= MNT_RDONLY; - } - break; - } - } - endmntent(file); - - switch (plan->flags) { - case F_MTFLAG: - return (flags & plan->mt_data); - case F_MTTYPE: - return (strncmp(fstype, plan->c_data, sizeof(fstype)) == 0); - default: - abort(); - } -} - -PLAN * -c_fstype(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_FSTYPE, f_fstype); - - switch (*arg) { - case 'r': - if (!strcmp(arg, "rdonly")) { - new->flags = F_MTFLAG; - new->mt_data = MNT_RDONLY; - return (new); - } - break; - } - - new->flags = F_MTTYPE; - new->c_data = arg; - return (new); -} - -/* - * -group gname functions -- - * - * True if the file belongs to the group gname. If gname is numeric and - * an equivalent of the getgrnam() function does not return a valid group - * name, gname is taken as a group ID. - */ -int -f_group(PLAN *plan, FTSENT *entry) -{ - - COMPARE(entry->fts_statp->st_gid, plan->g_data); -} - -PLAN * -c_group(char ***argvp, int isok, char *opt) -{ - char *gname = **argvp; - PLAN *new; - struct group *g; - gid_t gid; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_GROUP, f_group); - g = getgrnam(gname); - if (g == NULL) { - if (atoi(gname) == 0 && gname[0] != '0' && - strcmp(gname, "+0") && strcmp(gname, "-0")) - errx(1, "%s: %s: no such group", opt, gname); - gid = find_parsenum(new, "-group", gname, NULL); - - } else { - new->flags = F_EQUAL; - gid = g->gr_gid; - } - - new->g_data = gid; - return (new); -} - -/* - * -inum n functions -- - * - * True if the file has inode # n. - */ -int -f_inum(PLAN *plan, FTSENT *entry) -{ - - COMPARE(entry->fts_statp->st_ino, plan->i_data); -} - -PLAN * -c_inum(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_INUM, f_inum); - new->i_data = find_parsenum(new, opt, arg, NULL); - return (new); -} - -/* - * -links n functions -- - * - * True if the file has n links. - */ -int -f_links(PLAN *plan, FTSENT *entry) -{ - - COMPARE(entry->fts_statp->st_nlink, plan->l_data); -} - -PLAN * -c_links(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_LINKS, f_links); - new->l_data = (nlink_t)find_parsenum(new, opt, arg, NULL); - return (new); -} - -/* - * -ls functions -- - * - * Always true - prints the current entry to stdout in "ls" format. - */ -int -f_ls(PLAN *plan, FTSENT *entry) -{ - - printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp); - return (1); -} - -PLAN * -c_ls(char ***argvp, int isok, char *opt) -{ - - ftsoptions &= ~FTS_NOSTAT; - isoutput = 1; - - return (palloc(N_LS, f_ls)); -} - -/* - * - maxdepth n functions -- - * - * True if the current search depth is less than or equal to the - * maximum depth specified - */ -int -f_maxdepth(PLAN *plan, FTSENT *entry) -{ - extern FTS *tree; - - if (entry->fts_level >= plan->max_data) - fts_set(tree, entry, FTS_SKIP); - return (entry->fts_level <= plan->max_data); -} - -PLAN * -c_maxdepth(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - new = palloc(N_MAXDEPTH, f_maxdepth); - new->max_data = atoi(arg); - return (new); -} - -/* - * - mindepth n functions -- - * - * True if the current search depth is greater than or equal to the - * minimum depth specified - */ -int -f_mindepth(PLAN *plan, FTSENT *entry) -{ - return (entry->fts_level >= plan->min_data); -} - -PLAN * -c_mindepth(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - new = palloc(N_MINDEPTH, f_mindepth); - new->min_data = atoi(arg); - return (new); -} - -/* - * -mmin n functions -- - * - * True if the difference between the file modification time and the - * current time is n 24 hour periods. - */ -int -f_mmin(PLAN *plan, FTSENT *entry) -{ -#define SECSPERMIN 60 - COMPARE((now - entry->fts_statp->st_mtime + SECSPERMIN - 1) / - SECSPERMIN, plan->t_data); -} - -PLAN * -c_mmin(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_MMIN, f_mmin); - new->t_data = find_parsenum(new, opt, arg, NULL); - TIME_CORRECT(new, N_MMIN); - return (new); -} - -/* - * -mtime n functions -- - * - * True if the difference between the file modification time and the - * current time is n 24 hour periods. - */ -int -f_mtime(PLAN *plan, FTSENT *entry) -{ - COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) / - SECSPERDAY, plan->t_data); -} - -PLAN * -c_mtime(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_MTIME, f_mtime); - new->t_data = find_parsenum(new, opt, arg, NULL); - TIME_CORRECT(new, N_MTIME); - return (new); -} - -/* - * -name functions -- - * - * True if the basename of the filename being examined - * matches pattern using Pattern Matching Notation S3.14 - */ -int -f_name(PLAN *plan, FTSENT *entry) -{ - - return (!fnmatch(plan->c_data, entry->fts_name, 0)); -} - -PLAN * -c_name(char ***argvp, int isok, char *opt) -{ - char *pattern = **argvp; - PLAN *new; - - (*argvp)++; - new = palloc(N_NAME, f_name); - new->c_data = pattern; - return (new); -} - -/* - * -iname functions -- - * - * Similar to -name, but does case insensitive matching - * - */ -int -f_iname(PLAN *plan, FTSENT *entry) -{ - return (!fnmatch(plan->c_data, entry->fts_name, FNM_CASEFOLD)); -} - -PLAN * -c_iname(char ***argvp, int isok, char *opt) -{ - char *pattern = **argvp; - PLAN *new; - - (*argvp)++; - new = palloc(N_INAME, f_iname); - new->c_data = pattern; - return (new); -} - -/* - * -newer file functions -- - * - * True if the current file has been modified more recently - * than the modification time of the file named by the pathname - * file. - */ -int -f_newer(PLAN *plan, FTSENT *entry) -{ - - return timespeccmp(&entry->fts_statp->st_mtim, &plan->ts_data, >); -} - -PLAN * -c_newer(char ***argvp, int isok, char *opt) -{ - char *filename = **argvp; - PLAN *new; - struct stat sb; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - if (stat(filename, &sb)) - err(1, "%s: %s", opt, filename); - new = palloc(N_NEWER, f_newer); - new->ts_data = sb.st_mtim; - return (new); -} - -/* - * -nogroup functions -- - * - * True if file belongs to a user ID for which the equivalent - * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL. - */ -int -f_nogroup(PLAN *plan, FTSENT *entry) -{ - return getgrgid(entry->fts_statp->st_gid) != NULL; -} - -PLAN * -c_nogroup(char ***argvp, int isok, char *opt) -{ - ftsoptions &= ~FTS_NOSTAT; - - return (palloc(N_NOGROUP, f_nogroup)); -} - -/* - * -nouser functions -- - * - * True if file belongs to a user ID for which the equivalent - * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL. - */ -int -f_nouser(PLAN *plan, FTSENT *entry) -{ - return getpwuid(entry->fts_statp->st_uid) != NULL; -} - -PLAN * -c_nouser(char ***argvp, int isok, char *opt) -{ - ftsoptions &= ~FTS_NOSTAT; - - return (palloc(N_NOUSER, f_nouser)); -} - -/* - * -path functions -- - * - * True if the path of the filename being examined - * matches pattern using Pattern Matching Notation S3.14 - */ -int -f_path(PLAN *plan, FTSENT *entry) -{ - - return (!fnmatch(plan->c_data, entry->fts_path, 0)); -} - -PLAN * -c_path(char ***argvp, int isok, char *opt) -{ - char *pattern = **argvp; - PLAN *new; - - (*argvp)++; - new = palloc(N_NAME, f_path); - new->c_data = pattern; - return (new); -} - -/* - * -perm functions -- - * - * The mode argument is used to represent file mode bits. If it starts - * with a leading digit, it's treated as an octal mode, otherwise as a - * symbolic mode. - */ -int -f_perm(PLAN *plan, FTSENT *entry) -{ - mode_t mode; - - mode = entry->fts_statp->st_mode & - (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO); - if (plan->flags == F_ATLEAST) - return ((plan->m_data | mode) == mode); - else - return (mode == plan->m_data); - /* NOTREACHED */ -} - -PLAN * -c_perm(char ***argvp, int isok, char *opt) -{ - char *perm = **argvp; - PLAN *new; - mode_t *set; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_PERM, f_perm); - - if (*perm == '-') { - new->flags = F_ATLEAST; - ++perm; - } - - if ((set = setmode(perm)) == NULL) - err(1, "%s: Cannot set file mode `%s'", opt, perm); - - new->m_data = getmode(set, 0); - free(set); - return (new); -} - -/* - * -print functions -- - * - * Always true, causes the current pathame to be written to - * standard output. - */ -int -f_print(PLAN *plan, FTSENT *entry) -{ - - (void)printf("%s\n", entry->fts_path); - return (1); -} - -int -f_print0(PLAN *plan, FTSENT *entry) -{ - - (void)fputs(entry->fts_path, stdout); - (void)fputc('\0', stdout); - return (1); -} - -int -f_printx(PLAN *plan, FTSENT *entry) -{ - char *cp; - - for (cp = entry->fts_path; *cp; cp++) { - if (*cp == '\'' || *cp == '\"' || *cp == ' ' || - *cp == '$' || *cp == '`' || - *cp == '\t' || *cp == '\n' || *cp == '\\') - fputc('\\', stdout); - - fputc(*cp, stdout); - } - - fputc('\n', stdout); - return (1); -} - -PLAN * -c_print(char ***argvp, int isok, char *opt) -{ - - isoutput = 1; - - return (palloc(N_PRINT, f_print)); -} - -PLAN * -c_print0(char ***argvp, int isok, char *opt) -{ - - isoutput = 1; - - return (palloc(N_PRINT0, f_print0)); -} - -PLAN * -c_printx(char ***argvp, int isok, char *opt) -{ - - isoutput = 1; - - return (palloc(N_PRINTX, f_printx)); -} - -/* - * -prune functions -- - * - * Prune a portion of the hierarchy. - */ -int -f_prune(PLAN *plan, FTSENT *entry) -{ - if (fts_set(tree, entry, FTS_SKIP)) - err(1, "%s", entry->fts_path); - return (1); -} - -PLAN * -c_prune(char ***argvp, int isok, char *opt) -{ - - return (palloc(N_PRUNE, f_prune)); -} - -/* - * -regex regexp (and related) functions -- - * - * True if the complete file path matches the regular expression regexp. - * For -regex, regexp is a case-sensitive (basic) regular expression. - * For -iregex, regexp is a case-insensitive (basic) regular expression. - */ -int -f_regex(PLAN *plan, FTSENT *entry) -{ - - return (regexec(&plan->regexp_data, entry->fts_path, 0, NULL, 0) == 0); -} - -static PLAN * -c_regex_common(char ***argvp, int isok, enum ntype type, bool icase) -{ - char errbuf[LINE_MAX]; - regex_t reg; - char *regexp = **argvp; - char *lineregexp; - PLAN *new; - int rv; - size_t len; - - (*argvp)++; - - len = strlen(regexp) + 1 + 6; - lineregexp = malloc(len); /* max needed */ - if (lineregexp == NULL) - err(1, NULL); - snprintf(lineregexp, len, "^%s(%s%s)$", - (regcomp_flags & REG_EXTENDED) ? "" : "\\", regexp, - (regcomp_flags & REG_EXTENDED) ? "" : "\\"); - rv = regcomp(®, lineregexp, REG_NOSUB|regcomp_flags| - (icase ? REG_ICASE : 0)); - free(lineregexp); - if (rv != 0) { - regerror(rv, ®, errbuf, sizeof errbuf); - errx(1, "regexp %s: %s", regexp, errbuf); - } - - new = palloc(type, f_regex); - new->regexp_data = reg; - return (new); -} - -PLAN * -c_regex(char ***argvp, int isok, char *opt) -{ - - return (c_regex_common(argvp, isok, N_REGEX, false)); -} - -PLAN * -c_iregex(char ***argvp, int isok, char *opt) -{ - - return (c_regex_common(argvp, isok, N_IREGEX, true)); -} - -/* - * -since "timestamp" functions -- - * - * True if the file modification time is greater than the timestamp value - */ -int -f_since(PLAN *plan, FTSENT *entry) -{ - COMPARE(entry->fts_statp->st_mtime, plan->t_data); -} - -PLAN * -c_since(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_SINCE, f_since); - new->t_data = find_parsedate(new, opt, arg); - new->flags = F_GREATER; - return (new); -} - -/* - * -size n[c] functions -- - * - * 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. - */ -#define FIND_SIZE 512 -static int divsize = 1; - -int -f_size(PLAN *plan, FTSENT *entry) -{ - off_t size; - - size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) / - FIND_SIZE : entry->fts_statp->st_size; - COMPARE(size, plan->o_data); -} - -PLAN * -c_size(char ***argvp, int isok, char *opt) -{ - char *arg = **argvp; - PLAN *new; - char endch; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_SIZE, f_size); - endch = 'c'; - new->o_data = find_parsenum(new, opt, arg, &endch); - if (endch == 'c') - divsize = 0; - return (new); -} - -/* - * -type c functions -- - * - * True if the type of the file is c, where c is b, c, d, p, f or w - * for block special file, character special file, directory, FIFO, - * regular file or whiteout respectively. - */ -int -f_type(PLAN *plan, FTSENT *entry) -{ - - return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data); -} - -PLAN * -c_type(char ***argvp, int isok, char *opt) -{ - char *typestring = **argvp; - PLAN *new; - mode_t mask = (mode_t)0; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - switch (typestring[0]) { - case 'b': - mask = S_IFBLK; - break; - case 'c': - mask = S_IFCHR; - break; - case 'd': - mask = S_IFDIR; - break; - case 'f': - mask = S_IFREG; - break; - case 'l': - mask = S_IFLNK; - break; - case 'p': - mask = S_IFIFO; - break; - case 's': - mask = S_IFSOCK; - break; -#ifdef S_IFWHT - case 'W': - case 'w': - mask = S_IFWHT; -#ifdef FTS_WHITEOUT - ftsoptions |= FTS_WHITEOUT; -#endif - break; -#endif /* S_IFWHT */ - default: - errx(1, "%s: %s: unknown type", opt, typestring); - } - - new = palloc(N_TYPE, f_type); - new->m_data = mask; - return (new); -} - -/* - * -user uname functions -- - * - * True if the file belongs to the user uname. If uname is numeric and - * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not - * return a valid user name, uname is taken as a user ID. - */ -int -f_user(PLAN *plan, FTSENT *entry) -{ - - COMPARE(entry->fts_statp->st_uid, plan->u_data); -} - -PLAN * -c_user(char ***argvp, int isok, char *opt) -{ - char *username = **argvp; - PLAN *new; - struct passwd *p; - uid_t uid; - - (*argvp)++; - ftsoptions &= ~FTS_NOSTAT; - - new = palloc(N_USER, f_user); - p = getpwnam(username); - if (p == NULL) { - if (atoi(username) == 0 && username[0] != '0' && - strcmp(username, "+0") && strcmp(username, "-0")) - errx(1, "%s: %s: no such user", opt, username); - uid = find_parsenum(new, opt, username, NULL); - - } else { - new->flags = F_EQUAL; - uid = p->pw_uid; - } - - new->u_data = uid; - return (new); -} - -/* - * -xdev functions -- - * - * 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(char ***argvp, int isok, char *opt) -{ - ftsoptions |= FTS_XDEV; - - return (palloc(N_XDEV, f_always_true)); -} - -/* - * ( expression ) functions -- - * - * True if expression is true. - */ -int -f_expr(PLAN *plan, FTSENT *entry) -{ - PLAN *p; - int state; - - state = 0; - for (p = plan->p_data[0]; - p && (state = (p->eval)(p, entry)); p = p->next); - return (state); -} - -/* - * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers. They are - * eliminated during phase 2 of find_formplan() --- the '(' node is converted - * to a N_EXPR node containing the expression and the ')' node is discarded. - */ -PLAN * -c_openparen(char ***argvp, int isok, char *opt) -{ - - return (palloc(N_OPENPAREN, (int (*)(PLAN *, FTSENT *))-1)); -} - -PLAN * -c_closeparen(char ***argvp, int isok, char *opt) -{ - - return (palloc(N_CLOSEPAREN, (int (*)(PLAN *, FTSENT *))-1)); -} - -/* - * ! expression functions -- - * - * Negation of a primary; the unary NOT operator. - */ -int -f_not(PLAN *plan, FTSENT *entry) -{ - PLAN *p; - int state; - - state = 0; - for (p = plan->p_data[0]; - p && (state = (p->eval)(p, entry)); p = p->next); - return (!state); -} - -PLAN * -c_not(char ***argvp, int isok, char *opt) -{ - - return (palloc(N_NOT, f_not)); -} - -/* - * expression -o expression functions -- - * - * Alternation of primaries; the OR operator. The second expression is - * not evaluated if the first expression is true. - */ -int -f_or(PLAN *plan, FTSENT *entry) -{ - PLAN *p; - int state; - - state = 0; - for (p = plan->p_data[0]; - p && (state = (p->eval)(p, entry)); p = p->next); - - if (state) - return (1); - - for (p = plan->p_data[1]; - p && (state = (p->eval)(p, entry)); p = p->next); - return (state); -} - -PLAN * -c_or(char ***argvp, int isok, char *opt) -{ - - return (palloc(N_OR, f_or)); -} - -PLAN * -c_null(char ***argvp, int isok, char *opt) -{ - - return (NULL); -} - - -/* - * plan_cleanup -- - * Check and see if the specified plan has any residual state, - * and if so, clean it up as appropriate. - * - * At the moment, only N_EXEC has state. Two kinds: 1) - * lists of files to feed to subprocesses 2) State on exit - * statusses of past subprocesses. - */ -/* ARGSUSED1 */ -int -plan_cleanup(PLAN *plan, void *arg) -{ - if (plan->type==N_EXEC && plan->ep_narg) - run_f_exec(plan); - - return plan->ep_rval; /* Passed save exit-status up chain */ -} - -static PLAN * -palloc(enum ntype t, int (*f)(PLAN *, FTSENT *)) -{ - PLAN *new; - - if ((new = malloc(sizeof(PLAN))) == NULL) - err(1, NULL); - memset(new, 0, sizeof(PLAN)); - new->type = t; - new->eval = f; - return (new); -} |