summaryrefslogtreecommitdiff
path: root/usr.bin/find/find.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/find/find.c')
-rw-r--r--usr.bin/find/find.c1696
1 files changed, 1466 insertions, 230 deletions
diff --git a/usr.bin/find/find.c b/usr.bin/find/find.c
index 7b966bd..c56fedc 100644
--- a/usr.bin/find/find.c
+++ b/usr.bin/find/find.c
@@ -1,297 +1,1533 @@
-/* $NetBSD: find.c,v 1.30 2016/06/13 00:04:40 pgoyette Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- * 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.
+/* find COMPILE: cc -o find -s -O -i find.c -lS */
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, September 2003.
+ */
+/* from Unix 7th Edition /usr/src/cmd/find.c */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
*
* 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
+ * Redistributions of source code and documentation must retain the
+ * above copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 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.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of
+ * other 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.
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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/types.h>
-#include <sys/stat.h>
+#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
+#define USED __attribute__ ((used))
+#elif defined __GNUC__
+#define USED __attribute__ ((unused))
+#else
+#define USED
+#endif
+#if defined (SU3)
+static const char sccsid[] USED = "@(#)find_su3.sl 1.45 (gritter) 5/8/06";
+#elif defined (SUS)
+static const char sccsid[] USED = "@(#)find_sus.sl 1.45 (gritter) 5/8/06";
+#else
+static const char sccsid[] USED = "@(#)find.sl 1.45 (gritter) 5/8/06";
+#endif
-#include <err.h>
-#include <errno.h>
-#include <fts.h>
-#include <signal.h>
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
-#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <fcntl.h>
#include <unistd.h>
+#include <pwd.h>
+#include <time.h>
+#include <grp.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <errno.h>
+#include <locale.h>
+#include <signal.h>
+#include <fnmatch.h>
+#include <mntent.h>
+#ifndef major
+#include <sys/mkdev.h>
+#endif
+#if __NetBSD_Version__>= 300000000
+#include <sys/statvfs.h>
+#define statfs statvfs
+#endif
+#include "getdir.h"
+#define A_DAY 86400L /* a day full of seconds */
+#define EQ(x, y) (strcmp(x, y)==0)
+
+#ifndef MNTTYPE_IGNORE
+#define MNTTYPE_IGNORE ""
+#endif
+
+#ifndef S_IFDOOR
+#define S_IFDOOR 0xD000
+#endif
-#include "find.h"
+#ifndef S_IFNWK
+#define S_IFNWK 0x9000
+#endif
-static int ftscompare(const FTSENT **, const FTSENT **);
+#undef ctime
+#define ctime find_ctime
+
+static char *Pathname;
+
+struct aggregate { /* for exec ... {} + */
+ long a_cnt; /* count of arguments */
+ long a_cur; /* current position in aggregate */
+ long a_csz; /* aggregate current length */
+ long a_msz; /* aggregate maximum length */
+ char **a_vec; /* arguments */
+ char *a_spc; /* aggregate space */
+ long a_maxarg; /* maximum arguments in e_vec */
+};
+
+struct anode {
+ int (*F)(struct anode *);
+ union anode_l {
+ struct anode *L;
+ char *pat;
+ time_t t;
+ uid_t u;
+ gid_t g;
+ ino_t i;
+ nlink_t link;
+ off_t sz;
+ mode_t per;
+ int com;
+ FILE *fp;
+ char *fstype;
+ } l;
+ union anode_r {
+ struct anode *R;
+ int s;
+ pid_t pid;
+ struct aggregate *a;
+ } r;
+};
+static char *Fname;
+static time_t Now;
+static int Argc,
+ Ai,
+ Pi;
+static char **Argv;
+/* cpio stuff */
+static int Cpio;
+
+static struct stat Statb;
/*
- * find_formplan --
- * process the command line and create a "plan" corresponding to the
- * command arguments.
+ * Keep track of all visited directories, to avoid loops caused by
+ * symbolic links and to free storage and close files after fork().
*/
-PLAN *
-find_formplan(char **argv)
-{
- PLAN *plan, *tail, *new;
-
- /*
- * 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 = tail = NULL; *argv;) {
- if (!(new = find_create(&argv)))
- continue;
- if (plan == NULL)
- tail = plan = new;
- else {
- tail->next = new;
- tail = new;
+static struct visit {
+ struct getdb *v_db; /* getdb struct for this level */
+ ino_t v_ino; /* inode number */
+ int v_fd; /* file descriptor */
+ dev_t v_dev; /* device id */
+} *visited;
+static int vismax; /* number of members in visited */
+
+/*
+ * For -fstype, keep track of all filesystem types known to the system. If
+ * we had st_fstype in struct stat as SVR4 does, this would be far more
+ * reliable.
+ */
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+static struct fstype {
+ dev_t fsdev; /* device id of filesystem */
+ char *fstype; /* filesystem type */
+} *fstypes, *fscur;
+#endif /* __linux__ || _AIX || __hpux */
+
+static int Home = -1;
+static int wanthome;
+static mode_t um; /* user's umask */
+static const char *progname;
+static int status; /* exit status */
+static int depth; /* -depth flag */
+static int Print = 1; /* implicit -print */
+static int Prune; /* -prune at this point */
+static int Mount; /* -mount, -xdev */
+static int Execplus; /* have a -exec command {} + node */
+static int HLflag; /* -H or -L option given */
+static char *Statfs; /* result of statfs() on FreeBSD */
+static int incomplete; /* encountered an incomplete statement */
+static int sysv3;
+
+static int (*statfn)(const char *, struct stat *) = lstat;
+
+static struct anode *expr(void);
+static struct anode *e1(void);
+static struct anode *e2(void);
+static struct anode *e3(void);
+static struct anode *mk(struct anode *);
+static void oper(const char **);
+static char *nxtarg(int);
+static int and(struct anode *);
+static int or(struct anode *);
+static int not(struct anode *);
+static int glob(struct anode *);
+static int print(struct anode *);
+static int prune(struct anode *);
+static int null(struct anode *);
+static int mtime(struct anode *);
+static int atime(struct anode *);
+static int ctime(struct anode *);
+static int user(struct anode *);
+static int ino(struct anode *);
+static int group(struct anode *);
+static int nogroup(struct anode *);
+static int nouser(struct anode *);
+static int links(struct anode *);
+static int size(struct anode *);
+static int sizec(struct anode *);
+static int perm(struct anode *);
+static int type(struct anode *);
+static int exeq(struct anode *);
+static int ok(struct anode *);
+static int cpio(struct anode *);
+static int newer(struct anode *);
+static int cnewer(struct anode *);
+static int anewer(struct anode *);
+static int fstype(struct anode *);
+static int local(struct anode *);
+static int scomp(long long, long long, char);
+static int doex(int, struct aggregate *);
+static struct aggregate *mkagg(long);
+static uid_t getunum(const char *);
+static gid_t getgnum(const char *);
+static const char *getuser(uid_t);
+static const char *getgroup(gid_t);
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+static void getfscur(dev_t);
+static void getfstypes(void);
+#endif /* __linux__ || _AIX || __hpux */
+static int descend(char *, struct anode *, int);
+static int descend1(char *, struct anode *, int);
+static int descend2(char *, struct anode *, int);
+static void setpath(char *, const char *, int);
+static void pr(const char *, ...);
+static void er(const char *, ...);
+static void usage(void);
+static void *srealloc(void *, size_t);
+static void mkcpio(struct anode *, const char *, int);
+static void trailer(struct anode *, int);
+static void mknewer(struct anode *, const char *, int (*)(struct anode *));
+static mode_t newmode(const char *ms, const mode_t pm);
+
+int
+main(int argc, char **argv)
+{
+ struct anode *exlist;
+ struct anode nlist = { null, { 0 }, { 0 } };
+ int paths;
+ register char *sp = 0;
+ int i, j;
+
+ time(&Now);
+ umask(um = umask(0));
+ progname = basename(argv[0]);
+ setlocale(LC_COLLATE, "");
+ setlocale(LC_CTYPE, "");
+ if (getenv("SYSV3") != NULL)
+ sysv3 = 1;
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-' || argv[i][1] == '\0')
+ break;
+ if (argv[i][1] == '-') {
+ i++;
+ break;
+ }
+ for (j = 1; argv[i][j]; j++)
+ if (argv[i][j] != 'H' && argv[i][j] != 'L')
+ goto brk;
+ for (j = 1; argv[i][j]; j++)
+ HLflag = argv[i][j];
+ }
+brk: if (HLflag == 'L')
+ statfn = stat;
+ argc -= i - 1;
+ argv += i - 1;
+ Argc = argc; Argv = argv;
+ if(argc<2) {
+ pr("insufficient number of arguments");
+ usage();
+ }
+ for(Ai = paths = 1; Ai < argc; ++Ai, ++paths)
+ if(*Argv[Ai] == '-' || EQ(Argv[Ai], "(") || EQ(Argv[Ai], "!"))
+ break;
+ if(paths == 1) /* no path-list */
+ usage();
+ if(Ai<argc) {
+ if(!(exlist = expr())) /* parse and compile the arguments */
+ er("find: parsing error");
+ if(Ai<argc) {
+ pr("bad option %s", argv[Ai]);
+ usage();
}
+ } else
+ exlist = &nlist;
+ if (paths > 2)
+ wanthome = 1;
+ if (wanthome && (Home = open(".", O_RDONLY)) < 0)
+ er("bad starting directory");
+ for(Pi = 1; Pi < paths; ++Pi) {
+ if (Pi > 1 && Home >= 0 && fchdir(Home) < 0)
+ er("bad starting directory");
+ setpath(Pathname, Argv[Pi], 0);
+ Fname = sp = Pathname;
+ do
+ if (sp[0] == '/')
+ Fname = &sp[1];
+ while (*sp++);
+ descend(Pathname, exlist, 0); /* to find files that match */
+ }
+ if(Cpio || Execplus)
+ trailer(exlist, 1);
+ exit(status);
+}
+
+/* compile time functions: priority is expr()<e1()<e2()<e3() */
+
+/*ARGSUSED*/
+static struct anode *expr(void) { /* parse ALTERNATION (-o) */
+ register struct anode * p1;
+ struct anode n = { 0, { 0 }, { 0 } };
+
+ p1 = e1() /* get left operand */ ;
+ if(EQ(nxtarg(0), "-o")) {
+ const char *ops[] = { "-o", "-a", 0 };
+ oper(ops);
+ n.F = or, n.l.L = p1, n.r.R = expr();
+ return(mk(&n));
+ }
+ else if(Ai <= Argc) --Ai;
+ return(p1);
+}
+static struct anode *e1(void) { /* parse CONCATENATION (formerly -a) */
+ register struct anode * p1;
+ register char *a;
+ struct anode n = { 0, { 0 }, { 0 } };
+
+ p1 = e2();
+ a = nxtarg(0);
+ if(EQ(a, "-a")) {
+ const char *ops[] = { "-o", "-a", 0 };
+ oper(ops);
+And:
+ n.F = and, n.l.L = p1, n.r.R = e1();
+ return(mk(&n));
+ } else if(EQ(a, "(") || EQ(a, "!") || (*a=='-' && !EQ(a, "-o"))) {
+ --Ai;
+ goto And;
+ } else if(Ai <= Argc) --Ai;
+ return(p1);
+}
+static struct anode *e2(void) { /* parse NOT (!) */
+ struct anode n = { 0, { 0 }, { 0 } };
+ if(EQ(nxtarg(0), "!")) {
+ const char *ops[] = { "-o", "-a", "!", 0 };
+ oper(ops);
+ n.F = not, n.l.L = e3();
+ return(mk(&n));
+ }
+ else if(Ai <= Argc) --Ai;
+ return(e3());
+}
+static struct anode *e3(void) { /* parse parens and predicates */
+ struct anode *p1;
+ struct anode n = { 0, { 0 }, { 0 } };
+ long i, k;
+ register char *a, *b, s, *p, *q;
+
+ a = nxtarg(0);
+ if(EQ(a, "(")) {
+ const char *ops[] = { "-o", "-a", 0 };
+ oper(ops);
+ p1 = expr();
+ a = nxtarg(1);
+ if(!EQ(a, ")")) goto err;
+ return(p1);
+ }
+ else if(EQ(a, "-depth")) {
+ depth = 1;
+ n.F = null;
+ } else if(EQ(a, "-follow")) {
+ statfn = stat;
+ n.F = null;
+ } else if(EQ(a, "-mount") || EQ(a, "-xdev")) {
+ Mount = 1;
+ n.F = null;
+ } else if(EQ(a, "-print")) {
+ Print = 0;
+ n.F = print;
+ } else if(EQ(a, "-prune"))
+ n.F = prune;
+ else if(EQ(a, "-nogroup"))
+ n.F = nogroup;
+ else if(EQ(a, "-nouser"))
+ n.F = nouser;
+ else if(EQ(a, "-local")) {
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+ getfstypes();
+#endif /* __linux__ || _AIX || __hpux */
+ n.F = local;
+ Statfs = a;
+ }
+ if (n.F)
+ return mk(&n);
+ b = nxtarg(2);
+ s = *b;
+ /*if(s=='+') b++;*/
+ if(EQ(a, "-name"))
+ n.F = glob, n.l.pat = b;
+ else if(EQ(a, "-mtime"))
+ n.F = mtime, n.l.t = atol(b), n.r.s = s;
+ else if(EQ(a, "-atime"))
+ n.F = atime, n.l.t = atol(b), n.r.s = s;
+ else if(EQ(a, "-ctime"))
+ n.F = ctime, n.l.t = atol(b), n.r.s = s;
+ else if(EQ(a, "-user"))
+ n.F = user, n.l.u = getunum(b), n.r.s = s;
+ else if(EQ(a, "-inum"))
+ n.F = ino, n.l.i = atoll(b), n.r.s = s;
+ else if(EQ(a, "-group"))
+ n.F = group, n.l.g = getgnum(b), n.r.s = s;
+ else if(EQ(a, "-size")) {
+ n.l.sz = atoll(b), n.r.s = s;
+ while (b[0] && b[1])
+ b++;
+ if (b[0] == 'c')
+ n.F = sizec;
+ else
+ n.F = size;
+ }
+ else if(EQ(a, "-links"))
+ n.F = links, n.l.link = atol(b), n.r.s = s;
+ else if(EQ(a, "-perm")) {
+ while (*b == '-')
+ b++;
+ n.F = perm, n.l.per = newmode(b, 0), n.r.s = s;
+#if defined (SUS) || defined (SU3)
+ if (s == '-')
+ n.l.per &= 07777;
+#endif
+ }
+ else if(EQ(a, "-type")) {
+ i = b[0] == '-' || b[0] == '+' ? b[1] : b[0];
+ i = i=='d' ? S_IFDIR :
+ i=='b' ? S_IFBLK :
+ i=='c' ? S_IFCHR :
+ i=='D' ? S_IFDOOR :
+ i=='f' ? S_IFREG :
+ i=='l' ? S_IFLNK :
+ i=='n' ? S_IFNWK :
+ i=='p' ? S_IFIFO :
+ i=='s' ? S_IFSOCK :
+ 0;
+ n.F = type, n.l.per = i;
+ }
+ else if (EQ(a, "-exec")) {
+ Print = 0;
+ wanthome = 1;
+ i = Ai - 1;
+ q = "";
+ k = 0;
+ while(!EQ(p = nxtarg(1), ";")) {
+ if (EQ(p, "+") && EQ(q, "{}")) {
+ n.r.a = mkagg(k);
+ break;
+ }
+ q = p;
+ k += strlen(p) + 1;
+ }
+ n.F = exeq, n.l.com = i;
+ }
+ else if (EQ(a, "-ok")) {
+ Print = 0;
+ wanthome = 1;
+ i = Ai - 1;
+ while(!EQ(p = nxtarg(1), ";"));
+ n.F = ok, n.l.com = i;
+ }
+ else if(EQ(a, "-cpio"))
+ mkcpio(&n, b, 0);
+ else if(EQ(a, "-ncpio"))
+ mkcpio(&n, b, 1);
+ else if(EQ(a, "-newer"))
+ mknewer(&n, b, newer);
+ else if(EQ(a, "-anewer"))
+ mknewer(&n, b, anewer);
+ else if(EQ(a, "-cnewer"))
+ mknewer(&n, b, cnewer);
+ else if(EQ(a, "-fstype")) {
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+ getfstypes();
+#endif /* __linux__ || _AIX || __hpux */
+ n.F = fstype, n.l.fstype = b;
+ Statfs = a;
+ }
+ if (n.F) {
+ if (incomplete)
+ nxtarg(1);
+ return mk(&n);
+ }
+err: pr("bad option %s", a);
+ usage();
+ /*NOTREACHED*/
+ return 0;
+}
+static struct anode *mk(struct anode *p)
+{
+ struct anode *n;
+
+ n = srealloc(NULL, sizeof *n);
+ *n = *p;
+ return(n);
+}
+static void oper(const char **ops)
+{
+ char *a;
+
+ a = nxtarg(-1);
+ while (*ops)
+ if (EQ(a, *ops++))
+ er("operand follows operand");
+ Ai--;
+}
+
+static char *nxtarg(int must) { /* get next arg from command line */
+ static int strikes = 0;
+
+ if(must==1 && Ai>=Argc || strikes==3)
+ er("incomplete statement");
+ if(Ai>=Argc) {
+ if (must >= 0)
+ strikes++;
+ incomplete = 1;
+ Ai = Argc + 1;
+ return("");
}
+ return(Argv[Ai++]);
+}
- /*
- * if the user didn't specify one of -print, -ok, -fprint, -exec, or
- * -exit, then -print is assumed so we bracket the current expression
- * with parens, if necessary, and add a -print node on the end.
- */
- if (!isoutput) {
- if (plan == NULL) {
- new = c_print(NULL, 0, NULL);
- tail = plan = new;
+/* execution time functions */
+static int and(register struct anode *p)
+{
+ return(((*p->l.L->F)(p->l.L)) && ((*p->r.R->F)(p->r.R))?1:0);
+}
+static int or(register struct anode *p)
+{
+ return(((*p->l.L->F)(p->l.L)) || ((*p->r.R->F)(p->r.R))?1:0);
+}
+static int not(register struct anode *p)
+{
+ return( !((*p->l.L->F)(p->l.L)));
+}
+static int glob(register struct anode *p)
+{
+ int val;
+#ifdef __GLIBC__
+ /* avoid glibc's broken [^...] */
+ extern char **environ;
+ char **savenv = environ;
+ char *newenv[] = { "POSIXLY_CORRECT=", NULL };
+ environ = newenv;
+#endif /* __GLIBC__ */
+ val = fnmatch(p->l.pat, Fname, FNM_PATHNAME) == 0;
+#ifdef __GLIBC__
+ environ = savenv;
+#endif /* __GLIBC__ */
+ return val;
+}
+/*ARGSUSED*/
+static int print(register struct anode *p)
+{
+ puts(Pathname);
+ return(1);
+}
+/*ARGSUSED*/
+static int prune(register struct anode *p)
+{
+ if (!depth)
+ Prune = 1;
+ return(1);
+}
+/*ARGSUSED*/
+static int null(register struct anode *p)
+{
+ return(1);
+}
+static int mtime(register struct anode *p)
+{
+ return(scomp((Now - Statb.st_mtime) / A_DAY, p->l.t, p->r.s));
+}
+static int atime(register struct anode *p)
+{
+ return(scomp((Now - Statb.st_atime) / A_DAY, p->l.t, p->r.s));
+}
+static int ctime(register struct anode *p)
+{
+ return(scomp((Now - Statb.st_ctime) / A_DAY, p->l.t, p->r.s));
+}
+static int user(register struct anode *p)
+{
+ return(scomp(Statb.st_uid, p->l.u, p->r.s));
+}
+static int ino(register struct anode *p)
+{
+ return(scomp(Statb.st_ino, p->l.u, p->r.s));
+}
+static int group(register struct anode *p)
+{
+ return(p->l.u == Statb.st_gid);
+}
+static int nogroup(register struct anode *p)
+{
+ return(getgroup(Statb.st_gid) == NULL);
+}
+static int nouser(register struct anode *p)
+{
+ return(getuser(Statb.st_uid) == NULL);
+}
+static int links(register struct anode *p)
+{
+ return(scomp(Statb.st_nlink, p->l.link, p->r.s));
+}
+static int size(register struct anode *p)
+{
+ return(scomp(Statb.st_size?(Statb.st_size+511)>>9:0, p->l.sz, p->r.s));
+}
+static int sizec(register struct anode *p)
+{
+ return(scomp(Statb.st_size, p->l.sz, p->r.s));
+}
+static int perm(register struct anode *p)
+{
+ register int i;
+ i = (p->r.s=='-') ? p->l.per : 07777; /* '-' means only arg bits */
+ return((Statb.st_mode & i & 07777) == p->l.per);
+}
+static int type(register struct anode *p)
+{
+ return((Statb.st_mode&S_IFMT)==p->l.per);
+}
+static int exeq(register struct anode *p)
+{
+ if (p->r.a) {
+ if (Pathname) {
+ size_t sz = strlen(Pathname) + 1;
+ if (p->r.a->a_csz + sz <= p->r.a->a_msz &&
+ p->r.a->a_cur < p->r.a->a_maxarg-1) {
+ strcpy(p->r.a->a_vec[p->r.a->a_cur++] =
+ &p->r.a->a_spc[p->r.a->a_csz],
+ Pathname);
+ p->r.a->a_csz += sz;
+ return 1;
+ } else {
+ if (p->r.a->a_cur == 0) {
+ p->r.a->a_vec[p->r.a->a_cur++] =
+ Pathname;
+ p->r.a->a_vec[p->r.a->a_cur] = NULL;
+ }
+ else {
+ p->r.a->a_vec[p->r.a->a_cur] = NULL;
+ fflush(stdout);
+ doex(p->l.com, p->r.a);
+ return exeq(p);
+ }
+ }
} else {
- new = c_openparen(NULL, 0, NULL);
- new->next = plan;
- plan = new;
- new = c_closeparen(NULL, 0, NULL);
- tail->next = new;
- tail = new;
- new = c_print(NULL, 0, NULL);
- tail->next = new;
- tail = new;
+ if (p->r.a->a_cur == 0)
+ return 1;
+ p->r.a->a_vec[p->r.a->a_cur] = NULL;
}
}
+ fflush(stdout); /* to flush possible `-print' */
+ return(doex(p->l.com, p->r.a));
+}
+static int ok(struct anode *p)
+{
+ char c; int yes;
+ yes = 0;
+ fflush(stdout); /* to flush possible `-print' */
+ fprintf(stderr, "< %s ... %s >? ", Argv[p->l.com], Pathname);
+ if (read(0, &c, 1) != 1)
+ exit(2);
+ yes = c == 'y';
+ if (c != '\n')
+ while (read(0, &c, 1) == 1 && c != '\n');
+ if(yes) return(doex(p->l.com, 0));
+ return(0);
+}
- /*
- * 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 = paren_squish(plan); /* ()'s */
- plan = not_squish(plan); /* !'s */
- plan = or_squish(plan); /* -o's */
- return (plan);
+static int cpio(struct anode *p)
+{
+ if (strchr(Pathname, '\n')) {
+ pr("file name \"%s\" contains a newline character; "
+ "file not archived", Pathname);
+ status |= 1;
+ } else
+ fprintf(p->l.fp, "%s\n", Pathname);
+ return(1);
+}
+static int newer(register struct anode *p)
+{
+ return Statb.st_mtime > p->l.t;
+}
+static int anewer(register struct anode *p)
+{
+ return Statb.st_atime > p->l.t;
+}
+static int cnewer(register struct anode *p)
+{
+ return Statb.st_ctime > p->l.t;
+}
+static int fstype(register struct anode *p)
+{
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+ return(EQ(fscur->fstype, p->l.fstype));
+#elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
+ || defined (__DragonFly__) || defined (__APPLE__)
+ return(EQ(Statfs, p->l.fstype));
+#else
+ return(EQ(Statb.st_fstype, p->l.fstype));
+#endif
+}
+static int local(register struct anode *p)
+{
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+ return(strcmp(fscur->fstype, "nfs") && strcmp(fscur->fstype, "smbfs"));
+#elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
+ || defined (__DragonFly__) || defined (__APPLE__)
+ return(strcmp(Statfs, "nfs") != 0);
+#else
+ return(strcmp(Statb.st_fstype, "nfs") != 0);
+#endif
+}
+
+/* support functions */
+/* funny signed compare */
+static int scomp(register long long a, register long long b, register char s)
+{
+ if(s == '+')
+ return(a > b);
+ if(s == '-')
+ return(a < (b * -1));
+ return(a == b);
}
static int
-ftscompare(const FTSENT **e1, const FTSENT **e2)
+doex(int com, struct aggregate *a)
+{
+ register int np;
+ register char *na;
+ char **oargv;
+ int oargc;
+ static char **nargv;
+ static int narga;
+ static int ccode;
+ pid_t pid;
+
+ ccode = np = 0;
+ oargv = Argv;
+ oargc = com;
+ while (na=oargv[oargc++]) {
+ if (np >= narga-1)
+ nargv = srealloc(nargv, (narga+=20) * sizeof *nargv);
+ if(strcmp(na, ";")==0 && oargv == Argv) break;
+ if(strcmp(na, "{}")==0 && oargv == Argv) {
+ if (a) {
+ oargv = a->a_vec;
+ oargc = 0;
+ } else
+ nargv[np++] = Pathname;
+ }
+ else nargv[np++] = na;
+ }
+ if (a) {
+ a->a_cur = 0;
+ a->a_csz = 0;
+ }
+ if (np==0) return(9);
+ nargv[np] = 0;
+ if(pid = fork()) /*parent*/ while (wait(&ccode) != pid);
+ else { /*child*/
+ if (fchdir(Home) < 0) {
+ pr("bad starting directory");
+ _exit(1);
+ }
+ execvp(nargv[0], nargv);
+ _exit(1);
+ }
+ if (a && ccode) {
+ if (WIFSIGNALED(ccode))
+ status |= WTERMSIG(ccode) | 0200;
+ else if (WIFEXITED(ccode))
+ status |= WEXITSTATUS(ccode);
+ }
+ return(ccode && a==NULL ? 0:1);
+}
+
+static struct aggregate *mkagg(long baselen)
{
+ static size_t envsz;
+ extern char **environ;
+ register int i;
+ struct aggregate *a;
- return (strcoll((*e1)->fts_name, (*e2)->fts_name));
+ a = srealloc(NULL, sizeof *a);
+ if (envsz == 0)
+ for (i = 0; environ[i]; i++)
+ envsz += strlen(environ[i]) + 1;
+ a->a_msz = sysconf(_SC_ARG_MAX) - baselen - envsz - 2048;
+ a->a_spc = srealloc(NULL, a->a_msz);
+ a->a_maxarg = 8192;
+ a->a_vec = srealloc(NULL, a->a_maxarg * sizeof *a->a_vec);
+ a->a_csz = 0;
+ a->a_cur = 0;
+ Execplus = 1;
+ return a;
}
-static sigset_t ss;
-static bool notty;
+static uid_t getunum(const char *s) { /* find user name and return number */
+ struct passwd *pwd;
+ char *x;
+ uid_t u;
-static __inline void
-sig_init(void)
+ if ((pwd = getpwnam(s)) != NULL)
+ return pwd->pw_uid;
+ u = strtol(s, &x, 10);
+ if (*x == '\0')
+ return u;
+ er("cannot find %s name", s);
+ /*NOTREACHED*/
+ return 0;
+}
+
+static gid_t getgnum(const char *s) { /* find group name and return number */
+ struct group *grp;
+ char *x;
+ gid_t g;
+
+ if ((grp = getgrnam(s)) != NULL)
+ return grp->gr_gid;
+ g = strtol(s, &x, 10);
+ if (*x == '\0')
+ return g;
+ er("cannot find %s name", s);
+ /*NOTREACHED*/
+ return 0;
+}
+
+#define CACHESIZE 16
+
+static const char *getuser(uid_t uid)
{
- struct sigaction sa;
- notty = !(isatty(STDIN_FILENO) || isatty(STDOUT_FILENO) ||
- isatty(STDERR_FILENO));
- if (notty)
- return;
- sigemptyset(&ss);
- sigaddset(&ss, SIGHUP); /* block SIGINFO */
+ static struct {
+ char *name;
+ uid_t uid;
+ } cache[CACHESIZE];
+ static int last;
+ int i;
+ struct passwd *pwd;
+ const char *name;
- memset(&sa, 0, sizeof(sa));
- sa.sa_flags = SA_RESTART;
- sa.sa_handler = show_path;
- (void)sigaction(SIGHUP, &sa, NULL);
+ for (i = 0; i < CACHESIZE && cache[i].name; i++)
+ if (cache[i].uid == uid)
+ goto found;
+ if ((pwd = getpwuid(uid)) != NULL)
+ name = pwd->pw_name;
+ else
+ name = "";
+ if (i >= CACHESIZE) {
+ if (last >= CACHESIZE)
+ last = 0;
+ i = last++;
+ }
+ if (cache[i].name)
+ free(cache[i].name);
+ cache[i].name = strdup(name);
+ cache[i].uid = uid;
+found: return cache[i].name[0] ? cache[i].name : NULL;
+}
+static const char *getgroup(gid_t gid)
+{
+ static struct {
+ char *name;
+ gid_t gid;
+ } cache[CACHESIZE];
+ static int last;
+ int i;
+ struct group *grp;
+ const char *name;
+
+ for (i = 0; i < CACHESIZE && cache[i].name; i++)
+ if (cache[i].gid == gid)
+ goto found;
+ if ((grp = getgrgid(gid)) != NULL)
+ name = grp->gr_name;
+ else
+ name = "";
+ if (i >= CACHESIZE) {
+ if (last >= CACHESIZE)
+ last = 0;
+ i = last++;
+ }
+ if (cache[i].name)
+ free(cache[i].name);
+ cache[i].name = strdup(name);
+ cache[i].gid = gid;
+found: return cache[i].name[0] ? cache[i].name : NULL;
}
-static __inline void
-sig_lock(sigset_t *s)
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+static void getfscur(dev_t dev)
{
- if (notty)
- return;
- sigprocmask(SIG_BLOCK, &ss, s);
+ int i;
+
+ for (i = 0; fstypes[i].fstype; i++)
+ if (fstypes[i].fsdev == dev) {
+ fscur = &fstypes[i];
+ return;
+ }
+ er("filesystem type for %s unknown", Pathname);
}
-static __inline void
-sig_unlock(const sigset_t *s)
+static void getfstypes(void)
{
- if (notty)
+ struct stat st;
+ FILE *fp;
+ struct mntent *mp;
+#ifdef __hpux
+ const char mtab[] = "/etc/mnttab";
+#else /* __linux__, _AIX */
+ const char mtab[] = "/etc/mtab";
+#endif /* __linux__, _AIX */
+ int i = 0;
+
+ if (fstypes)
return;
- sigprocmask(SIG_SETMASK, s, NULL);
+ if ((fp = setmntent(mtab, "r")) == NULL)
+ er("cannot open %s: %s", mtab, strerror(errno));
+ while ((mp = getmntent(fp)) != NULL) {
+ if (EQ(mp->mnt_type, MNTTYPE_IGNORE))
+ continue;
+ if (stat(mp->mnt_dir, &st) < 0)
+ continue;
+ fstypes = srealloc(fstypes, (i+1) * sizeof *fstypes);
+ fstypes[i].fsdev = st.st_dev;
+ fstypes[i].fstype = strdup(mp->mnt_type);
+ i++;
+ }
+ endmntent(fp);
}
-
-FTS *tree; /* pointer to top of FTS hierarchy */
-FTSENT *g_entry; /* shared with SIGINFO handler */
+#endif /* __linux__ || _AIX || __hpux */
/*
- * 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.
+ * First part of descend, called for any file found.
*/
-int
-find_execute(PLAN *plan, char **paths)
+static int descend(char *fname, struct anode *exlist, int level)
{
- PLAN *p;
- int r, rval, cval;
- sigset_t s;
+ struct stat ost;
+ register char *c1;
+ int i;
+ int rv = 0;
+
+ if(statfn(fname, &Statb)<0) {
+ if (statfn != lstat && lstat(fname, &Statb) == 0)
+ nof: c1 = "cannot follow symbolic link %s: %s";
+ else if (sysv3)
+ c1 = "stat() failed: %s: %s";
+ else if (errno == ENOENT || errno == ENOTDIR)
+ c1 = "cannot open %s: %s";
+ else
+ c1 = "stat() error %s: %s";
+ pr(c1, Pathname, strerror(errno));
+ status = 18;
+ return(0);
+ }
+ if (level == 0 && HLflag == 'H' && (Statb.st_mode&S_IFMT) == S_IFLNK) {
+ struct stat nst;
+ if (stat(fname, &nst) == 0)
+ Statb = nst;
+ else if (errno == ELOOP)
+ goto nof;
+ }
+#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || \
+ defined (__DragonFly__) || defined (__APPLE__)
+ if (Statfs != NULL) {
+ static struct statfs sf;
+ if (statfs(fname, &sf) < 0) {
+ pr("statfs() error %s: %s", Pathname, strerror(errno));
+ status = 18;
+ return(0);
+ }
+ Statfs = sf.f_fstypename;
+ }
+#endif /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+ if (Mount) {
+ static dev_t curdev;
+ if (level == 0)
+ curdev = Statb.st_dev;
+ else if (curdev != Statb.st_dev)
+ return(0);
+ }
+ Prune = 0;
+ if (!depth) {
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+ if (fstypes)
+ getfscur(Statb.st_dev);
+#endif /* __linux__ || _AIX || __hpux */
+ if((*exlist->F)(exlist) && Print)
+ puts(Pathname);
+ } else
+ ost = Statb;
+ if(Prune || (Statb.st_mode&S_IFMT)!=S_IFDIR)
+ goto reg;
+ if (statfn != lstat) {
+ for (i = 0; i < level; i++)
+ if (Statb.st_dev == visited[i].v_dev &&
+ Statb.st_ino == visited[i].v_ino) {
+#ifdef SU3
+ pr("Symbolic link loop at %s", Pathname);
+ status = 18;
+#endif /* SU3 */
+ goto reg;
+ }
+ }
+ if (level >= vismax) {
+ vismax += 20;
+ visited = srealloc(visited, sizeof *visited * vismax);
+ }
+ visited[level].v_dev = Statb.st_dev;
+ visited[level].v_ino = Statb.st_ino;
- cval = 1;
+ rv = descend1(fname, exlist, level);
- if (!(tree = fts_open(paths, ftsoptions, issort ? ftscompare : NULL)))
- err(1, "ftsopen");
+reg:
+ if (depth) {
+ Statb = ost;
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+ if (fstypes)
+ getfscur(Statb.st_dev);
+#endif /* __linux__ || _AIX || __hpux */
+ if ((*exlist->F)(exlist) && Print)
+ puts(Pathname);
+ }
+ return(rv);
+}
- sig_init();
- sig_lock(&s);
- for (rval = 0; cval && (g_entry = fts_read(tree)) != NULL;) {
- switch (g_entry->fts_info) {
- case FTS_D:
- if (isdepth)
- continue;
- break;
- case FTS_DP:
- if (!isdepth)
- continue;
- break;
- case FTS_DNR:
- case FTS_ERR:
- case FTS_NS:
- sig_unlock(&s);
- (void)fflush(stdout);
- warnx("%s: %s",
- g_entry->fts_path, strerror(g_entry->fts_errno));
- rval = 1;
- sig_lock(&s);
- continue;
- }
-#define BADCH " \t\n\\'\""
- if (isxargs && strpbrk(g_entry->fts_path, BADCH)) {
- sig_unlock(&s);
- (void)fflush(stdout);
- warnx("%s: illegal path", g_entry->fts_path);
- rval = 1;
- sig_lock(&s);
+/*
+ * Second part of descend, called for any directory found.
+ */
+static int descend1(char *fname, struct anode *exlist, int level)
+{
+ int dir = 0; /* open directory */
+ register char *c1;
+ struct getdb *db;
+ register struct direc *dp;
+ int endofname;
+ int err;
+ int oflags = O_RDONLY;
+
+#ifdef O_DIRECTORY
+ oflags |= O_DIRECTORY;
+#endif
+#ifdef O_NOFOLLOW
+ if (statfn == lstat && (HLflag != 'H' || level > 0))
+ oflags |= O_NOFOLLOW;
+#endif
+ if ((dir = open(fname, oflags)) < 0 ||
+ fcntl(dir, F_SETFD, FD_CLOEXEC) < 0 ||
+ fchdir(dir) < 0) {
+ if (dir >= 0)
+ close(dir);
+ else if (errno == EMFILE && descend2(fname, exlist, level))
+ /*
+ * A possible performance improvement would be to
+ * call descend2() in the directory above, since
+ * the current method involves one fork() call per
+ * subdirectory at this level. The condition occurs
+ * so rarely that it seems hardly worth optimization
+ * though.
+ */
+ return 0;
+ pr("cannot open %s: %s", Pathname, strerror(errno));
+ status = 18;
+ return 0;
+ }
+ if ((db = getdb_alloc(Pathname, dir)) == NULL) {
+ write(2, "no memory\n", 10);
+ _exit(077);
+ }
+ visited[level].v_db = db;
+ visited[level].v_fd = dir;
+ for(c1 = Pathname; *c1; ++c1);
+ if(*(c1-1) == '/')
+ --c1;
+ endofname = c1 - Pathname;
+
+ while ((dp = getdir(db, &err)) != NULL) {
+ if((dp->d_name[0]=='.' && dp->d_name[1]=='\0') ||
+ (dp->d_name[0]=='.' &&
+ dp->d_name[1]=='.' && dp->d_name[2]=='\0'))
continue;
+ setpath(&Pathname[endofname], dp->d_name, 1);
+ Fname = &Pathname[endofname+1];
+ if(descend(Fname, exlist, level+1)) {
+ if (fchdir(dir) < 0)
+ er("bad directory tree");
}
+ }
+ Pathname[endofname] = '\0';
+ getdb_free(db);
+ if (err) {
+ pr("cannot read dir %s: %s", Pathname, strerror(errno));
+ status = 18;
+ }
+ close(dir);
+ visited[level].v_fd = -1;
+ return 1;
+}
+
+/*
+ * Third part of descend, called if the limit of open file descriptors
+ * is exceeded (EMFILE).
+ */
+static int descend2(char *fname, struct anode *exlist, int level)
+{
+ pid_t pid;
+ int i;
- /*
- * 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.
- */
- sig_unlock(&s);
- for (p = plan; p && (p->eval)(p, g_entry); p = p->next)
- if (p->type == N_EXIT) {
- rval = p->exit_val;
- cval = 0;
+ if (Cpio || Execplus)
+ trailer(exlist, 0);
+ fflush(stdout);
+ switch (pid = fork()) {
+ case 0:
+ for (i = 0; i < level-1; i++) {
+ if (visited[i].v_fd >= 0) {
+ getdb_free(visited[i].v_db);
+ close(visited[i].v_fd);
+ visited[i].v_fd = -1;
}
- sig_lock(&s);
+ }
+ status |= 0;
+ descend1(fname, exlist, level);
+ if (Cpio || Execplus)
+ trailer(exlist, 0);
+ exit(status);
+ /*NOTREACHED*/
+ default:
+ while (waitpid(pid, &i, 0) != pid);
+ if (i && WIFSIGNALED(i)) {
+ struct rlimit rl;
+
+ rl.rlim_cur = rl.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rl);
+ raise(WTERMSIG(i));
+ pause();
+ }
+ if (i)
+ status |= WEXITSTATUS(i);
+ return 1;
+ case -1:
+ return 0;
+ }
+}
+static void setpath(char *eos, const char *fn, int slash)
+{
+ static char *pathend;
+ char *opath;
+
+ for (;;) {
+ if (eos >= pathend) {
+ pathend += 14;
+ opath = Pathname;
+ Pathname = srealloc(Pathname, pathend - Pathname);
+ eos += Pathname - opath;
+ pathend += Pathname - opath;
+ }
+ if (slash) {
+ *eos++ = '/';
+ slash = 0;
+ } else
+ if ((*eos++ = *fn++) == '\0')
+ break;
}
+}
- sig_unlock(&s);
- if (g_entry == NULL && errno)
- err(1, "fts_read");
- (void)fts_close(tree);
+static void pr(const char *s, ...)
+{
+ va_list ap;
- /*
- * Cleanup any plans with leftover state.
- * Keep the last non-zero return value.
- */
- if ((r = find_traverse(plan, plan_cleanup, NULL)) != 0)
- rval = r;
+ fprintf(stderr, "%s: ", progname);
+ va_start(ap, s);
+ vfprintf(stderr, s, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void er(const char *s, ...)
+{
+ va_list ap;
- return (rval);
+ fprintf(stderr, "%s: ", progname);
+ va_start(ap, s);
+ vfprintf(stderr, s, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ exit(1);
}
+static void usage(void)
+{
+ er("path-list predicate-list");
+}
+
+static void *srealloc(void *op, size_t n)
+{
+ void *np;
+
+ if ((np = realloc(op, n)) == NULL) {
+ write(2, "no memory\n", 10);
+ _exit(077);
+ }
+ return np;
+}
+
+static void mkcpio(struct anode *p, const char *b, int ascii)
+{
+ int fd, pd[2];
+ char flags[20], *cp;
+
+ p->F = cpio;
+ if (*b == '\0')
+ return;
+ depth = 1;
+ Print = 0;
+ Cpio = 1;
+ if (pipe(pd) < 0 || (p->l.fp = fdopen(pd[1], "w")) == NULL)
+ er("pipe() %s", strerror(errno));
+ if ((fd = creat(b, 0666)) < 0)
+ er("cannot create %s", b);
+ switch (p->r.pid = fork()) {
+ case -1:
+ er("can't fork");
+ /*NOTREACHED*/
+ case 0:
+ dup2(pd[0], 0);
+ close(pd[0]);
+ close(pd[1]);
+ dup2(fd, 1);
+ close(fd);
+ cp = flags;
+ *cp++ = '-';
+ *cp++ = 'o';
+ *cp++ = 'B';
+ if (ascii)
+ *cp++ = 'c';
+ if (statfn == stat)
+ *cp++ = 'L';
+ *cp = '\0';
+ execlp("cpio", "cpio", flags, NULL);
+ pr("cannot exec cpio: %s", strerror(errno));
+ _exit(0177);
+ /*NOTREACHED*/
+ }
+ close(pd[0]);
+ close(fd);
+}
+
+static void
+trailer(register struct anode *p, int termcpio)
+{
+ char *Opath = Pathname;
+ Pathname = 0;
+ if (p->F == or || p->F == and) {
+ trailer(p->l.L, termcpio);
+ trailer(p->r.R, termcpio);
+ } else if (p->F == not)
+ trailer(p->l.L, termcpio);
+ else if (p->F == cpio) {
+ if (termcpio) {
+ int s;
+
+ fclose(p->l.fp);
+ while (waitpid(p->r.pid, &s, 0) != p->r.pid);
+ if (s) {
+ if (WIFEXITED(s))
+ status |= WEXITSTATUS(s);
+ else if (WIFSIGNALED(s))
+ status |= WTERMSIG(s) | 0200;
+ }
+ } else
+ fflush(p->l.fp);
+ } else if (p->F == exeq && p->r.a)
+ exeq(p);
+ Pathname = Opath;
+}
+
+static void
+mknewer(struct anode *p, const char *b, int (*f)(struct anode *))
+{
+ if (*b && stat(b, &Statb) < 0)
+ er("cannot access %s", b);
+ p->l.t = Statb.st_mtime;
+ p->F = f;
+}
+
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, September 2003.
+ */
+/* from Unix 7th Edition /usr/src/cmd/chmod.c */
/*
- * find_traverse --
- * traverse the plan tree and execute func() on all plans. This
- * does not evaluate each plan's eval() function; it is intended
- * for operations that must run on all plans, such as state
- * cleanup.
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * Redistributions of source code and documentation must retain the
+ * above copyright notice, this list of conditions and the following
+ * disclaimer.
+ * 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.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of
+ * other contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
*
- * If any func() returns non-zero, then so will find_traverse().
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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.
*/
-int
-find_traverse(PLAN *plan, int (*func)(PLAN *, void *), void *arg)
-{
- PLAN *p;
- int r, rval;
-
- rval = 0;
- for (p = plan; p; p = p->next) {
- if ((r = func(p, arg)) != 0)
- rval = r;
- if (p->type == N_EXPR || p->type == N_OR) {
- if (p->p_data[0])
- if ((r = find_traverse(p->p_data[0],
- func, arg)) != 0)
- rval = r;
- if (p->p_data[1])
- if ((r = find_traverse(p->p_data[1],
- func, arg)) != 0)
- rval = r;
+
+#define USER 05700 /* user's bits */
+#define GROUP 02070 /* group's bits */
+#define OTHER 00007 /* other's bits */
+#define ALL 07777 /* all */
+
+#define READ 00444 /* read permit */
+#define WRITE 00222 /* write permit */
+#define EXEC 00111 /* exec permit */
+#define SETID 06000 /* set[ug]id */
+#define STICKY 01000 /* sticky bit */
+
+#ifndef S_ENFMT
+#define S_ENFMT 02000 /* mandatory locking bit */
+#endif
+
+static mode_t absol(const char **);
+static mode_t who(const char **, mode_t *);
+static int what(const char **);
+static mode_t where(const char **, mode_t, int *, int *, const mode_t);
+
+static mode_t
+newmode(const char *ms, const mode_t pm)
+{
+ register mode_t o, m, b;
+ int lock, setsgid = 0, cleared = 0, copy = 0;
+ mode_t nm, om, mm;
+ const char *mo = ms;
+
+ nm = om = pm;
+ m = absol(&ms);
+ if (!*ms) {
+ nm = m;
+ goto out;
+ }
+ if ((lock = (nm&S_IFMT) != S_IFDIR && (nm&(S_ENFMT|S_IXGRP)) == S_ENFMT)
+ == 01)
+ nm &= ~(mode_t)S_ENFMT;
+ do {
+ m = who(&ms, &mm);
+ while (o = what(&ms)) {
+ b = where(&ms, nm, &lock, &copy, pm);
+ switch (o) {
+ case '+':
+ nm |= b & m & ~mm;
+ if (b & S_ISGID)
+ setsgid = 1;
+ if (lock & 04)
+ lock |= 02;
+ break;
+ case '-':
+ nm &= ~(b & m & ~mm);
+ if (b & S_ISGID)
+ setsgid = 1;
+ if (lock & 04)
+ lock = 0;
+ break;
+ case '=':
+ nm &= ~m;
+ nm |= b & m & ~mm;
+ lock &= ~01;
+ if (lock & 04)
+ lock |= 02;
+ om = 0;
+ if (copy == 0)
+ cleared = 1;
+ break;
+ }
+ lock &= ~04;
}
+ } while (*ms++ == ',');
+ if (*--ms)
+ er("bad permissions: %s", mo);
+out: if (pm & S_IFDIR) {
+ if ((pm & S_ISGID) && setsgid == 0)
+ nm |= S_ISGID;
+ else if ((nm & S_ISGID) && setsgid == 0)
+ nm &= ~(mode_t)S_ISGID;
+ }
+ return(nm);
+}
+
+static mode_t
+absol(const char **ms)
+{
+ register int c, i;
+
+ i = 0;
+ while ((c = *(*ms)++) >= '0' && c <= '7')
+ i = (i << 3) + (c - '0');
+ (*ms)--;
+ return(i);
+}
+
+static mode_t
+who(const char **ms, mode_t *mp)
+{
+ register int m;
+
+ m = 0;
+ *mp = 0;
+ for (;;) switch (*(*ms)++) {
+ case 'u':
+ m |= USER;
+ continue;
+ case 'g':
+ m |= GROUP;
+ continue;
+ case 'o':
+ m |= OTHER;
+ continue;
+ case 'a':
+ m |= ALL;
+ continue;
+ default:
+ (*ms)--;
+ if (m == 0) {
+ m = ALL;
+ *mp = um;
+ }
+ return m;
+ }
+}
+
+static int
+what(const char **ms)
+{
+ switch (**ms) {
+ case '+':
+ case '-':
+ case '=':
+ return *(*ms)++;
+ }
+ return(0);
+}
+
+static mode_t
+where(const char **ms, mode_t om, int *lock, int *copy, const mode_t pm)
+{
+ register mode_t m;
+
+ m = 0;
+ *copy = 0;
+ switch (**ms) {
+ case 'u':
+ m = (om & USER) >> 6;
+ goto dup;
+ case 'g':
+ m = (om & GROUP) >> 3;
+ goto dup;
+ case 'o':
+ m = (om & OTHER);
+ dup:
+ *copy = 1;
+ m &= (READ|WRITE|EXEC);
+ m |= (m << 3) | (m << 6);
+ ++(*ms);
+ return m;
+ }
+ for (;;) switch (*(*ms)++) {
+ case 'r':
+ m |= READ;
+ continue;
+ case 'w':
+ m |= WRITE;
+ continue;
+ case 'x':
+ m |= EXEC;
+ continue;
+ case 'X':
+ if ((pm&S_IFMT) == S_IFDIR || (pm & EXEC))
+ m |= EXEC;
+ continue;
+ case 'l':
+ if ((pm&S_IFMT) != S_IFDIR)
+ *lock |= 04;
+ continue;
+ case 's':
+ m |= SETID;
+ continue;
+ case 't':
+ m |= STICKY;
+ continue;
+ default:
+ (*ms)--;
+ return m;
}
- return rval;
}