commands, man: remove minix find
This commit is contained in:
parent
6faa2a636c
commit
13d50be356
4 changed files with 1 additions and 1016 deletions
|
@ -11,7 +11,7 @@ SUBDIR= aal add_route adduser advent arp ash at autil awk \
|
||||||
dd de decomp16 DESCRIBE dev2name devsize df dhcpd \
|
dd de decomp16 DESCRIBE dev2name devsize df dhcpd \
|
||||||
dhrystone diff dirname dis88 du dumpcore easypack \
|
dhrystone diff dirname dis88 du dumpcore easypack \
|
||||||
ed eject elle elvis env expand factor fgrep file \
|
ed eject elle elvis env expand factor fgrep file \
|
||||||
find finger fingerd fix fold format fortune fsck \
|
finger fingerd fix fold format fortune fsck \
|
||||||
fsck1 ftp101 ftpd200 getty gomoku grep head host \
|
fsck1 ftp101 ftpd200 getty gomoku grep head host \
|
||||||
hostaddr id ifconfig ifdef indent install \
|
hostaddr id ifconfig ifdef indent install \
|
||||||
intr ipcrm ipcs irdpd isoread join kill last leave \
|
intr ipcrm ipcs irdpd isoread join kill last leave \
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
PROG= find
|
|
||||||
MAN=
|
|
||||||
|
|
||||||
.include <minix.prog.mk>
|
|
|
@ -1,927 +0,0 @@
|
||||||
/* find - look for files satisfying a predicate Author: E. Baalbergen */
|
|
||||||
|
|
||||||
/* Original author: Erik Baalbergen; POSIX compliant version: Bert Laverman */
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <grp.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/*######################## DEFINITIONS ##############################*/
|
|
||||||
|
|
||||||
#ifdef S_IFLNK
|
|
||||||
#define LSTAT lstat
|
|
||||||
#else
|
|
||||||
#define LSTAT stat
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SHELL "/bin/sh"
|
|
||||||
#define MAXARG 256 /* maximum length for an argv for -exec */
|
|
||||||
#define BSIZE 512 /* POSIX wants 512 byte blocks */
|
|
||||||
#define SECS_PER_DAY (24L*60L*60L) /* check your planet */
|
|
||||||
|
|
||||||
#define OP_NAME 1 /* match name */
|
|
||||||
#define OP_PERM 2 /* check file permission bits */
|
|
||||||
#define OP_TYPE 3 /* check file type bits */
|
|
||||||
#define OP_LINKS 4 /* check link count */
|
|
||||||
#define OP_USER 5 /* check owner */
|
|
||||||
#define OP_GROUP 6 /* check group ownership */
|
|
||||||
#define OP_SIZE 7 /* check size, blocks or bytes */
|
|
||||||
#define OP_SIZEC 8 /* this is a fake for -size with 'c' */
|
|
||||||
#define OP_INUM 9 /* compare inode number */
|
|
||||||
#define OP_ATIME 10 /* check last access time */
|
|
||||||
#define OP_CTIME 11 /* check creation time */
|
|
||||||
#define OP_MTIME 12 /* check last modification time */
|
|
||||||
#define OP_EXEC 13 /* execute command */
|
|
||||||
#define OP_OK 14 /* execute with confirmation */
|
|
||||||
#define OP_PRINT 15 /* print name */
|
|
||||||
#define OP_PRINT0 16 /* print name null terminated */
|
|
||||||
#define OP_NEWER 17 /* compare modification times */
|
|
||||||
#define OP_CNEWER 18 /* compare modification times */
|
|
||||||
#define OP_AND 19 /* logical and (short circuit) */
|
|
||||||
#define OP_OR 20 /* logical or (short circuit) */
|
|
||||||
#define OP_XDEV 21 /* do not cross file-system boundaries */
|
|
||||||
#define OP_DEPTH 22 /* descend directory before testing */
|
|
||||||
#define OP_PRUNE 23 /* don't descend into current directory */
|
|
||||||
#define OP_NOUSER 24 /* check validity of user id */
|
|
||||||
#define OP_NOGROUP 25 /* check validity of group id */
|
|
||||||
#define LPAR 26 /* left parenthesis */
|
|
||||||
#define RPAR 27 /* right parenthesis */
|
|
||||||
#define NOT 28 /* logical not */
|
|
||||||
|
|
||||||
/* Some return values: */
|
|
||||||
#define EOI -1 /* end of expression */
|
|
||||||
#define NONE 0 /* not a valid predicate */
|
|
||||||
|
|
||||||
/* For -perm with symbolic modes: */
|
|
||||||
#define ISWHO(c) ((c == 'u') || (c == 'g') || (c == 'o') || (c == 'a'))
|
|
||||||
#define ISOPER(c) ((c == '-') || (c == '=') || (c == '+'))
|
|
||||||
#define ISMODE(c) ((c == 'r') || (c == 'w') || (c == 'x') || \
|
|
||||||
(c == 's') || (c == 't'))
|
|
||||||
#define MUSER 1
|
|
||||||
#define MGROUP 2
|
|
||||||
#define MOTHERS 4
|
|
||||||
|
|
||||||
|
|
||||||
struct exec {
|
|
||||||
int e_cnt;
|
|
||||||
char *e_vec[MAXARG];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct node {
|
|
||||||
int n_type; /* any OP_ or NOT */
|
|
||||||
union {
|
|
||||||
char *n_str;
|
|
||||||
struct {
|
|
||||||
long n_val;
|
|
||||||
int n_sign;
|
|
||||||
} n_int;
|
|
||||||
struct exec *n_exec;
|
|
||||||
struct {
|
|
||||||
struct node *n_left, *n_right;
|
|
||||||
} n_opnd;
|
|
||||||
} n_info;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct oper {
|
|
||||||
char *op_str;
|
|
||||||
int op_val;
|
|
||||||
} ops[] = {
|
|
||||||
|
|
||||||
{
|
|
||||||
"name", OP_NAME
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"perm", OP_PERM
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type", OP_TYPE
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"links", OP_LINKS
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"user", OP_USER
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"group", OP_GROUP
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"size", OP_SIZE
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inum", OP_INUM
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"atime", OP_ATIME
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ctime", OP_CTIME
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mtime", OP_MTIME
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"exec", OP_EXEC
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ok", OP_OK
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"print", OP_PRINT
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"print0", OP_PRINT0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"newer", OP_NEWER
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cnewer", OP_CNEWER
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"a", OP_AND
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"o", OP_OR
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"xdev", OP_XDEV
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"depth", OP_DEPTH
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"prune", OP_PRUNE
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"nouser", OP_NOUSER
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"nogroup", OP_NOGROUP
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0, 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
char **ipp; /* pointer to next argument during parsing */
|
|
||||||
char *prog; /* program name (== argv [0]) */
|
|
||||||
char *epath; /* value of PATH environment string */
|
|
||||||
long current_time; /* for computing age */
|
|
||||||
int tty; /* fd for /dev/tty when using -ok */
|
|
||||||
int xdev_flag = 0; /* cross device boundaries? */
|
|
||||||
int devnr; /* device nr of first inode */
|
|
||||||
int depth_flag = 0; /* descend before check? */
|
|
||||||
int prune_here; /* This is Baaaad! Don't ever do this again! */
|
|
||||||
int um; /* current umask() */
|
|
||||||
int needprint = 1; /* implicit -print needed? */
|
|
||||||
|
|
||||||
|
|
||||||
/* The prototypes: */
|
|
||||||
_PROTOTYPE(int main, (int argc, char **argv));
|
|
||||||
_PROTOTYPE(char *Malloc, (int n));
|
|
||||||
_PROTOTYPE(char *Salloc, (char *s));
|
|
||||||
_PROTOTYPE(void find, (char *path, struct node * pred, char *last));
|
|
||||||
_PROTOTYPE(int check, (char *path, struct stat * st, struct node * n, char *last));
|
|
||||||
_PROTOTYPE(int ichk, (long val, struct node * n));
|
|
||||||
_PROTOTYPE(int lex, (char *str));
|
|
||||||
_PROTOTYPE(struct node * newnode, (int t));
|
|
||||||
_PROTOTYPE(int isnumber, (char *str, int base, int sign));
|
|
||||||
_PROTOTYPE(void number, (char *str, int base, long *pl, int *ps));
|
|
||||||
_PROTOTYPE(void fmode, (char *str, long *pl, int *ps));
|
|
||||||
_PROTOTYPE(struct node * expr, (int t));
|
|
||||||
_PROTOTYPE(struct node * primary, (int t));
|
|
||||||
_PROTOTYPE(struct node * secondary, (int t));
|
|
||||||
_PROTOTYPE(void checkarg, (char *arg));
|
|
||||||
_PROTOTYPE(struct node * simple, (int t));
|
|
||||||
_PROTOTYPE(void nonfatal, (char *s1, char *s2));
|
|
||||||
_PROTOTYPE(void fatal, (char *s1, char *s2));
|
|
||||||
_PROTOTYPE(int smatch, (char *s, char *t));
|
|
||||||
_PROTOTYPE(char *find_bin, (char *s));
|
|
||||||
_PROTOTYPE(int execute, (int op, struct exec * e, char *path));
|
|
||||||
_PROTOTYPE(void domode, (int op, int *mode, int bits));
|
|
||||||
|
|
||||||
|
|
||||||
/* Malloc: a certified malloc */
|
|
||||||
char *Malloc(n)
|
|
||||||
int n;
|
|
||||||
{
|
|
||||||
char *m;
|
|
||||||
|
|
||||||
if ((m = (char *) malloc(n)) == (char *) NULL) fatal("out of memory", "");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Salloc: allocate space for a string */
|
|
||||||
char *Salloc(s)
|
|
||||||
char *s;
|
|
||||||
{
|
|
||||||
return strcpy(Malloc(strlen(s) + 1), s);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Main: the main body */
|
|
||||||
int main(argc, argv)
|
|
||||||
int argc;
|
|
||||||
char *argv[];
|
|
||||||
{
|
|
||||||
char **pathlist, *path, *last;
|
|
||||||
int pathcnt = 0, i;
|
|
||||||
struct node *pred;
|
|
||||||
|
|
||||||
prog = *argv++; /* set program name (for diagnostics) */
|
|
||||||
if ((epath = getenv("PATH")) == (char *) NULL)
|
|
||||||
fatal("Can't get path from environment", "");
|
|
||||||
(void) umask(um = umask(0)); /* non-destructive get-umask :-) */
|
|
||||||
time(¤t_time); /* get current time */
|
|
||||||
|
|
||||||
pathlist= argv;
|
|
||||||
while (--argc > 0 && lex(*argv) == NONE) { /* find paths */
|
|
||||||
pathcnt++;
|
|
||||||
argv++;
|
|
||||||
}
|
|
||||||
if (pathcnt == 0) /* there must be at least one path */
|
|
||||||
fatal("Usage: path-list [predicate-list]", "");
|
|
||||||
|
|
||||||
ipp = argv; /* prepare for parsing */
|
|
||||||
if (argc != 0) { /* If there is anything to parse, */
|
|
||||||
pred = expr(lex(*ipp)); /* then do so */
|
|
||||||
if (lex(*++ipp) != EOI) /* Make sure there's nothing left */
|
|
||||||
fatal("syntax error: garbage at end of predicate", "");
|
|
||||||
} else /* No predicate list */
|
|
||||||
pred = (struct node *) NULL;
|
|
||||||
|
|
||||||
for (i = 0; i < pathcnt; i++) {
|
|
||||||
if (xdev_flag) xdev_flag = 2;
|
|
||||||
path = pathlist[i];
|
|
||||||
if ((last = strrchr(path, '/')) == NULL) last = path; else last++;
|
|
||||||
find(path, pred, last);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void find(path, pred, last)
|
|
||||||
char *path, *last;
|
|
||||||
struct node *pred;
|
|
||||||
{
|
|
||||||
char spath[PATH_MAX];
|
|
||||||
register char *send = spath, *p;
|
|
||||||
struct stat st;
|
|
||||||
DIR *dp;
|
|
||||||
struct dirent *de;
|
|
||||||
|
|
||||||
if (path[1] == '\0' && *path == '/') {
|
|
||||||
*send++ = '/';
|
|
||||||
*send = '\0';
|
|
||||||
} else
|
|
||||||
while (*send++ = *path++) {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LSTAT(spath, &st) == -1)
|
|
||||||
nonfatal("can't get status of ", spath);
|
|
||||||
else {
|
|
||||||
switch (xdev_flag) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (st.st_dev != devnr) return;
|
|
||||||
break;
|
|
||||||
case 2: /* set current device number */
|
|
||||||
xdev_flag = 1;
|
|
||||||
devnr = st.st_dev;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
prune_here = 0;
|
|
||||||
if (!depth_flag && check(spath, &st, pred, last) && needprint)
|
|
||||||
printf("%s\n", spath);
|
|
||||||
if (!prune_here && (st.st_mode & S_IFMT) == S_IFDIR) {
|
|
||||||
if ((dp = opendir(spath)) == NULL) {
|
|
||||||
nonfatal("can't read directory ", spath);
|
|
||||||
perror( "Error" );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
send[-1] = '/';
|
|
||||||
while ((de = readdir(dp)) != NULL) {
|
|
||||||
p = de->d_name;
|
|
||||||
if ((de->d_name[0] != '.') || ((de->d_name[1])
|
|
||||||
&& ((de->d_name[1] != '.')
|
|
||||||
|| (de->d_name[2])))) {
|
|
||||||
strcpy(send, de->d_name);
|
|
||||||
find(spath, pred, send);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dp);
|
|
||||||
}
|
|
||||||
if (depth_flag) {
|
|
||||||
send[-1] = '\0';
|
|
||||||
if (check(spath, &st, pred, last) && needprint)
|
|
||||||
printf("%s\n", spath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int check(path, st, n, last)
|
|
||||||
char *path, *last;
|
|
||||||
register struct stat *st;
|
|
||||||
register struct node *n;
|
|
||||||
{
|
|
||||||
if (n == (struct node *) NULL) return 1;
|
|
||||||
switch (n->n_type) {
|
|
||||||
case OP_AND:
|
|
||||||
return check(path, st, n->n_info.n_opnd.n_left, last) &&
|
|
||||||
check(path, st, n->n_info.n_opnd.n_right, last);
|
|
||||||
case OP_OR:
|
|
||||||
return check(path, st, n->n_info.n_opnd.n_left, last) ||
|
|
||||||
check(path, st, n->n_info.n_opnd.n_right, last);
|
|
||||||
case NOT:
|
|
||||||
return !check(path, st, n->n_info.n_opnd.n_left, last);
|
|
||||||
case OP_NAME:
|
|
||||||
return smatch(last, n->n_info.n_str);
|
|
||||||
case OP_PERM:
|
|
||||||
if (n->n_info.n_int.n_sign < 0)
|
|
||||||
return(st->st_mode & (int) n->n_info.n_int.n_val) ==
|
|
||||||
(int) n->n_info.n_int.n_val;
|
|
||||||
return(st->st_mode & 07777) == (int) n->n_info.n_int.n_val;
|
|
||||||
case OP_NEWER:
|
|
||||||
return st->st_mtime > n->n_info.n_int.n_val;
|
|
||||||
case OP_CNEWER:
|
|
||||||
return st->st_ctime > n->n_info.n_int.n_val;
|
|
||||||
case OP_TYPE:
|
|
||||||
return(st->st_mode & S_IFMT) == (mode_t) n->n_info.n_int.n_val;
|
|
||||||
case OP_LINKS:
|
|
||||||
return ichk((long) (st->st_nlink), n);
|
|
||||||
case OP_USER:
|
|
||||||
return st->st_uid == n->n_info.n_int.n_val;
|
|
||||||
case OP_GROUP:
|
|
||||||
return st->st_gid == n->n_info.n_int.n_val;
|
|
||||||
case OP_SIZE:
|
|
||||||
return ichk((st->st_size == 0) ? 0L :
|
|
||||||
(long) ((st->st_size - 1) / BSIZE + 1), n);
|
|
||||||
case OP_SIZEC:
|
|
||||||
return ichk((long) st->st_size, n);
|
|
||||||
case OP_INUM:
|
|
||||||
return ichk((long) (st->st_ino), n);
|
|
||||||
case OP_ATIME:
|
|
||||||
return ichk(st->st_atime, n);
|
|
||||||
case OP_CTIME:
|
|
||||||
return ichk(st->st_ctime, n);
|
|
||||||
case OP_MTIME:
|
|
||||||
return ichk(st->st_mtime, n);
|
|
||||||
case OP_EXEC:
|
|
||||||
case OP_OK:
|
|
||||||
return execute(n->n_type, n->n_info.n_exec, path);
|
|
||||||
case OP_PRINT:
|
|
||||||
printf("%s\n", path);
|
|
||||||
return 1;
|
|
||||||
case OP_PRINT0:
|
|
||||||
printf("%s", path); putchar(0);
|
|
||||||
return 1;
|
|
||||||
case OP_XDEV:
|
|
||||||
case OP_DEPTH:
|
|
||||||
return 1;
|
|
||||||
case OP_PRUNE:
|
|
||||||
prune_here = 1;
|
|
||||||
return 1;
|
|
||||||
case OP_NOUSER:
|
|
||||||
return(getpwuid(st->st_uid) == (struct passwd *) NULL);
|
|
||||||
case OP_NOGROUP:
|
|
||||||
return(getgrgid(st->st_gid) == (struct group *) NULL);
|
|
||||||
}
|
|
||||||
fatal("ILLEGAL NODE", "");
|
|
||||||
return 0; /* Never reached */
|
|
||||||
}
|
|
||||||
|
|
||||||
int ichk(val, n)
|
|
||||||
long val;
|
|
||||||
struct node *n;
|
|
||||||
{
|
|
||||||
switch (n->n_info.n_int.n_sign) {
|
|
||||||
case 0:
|
|
||||||
return val == n->n_info.n_int.n_val;
|
|
||||||
case 1:
|
|
||||||
return val > n->n_info.n_int.n_val;
|
|
||||||
case -1: return val < n->n_info.n_int.n_val;
|
|
||||||
}
|
|
||||||
fatal("internal: bad n_sign", "");
|
|
||||||
return 0; /* Never reached */
|
|
||||||
}
|
|
||||||
|
|
||||||
int lex(str)
|
|
||||||
char *str;
|
|
||||||
{
|
|
||||||
if (str == (char *) NULL) return EOI;
|
|
||||||
if (*str == '-') {
|
|
||||||
register struct oper *op;
|
|
||||||
|
|
||||||
str++;
|
|
||||||
for (op = ops; op->op_str; op++)
|
|
||||||
if (strcmp(str, op->op_str) == 0) break;
|
|
||||||
return op->op_val;
|
|
||||||
}
|
|
||||||
if (str[1] == 0) {
|
|
||||||
switch (*str) {
|
|
||||||
case '(':
|
|
||||||
return LPAR;
|
|
||||||
case ')':
|
|
||||||
return RPAR;
|
|
||||||
case '!': return NOT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct node *
|
|
||||||
newnode(t)
|
|
||||||
int t;
|
|
||||||
{
|
|
||||||
struct node *n = (struct node *) Malloc(sizeof(struct node));
|
|
||||||
|
|
||||||
n->n_type = t;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*########################### PARSER ###################################*/
|
|
||||||
/* Grammar:
|
|
||||||
* expr : primary | primary OR expr;
|
|
||||||
* primary : secondary | secondary AND primary | secondary primary;
|
|
||||||
* secondary : NOT secondary | LPAR expr RPAR | simple;
|
|
||||||
* simple : -OP args...
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Isnumber checks correct number syntax. A sign is allowed, but the '+'
|
|
||||||
* only if the number is to be in decimal.
|
|
||||||
*/
|
|
||||||
int isnumber(str, base, sign)
|
|
||||||
register char *str;
|
|
||||||
int base;
|
|
||||||
int sign;
|
|
||||||
{
|
|
||||||
if (sign && ((*str == '-') || ((base == 8) && (*str == '+')))) str++;
|
|
||||||
while ((*str >= '0') && (*str < ('0' + base))) str++;
|
|
||||||
return(*str == '\0' ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert a string to an integer, storing sign info in *ps. */
|
|
||||||
void number(str, base, pl, ps)
|
|
||||||
char *str;
|
|
||||||
int base;
|
|
||||||
long *pl;
|
|
||||||
int *ps;
|
|
||||||
{
|
|
||||||
int up = '0' + base - 1;
|
|
||||||
long val = 0;
|
|
||||||
|
|
||||||
*ps = ((*str == '-' || *str == '+') ? ((*str++ == '-') ? -1 : 1) : 0);
|
|
||||||
while (*str >= '0' && *str <= up) val = base * val + *str++ - '0';
|
|
||||||
if (*str) fatal("syntax error: illegal numeric value", "");
|
|
||||||
*pl = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void domode(op, mode, bits)
|
|
||||||
int op;
|
|
||||||
int *mode;
|
|
||||||
int bits;
|
|
||||||
{
|
|
||||||
switch (op) {
|
|
||||||
case '-':
|
|
||||||
*mode &= ~bits;
|
|
||||||
break; /* clear bits */
|
|
||||||
case '=':
|
|
||||||
*mode |= bits;
|
|
||||||
break; /* set bits */
|
|
||||||
case '+':
|
|
||||||
*mode |= (bits & ~um); /* set, but take umask in account */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void fmode(str, pl, ps)
|
|
||||||
char *str;
|
|
||||||
long *pl;
|
|
||||||
int *ps;
|
|
||||||
{
|
|
||||||
int m = 0, w, op;
|
|
||||||
char *p = str;
|
|
||||||
|
|
||||||
if (*p == '-') {
|
|
||||||
*ps = -1;
|
|
||||||
p++;
|
|
||||||
} else
|
|
||||||
*ps = 0;
|
|
||||||
|
|
||||||
while (*p) {
|
|
||||||
w = 0;
|
|
||||||
if (ISOPER(*p))
|
|
||||||
w = MUSER | MGROUP | MOTHERS;
|
|
||||||
else if (!ISWHO(*p))
|
|
||||||
fatal("u, g, o, or a expected: ", p);
|
|
||||||
else {
|
|
||||||
while (ISWHO(*p)) {
|
|
||||||
switch (*p) {
|
|
||||||
case 'u':
|
|
||||||
w |= MUSER;
|
|
||||||
break;
|
|
||||||
case 'g':
|
|
||||||
w |= MGROUP;
|
|
||||||
break;
|
|
||||||
case 'o':
|
|
||||||
w |= MOTHERS;
|
|
||||||
break;
|
|
||||||
case 'a':
|
|
||||||
w = MUSER | MGROUP | MOTHERS;
|
|
||||||
}
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
if (!ISOPER(*p)) fatal("-, + or = expected: ", p);
|
|
||||||
}
|
|
||||||
op = *p++;
|
|
||||||
while (ISMODE(*p)) {
|
|
||||||
switch (*p) {
|
|
||||||
case 'r':
|
|
||||||
if (w & MUSER) domode(op, &m, S_IRUSR);
|
|
||||||
if (w & MGROUP) domode(op, &m, S_IRGRP);
|
|
||||||
if (w & MOTHERS) domode(op, &m, S_IROTH);
|
|
||||||
break;
|
|
||||||
case 'w':
|
|
||||||
if (w & MUSER) domode(op, &m, S_IWUSR);
|
|
||||||
if (w & MGROUP) domode(op, &m, S_IWGRP);
|
|
||||||
if (w & MOTHERS) domode(op, &m, S_IWOTH);
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
if (w & MUSER) domode(op, &m, S_IXUSR);
|
|
||||||
if (w & MGROUP) domode(op, &m, S_IXGRP);
|
|
||||||
if (w & MOTHERS) domode(op, &m, S_IXOTH);
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
if (w & MUSER) domode(op, &m, S_ISUID);
|
|
||||||
if (w & MGROUP) domode(op, &m, S_ISGID);
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
domode(op, &m, S_ISVTX);
|
|
||||||
}
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
if (*p) {
|
|
||||||
if (*p == ',')
|
|
||||||
p++;
|
|
||||||
else
|
|
||||||
fatal("garbage at end of mode string: ", p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*pl = m;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct node *
|
|
||||||
expr(t)
|
|
||||||
int t;
|
|
||||||
{
|
|
||||||
struct node *nd, *p, *nd2;
|
|
||||||
|
|
||||||
nd = primary(t);
|
|
||||||
if ((t = lex(*++ipp)) == OP_OR) {
|
|
||||||
nd2 = expr(lex(*++ipp));
|
|
||||||
p = newnode(OP_OR);
|
|
||||||
p->n_info.n_opnd.n_left = nd;
|
|
||||||
p->n_info.n_opnd.n_right = nd2;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
ipp--;
|
|
||||||
return nd;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct node *
|
|
||||||
primary(t)
|
|
||||||
int t;
|
|
||||||
{
|
|
||||||
struct node *nd, *p, *nd2;
|
|
||||||
|
|
||||||
nd = secondary(t);
|
|
||||||
if ((t = lex(*++ipp)) != OP_AND) {
|
|
||||||
ipp--;
|
|
||||||
if (t == EOI || t == RPAR || t == OP_OR) return nd;
|
|
||||||
}
|
|
||||||
nd2 = primary(lex(*++ipp));
|
|
||||||
p = newnode(OP_AND);
|
|
||||||
p->n_info.n_opnd.n_left = nd;
|
|
||||||
p->n_info.n_opnd.n_right = nd2;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct node *
|
|
||||||
secondary(t)
|
|
||||||
int t;
|
|
||||||
{
|
|
||||||
struct node *n, *p;
|
|
||||||
|
|
||||||
if (t == LPAR) {
|
|
||||||
n = expr(lex(*++ipp));
|
|
||||||
if (lex(*++ipp) != RPAR) fatal("syntax error, ) expected", "");
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
if (t == NOT) {
|
|
||||||
n = secondary(lex(*++ipp));
|
|
||||||
p = newnode(NOT);
|
|
||||||
p->n_info.n_opnd.n_left = n;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
return simple(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkarg(arg)
|
|
||||||
char *arg;
|
|
||||||
{
|
|
||||||
if (arg == 0) fatal("syntax error, argument expected", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct node *
|
|
||||||
simple(t)
|
|
||||||
int t;
|
|
||||||
{
|
|
||||||
struct node *p = newnode(t);
|
|
||||||
struct exec *e;
|
|
||||||
struct stat est;
|
|
||||||
struct passwd *pw;
|
|
||||||
struct group *gr;
|
|
||||||
long l;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
switch (t) {
|
|
||||||
case OP_TYPE:
|
|
||||||
checkarg(*++ipp);
|
|
||||||
switch (**ipp) {
|
|
||||||
case 'b':
|
|
||||||
p->n_info.n_int.n_val = S_IFBLK;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
p->n_info.n_int.n_val = S_IFCHR;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
p->n_info.n_int.n_val = S_IFDIR;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
p->n_info.n_int.n_val = S_IFREG;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
p->n_info.n_int.n_val = S_IFIFO;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
p->n_info.n_int.n_val = ~0;
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
#ifdef S_IFLNK
|
|
||||||
p->n_info.n_int.n_val = S_IFLNK;
|
|
||||||
#else
|
|
||||||
p->n_info.n_int.n_val = ~0; /* Always unequal. */
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fatal("-type needs b, c, d, f, p, s or l", "");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OP_USER:
|
|
||||||
checkarg(*++ipp);
|
|
||||||
if (((pw = getpwnam(*ipp)) == NULL)
|
|
||||||
&& isnumber(*ipp, 10, 0))
|
|
||||||
number(*ipp, 10, &(p->n_info.n_int.n_val),
|
|
||||||
&(p->n_info.n_int.n_sign));
|
|
||||||
else {
|
|
||||||
if (pw == NULL)
|
|
||||||
fatal("unknown user: ", *ipp);
|
|
||||||
p->n_info.n_int.n_val = pw->pw_uid;
|
|
||||||
p->n_info.n_int.n_sign = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OP_GROUP:
|
|
||||||
checkarg(*++ipp);
|
|
||||||
if (((gr = getgrnam(*ipp)) == NULL)
|
|
||||||
&& isnumber(*ipp, 10, 0))
|
|
||||||
number(*ipp, 10, &(p->n_info.n_int.n_val),
|
|
||||||
&(p->n_info.n_int.n_sign));
|
|
||||||
else {
|
|
||||||
if (gr == NULL)
|
|
||||||
fatal("unknown group: ", *ipp);
|
|
||||||
p->n_info.n_int.n_val = gr->gr_gid;
|
|
||||||
p->n_info.n_int.n_sign = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case OP_SIZE:
|
|
||||||
checkarg(*++ipp);
|
|
||||||
i = strlen(*ipp) - 1;
|
|
||||||
if ((*ipp)[i] == 'c') {
|
|
||||||
p->n_type = OP_SIZEC; /* Count in bytes i.s.o. blocks */
|
|
||||||
(*ipp)[i] = '\0';
|
|
||||||
}
|
|
||||||
number(*ipp, 10, &(p->n_info.n_int.n_val),
|
|
||||||
&(p->n_info.n_int.n_sign));
|
|
||||||
break;
|
|
||||||
case OP_LINKS:
|
|
||||||
case OP_INUM:
|
|
||||||
checkarg(*++ipp);
|
|
||||||
number(*ipp, 10, &(p->n_info.n_int.n_val),
|
|
||||||
&(p->n_info.n_int.n_sign));
|
|
||||||
break;
|
|
||||||
case OP_PERM:
|
|
||||||
checkarg(*++ipp);
|
|
||||||
if (isnumber(*ipp, 8, 1)) number(*ipp, 8, &(p->n_info.n_int.n_val),
|
|
||||||
&(p->n_info.n_int.n_sign));
|
|
||||||
else
|
|
||||||
fmode(*ipp, &(p->n_info.n_int.n_val),
|
|
||||||
&(p->n_info.n_int.n_sign));
|
|
||||||
break;
|
|
||||||
case OP_ATIME:
|
|
||||||
case OP_CTIME:
|
|
||||||
case OP_MTIME:
|
|
||||||
checkarg(*++ipp);
|
|
||||||
number(*ipp, 10, &l, &(p->n_info.n_int.n_sign));
|
|
||||||
p->n_info.n_int.n_val = current_time - l * SECS_PER_DAY;
|
|
||||||
/* More than n days old means less than the absolute time */
|
|
||||||
p->n_info.n_int.n_sign *= -1;
|
|
||||||
break;
|
|
||||||
case OP_EXEC:
|
|
||||||
case OP_OK:
|
|
||||||
checkarg(*++ipp);
|
|
||||||
e = (struct exec *) Malloc(sizeof(struct exec));
|
|
||||||
e->e_cnt = 2;
|
|
||||||
e->e_vec[0] = SHELL;
|
|
||||||
p->n_info.n_exec = e;
|
|
||||||
while (*ipp) {
|
|
||||||
if (**ipp == ';' && (*ipp)[1] == '\0') {
|
|
||||||
e->e_vec[e->e_cnt] = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
e->e_vec[(e->e_cnt)++] =
|
|
||||||
(**ipp == '{' && (*ipp)[1] == '}'
|
|
||||||
&& (*ipp)[2] == '\0') ? (char *) (-1) : *ipp;
|
|
||||||
ipp++;
|
|
||||||
}
|
|
||||||
if (*ipp == 0) fatal("-exec/-ok: ; missing", "");
|
|
||||||
if ((e->e_vec[1] = find_bin(e->e_vec[2])) == 0)
|
|
||||||
fatal("can't find program ", e->e_vec[2]);
|
|
||||||
if (t == OP_OK)
|
|
||||||
if ((tty = open("/dev/tty", O_RDWR)) < 0)
|
|
||||||
fatal("can't open /dev/tty", "");
|
|
||||||
break;
|
|
||||||
case OP_CNEWER:
|
|
||||||
case OP_NEWER:
|
|
||||||
checkarg(*++ipp);
|
|
||||||
if (LSTAT(*ipp, &est) == -1)
|
|
||||||
fatal("-newer: can't get status of ", *ipp);
|
|
||||||
p->n_info.n_int.n_val = est.st_mtime;
|
|
||||||
break;
|
|
||||||
case OP_NAME:
|
|
||||||
checkarg(*++ipp);
|
|
||||||
p->n_info.n_str = *ipp;
|
|
||||||
break;
|
|
||||||
case OP_XDEV: xdev_flag = 1; break;
|
|
||||||
case OP_DEPTH: depth_flag = 1; break;
|
|
||||||
case OP_PRUNE:
|
|
||||||
case OP_PRINT:
|
|
||||||
case OP_PRINT0:
|
|
||||||
case OP_NOUSER: case OP_NOGROUP: break;
|
|
||||||
default:
|
|
||||||
fatal("syntax error, operator expected", "");
|
|
||||||
}
|
|
||||||
if ((t == OP_PRINT) || (t == OP_PRINT0) || (t == OP_EXEC) || (t == OP_OK))
|
|
||||||
needprint = 0;
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*######################## DIAGNOSTICS ##############################*/
|
|
||||||
|
|
||||||
void nonfatal(s1, s2)
|
|
||||||
char *s1, *s2;
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s: %s%s\n", prog, s1, s2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fatal(s1, s2)
|
|
||||||
char *s1, *s2;
|
|
||||||
{
|
|
||||||
nonfatal(s1, s2);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*################### SMATCH #########################*/
|
|
||||||
/* Don't try to understand the following one... */
|
|
||||||
int smatch(s, t) /* shell-like matching */
|
|
||||||
char *s, *t;
|
|
||||||
{
|
|
||||||
register n;
|
|
||||||
|
|
||||||
if (*t == '\0') return *s == '\0';
|
|
||||||
if (*t == '*') {
|
|
||||||
++t;
|
|
||||||
do
|
|
||||||
if (smatch(s, t)) return 1;
|
|
||||||
while (*s++ != '\0');
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (*s == '\0') return 0;
|
|
||||||
if (*t == '\\') return (*s == *++t) ? smatch(++s, ++t) : 0;
|
|
||||||
if (*t == '?') return smatch(++s, ++t);
|
|
||||||
if (*t == '[') {
|
|
||||||
while (*++t != ']') {
|
|
||||||
if (*t == '\\') ++t;
|
|
||||||
if (*(t + 1) != '-')
|
|
||||||
if (*t == *s) {
|
|
||||||
while (*++t != ']')
|
|
||||||
if (*t == '\\') ++t;
|
|
||||||
return smatch(++s, ++t);
|
|
||||||
} else
|
|
||||||
continue;
|
|
||||||
if (*(t + 2) == ']') return(*s == *t || *s == '-');
|
|
||||||
n = (*(t + 2) == '\\') ? 3 : 2;
|
|
||||||
if (*s >= *t && *s <= *(t + n)) {
|
|
||||||
while (*++t != ']')
|
|
||||||
if (*t == '\\') ++t;
|
|
||||||
return smatch(++s, ++t);
|
|
||||||
}
|
|
||||||
t += n;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return(*s == *t) ? smatch(++s, ++t) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*####################### EXECUTE ###########################*/
|
|
||||||
/* Do -exec or -ok */
|
|
||||||
|
|
||||||
char *
|
|
||||||
find_bin(s)
|
|
||||||
char *s;
|
|
||||||
{
|
|
||||||
char *f, *l, buf[PATH_MAX];
|
|
||||||
|
|
||||||
if (*s == '/') /* absolute path name */
|
|
||||||
return(access(s, 1) == 0) ? s : 0;
|
|
||||||
l = f = epath;
|
|
||||||
for (;;) {
|
|
||||||
if (*l == ':' || *l == 0) {
|
|
||||||
if (l == f) {
|
|
||||||
if (access(s, 1) == 0) return Salloc(s);
|
|
||||||
f++;
|
|
||||||
} else {
|
|
||||||
register char *p = buf, *q = s;
|
|
||||||
|
|
||||||
while (f != l) *p++ = *f++;
|
|
||||||
f++;
|
|
||||||
*p++ = '/';
|
|
||||||
while (*p++ = *q++) {
|
|
||||||
}
|
|
||||||
if (access(buf, 1) == 0) return Salloc(buf);
|
|
||||||
}
|
|
||||||
if (*l == 0) break;
|
|
||||||
}
|
|
||||||
l++;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int execute(op, e, path)
|
|
||||||
int op;
|
|
||||||
struct exec *e;
|
|
||||||
char *path;
|
|
||||||
{
|
|
||||||
int s, pid;
|
|
||||||
char *argv[MAXARG];
|
|
||||||
register char **p, **q;
|
|
||||||
|
|
||||||
for (p = e->e_vec, q = argv; *p;) /* replace the {}s */
|
|
||||||
if ((*q++ = *p++) == (char *) -1) q[-1] = path;
|
|
||||||
*q = '\0';
|
|
||||||
if (op == OP_OK) {
|
|
||||||
char answer[10];
|
|
||||||
|
|
||||||
for (p = &argv[2]; *p; p++) {
|
|
||||||
write(tty, *p, strlen(*p));
|
|
||||||
write(tty, " ", 1);
|
|
||||||
}
|
|
||||||
write(tty, "? ", 2);
|
|
||||||
if (read(tty, answer, 10) < 2 || *answer != 'y') return 0;
|
|
||||||
}
|
|
||||||
if ((pid = fork()) == -1) fatal("can't fork", "");
|
|
||||||
if (pid == 0) {
|
|
||||||
register i = 3;
|
|
||||||
|
|
||||||
while (close(i++) == 0) {
|
|
||||||
} /* wow!!! */
|
|
||||||
execv(argv[1], &argv[2]); /* binary itself? */
|
|
||||||
execv(argv[0], &argv[1]); /* shell command? */
|
|
||||||
fatal("exec failure: ", argv[1]); /* none of them! */
|
|
||||||
exit(127);
|
|
||||||
}
|
|
||||||
return wait(&s) == pid && s == 0;
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
.TH FIND 1
|
|
||||||
.SH NAME
|
|
||||||
find \- find files meeting a given condition
|
|
||||||
.SH SYNOPSIS
|
|
||||||
\fBfind \fIdirectory \fIexpression\fR
|
|
||||||
.br
|
|
||||||
.de FL
|
|
||||||
.TP
|
|
||||||
\\fB\\$1\\fR
|
|
||||||
\\$2
|
|
||||||
..
|
|
||||||
.de EX
|
|
||||||
.TP 20
|
|
||||||
\\fB\\$1\\fR
|
|
||||||
# \\$2
|
|
||||||
..
|
|
||||||
.SH EXAMPLES
|
|
||||||
.EX "find / \-name a.out \-print" "Print all \fIa.out\fR paths"
|
|
||||||
.EX "find /usr/ast ! \-newer f \-ok rm {} \e;" "Ask before removing"
|
|
||||||
.EX "find /usr \-size +20 \-exec mv {} /big \e^;" "move files > 10k"
|
|
||||||
.EX "find / \e( \-name a.out \-o \-name \(fm*.o\(fm \e) \-exec rm {} \e;" "2 conds"
|
|
||||||
.SH DESCRIPTION
|
|
||||||
.PP
|
|
||||||
\fIFind\fR descends the file tree starting at the given directory checking
|
|
||||||
each file in that directory and its subdirectories against a predicate.
|
|
||||||
If the predicate is true, an action is taken. The predicates may be
|
|
||||||
connected by \fB\-a\fR (Boolean and), \fB\-o\fR (Boolean or) and !
|
|
||||||
(Boolean negation).
|
|
||||||
Each predicate is true under the conditions specified below. The integer
|
|
||||||
\fIn\fR may also be +\fIn\fR to mean any value greater than \fIn\fR,
|
|
||||||
\fI\-n\fR to mean any value less than
|
|
||||||
\fIn\fR, or just \fIn\fR for exactly \fIn\fR.
|
|
||||||
.PP
|
|
||||||
.RS
|
|
||||||
.ta +\w'\-mtime nmm'u
|
|
||||||
.in +\w'\-mtime nmm'u
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-name s true if current filename is \fIs\fR (include shell wild cards)
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-size n true if file size is \fIn\fR blocks
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-inum n true if the current file's i-node number is \fIn\fR
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-mtime n true if modification time relative to today (in days) is \fIn\fR
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-links n true if the number of links to the file is \fIn\fR
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-newer f true if the file is newer than \fIf\fR
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-perm n true if the file's permission bits = \fIn\fR (\fIn\fR is in octal)
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-user u true if the uid = \fIu\fR (a numerical value, not a login name)
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-group g true if the gid = \fIg\fR (a numerical value, not a group name)
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-type x where \fIx\fR is \fBbcdfug\fR (block, char, dir, regular file, setuid, setgid)
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-xdev do not cross devices to search mounted file systems
|
|
||||||
.in -\w'\-mtime nmm'u
|
|
||||||
.fi
|
|
||||||
.RE
|
|
||||||
.PP
|
|
||||||
Following the expression can be one of the following, telling what to do
|
|
||||||
when a file is found:
|
|
||||||
.PP
|
|
||||||
.RS
|
|
||||||
.ta +\w'\-mtime nmm'u
|
|
||||||
.in +\w'\-mtime nmm'u
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-print print the file name on standard output
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-print0 print the file name terminated by a null character, to be
|
|
||||||
used with
|
|
||||||
.BR "xargs \-0" .
|
|
||||||
(MINIX 3 extension).
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-exec execute a command, {} stands for the file name
|
|
||||||
.ti -\w'\-mtime nmm'u
|
|
||||||
\-ok prompts before executing the command
|
|
||||||
.in -\w'\-mtime nmm'u
|
|
||||||
.RE
|
|
||||||
.SH "SEE ALSO"
|
|
||||||
.BR test (1),
|
|
||||||
.BR xargs (1).
|
|
Loading…
Reference in a new issue