[9] | 1 | /* find - look for files satisfying a predicate Author: E. Baalbergen */
|
---|
| 2 |
|
---|
| 3 | /* Original author: Erik Baalbergen; POSIX compliant version: Bert Laverman */
|
---|
| 4 |
|
---|
| 5 | #include <sys/types.h>
|
---|
| 6 | #include <sys/stat.h>
|
---|
| 7 | #include <sys/wait.h>
|
---|
| 8 | #include <fcntl.h>
|
---|
| 9 | #include <stdlib.h>
|
---|
| 10 | #include <string.h>
|
---|
| 11 | #include <unistd.h>
|
---|
| 12 | #include <time.h>
|
---|
| 13 | #include <pwd.h>
|
---|
| 14 | #include <grp.h>
|
---|
| 15 | #include <dirent.h>
|
---|
| 16 | #include <limits.h>
|
---|
| 17 | #include <stdio.h>
|
---|
| 18 |
|
---|
| 19 | /*######################## DEFINITIONS ##############################*/
|
---|
| 20 |
|
---|
| 21 | #ifdef S_IFLNK
|
---|
| 22 | #define LSTAT lstat
|
---|
| 23 | #else
|
---|
| 24 | #define LSTAT stat
|
---|
| 25 | #endif
|
---|
| 26 |
|
---|
| 27 | #define SHELL "/bin/sh"
|
---|
| 28 | #define MAXARG 256 /* maximum length for an argv for -exec */
|
---|
| 29 | #define BSIZE 512 /* POSIX wants 512 byte blocks */
|
---|
| 30 | #define SECS_PER_DAY (24L*60L*60L) /* check your planet */
|
---|
| 31 |
|
---|
| 32 | #define OP_NAME 1 /* match name */
|
---|
| 33 | #define OP_PERM 2 /* check file permission bits */
|
---|
| 34 | #define OP_TYPE 3 /* check file type bits */
|
---|
| 35 | #define OP_LINKS 4 /* check link count */
|
---|
| 36 | #define OP_USER 5 /* check owner */
|
---|
| 37 | #define OP_GROUP 6 /* check group ownership */
|
---|
| 38 | #define OP_SIZE 7 /* check size, blocks or bytes */
|
---|
| 39 | #define OP_SIZEC 8 /* this is a fake for -size with 'c' */
|
---|
| 40 | #define OP_INUM 9 /* compare inode number */
|
---|
| 41 | #define OP_ATIME 10 /* check last access time */
|
---|
| 42 | #define OP_CTIME 11 /* check creation time */
|
---|
| 43 | #define OP_MTIME 12 /* check last modification time */
|
---|
| 44 | #define OP_EXEC 13 /* execute command */
|
---|
| 45 | #define OP_OK 14 /* execute with confirmation */
|
---|
| 46 | #define OP_PRINT 15 /* print name */
|
---|
| 47 | #define OP_PRINT0 16 /* print name null terminated */
|
---|
| 48 | #define OP_NEWER 17 /* compare modification times */
|
---|
| 49 | #define OP_CNEWER 18 /* compare modification times */
|
---|
| 50 | #define OP_AND 19 /* logical and (short circuit) */
|
---|
| 51 | #define OP_OR 20 /* logical or (short circuit) */
|
---|
| 52 | #define OP_XDEV 21 /* do not cross file-system boundaries */
|
---|
| 53 | #define OP_DEPTH 22 /* descend directory before testing */
|
---|
| 54 | #define OP_PRUNE 23 /* don't descend into current directory */
|
---|
| 55 | #define OP_NOUSER 24 /* check validity of user id */
|
---|
| 56 | #define OP_NOGROUP 25 /* check validity of group id */
|
---|
| 57 | #define LPAR 26 /* left parenthesis */
|
---|
| 58 | #define RPAR 27 /* right parenthesis */
|
---|
| 59 | #define NOT 28 /* logical not */
|
---|
| 60 |
|
---|
| 61 | /* Some return values: */
|
---|
| 62 | #define EOI -1 /* end of expression */
|
---|
| 63 | #define NONE 0 /* not a valid predicate */
|
---|
| 64 |
|
---|
| 65 | /* For -perm with symbolic modes: */
|
---|
| 66 | #define ISWHO(c) ((c == 'u') || (c == 'g') || (c == 'o') || (c == 'a'))
|
---|
| 67 | #define ISOPER(c) ((c == '-') || (c == '=') || (c == '+'))
|
---|
| 68 | #define ISMODE(c) ((c == 'r') || (c == 'w') || (c == 'x') || \
|
---|
| 69 | (c == 's') || (c == 't'))
|
---|
| 70 | #define MUSER 1
|
---|
| 71 | #define MGROUP 2
|
---|
| 72 | #define MOTHERS 4
|
---|
| 73 |
|
---|
| 74 |
|
---|
| 75 | struct exec {
|
---|
| 76 | int e_cnt;
|
---|
| 77 | char *e_vec[MAXARG];
|
---|
| 78 | };
|
---|
| 79 |
|
---|
| 80 | struct node {
|
---|
| 81 | int n_type; /* any OP_ or NOT */
|
---|
| 82 | union {
|
---|
| 83 | char *n_str;
|
---|
| 84 | struct {
|
---|
| 85 | long n_val;
|
---|
| 86 | int n_sign;
|
---|
| 87 | } n_int;
|
---|
| 88 | struct exec *n_exec;
|
---|
| 89 | struct {
|
---|
| 90 | struct node *n_left, *n_right;
|
---|
| 91 | } n_opnd;
|
---|
| 92 | } n_info;
|
---|
| 93 | };
|
---|
| 94 |
|
---|
| 95 | struct oper {
|
---|
| 96 | char *op_str;
|
---|
| 97 | int op_val;
|
---|
| 98 | } ops[] = {
|
---|
| 99 |
|
---|
| 100 | {
|
---|
| 101 | "name", OP_NAME
|
---|
| 102 | },
|
---|
| 103 | {
|
---|
| 104 | "perm", OP_PERM
|
---|
| 105 | },
|
---|
| 106 | {
|
---|
| 107 | "type", OP_TYPE
|
---|
| 108 | },
|
---|
| 109 | {
|
---|
| 110 | "links", OP_LINKS
|
---|
| 111 | },
|
---|
| 112 | {
|
---|
| 113 | "user", OP_USER
|
---|
| 114 | },
|
---|
| 115 | {
|
---|
| 116 | "group", OP_GROUP
|
---|
| 117 | },
|
---|
| 118 | {
|
---|
| 119 | "size", OP_SIZE
|
---|
| 120 | },
|
---|
| 121 | {
|
---|
| 122 | "inum", OP_INUM
|
---|
| 123 | },
|
---|
| 124 | {
|
---|
| 125 | "atime", OP_ATIME
|
---|
| 126 | },
|
---|
| 127 | {
|
---|
| 128 | "ctime", OP_CTIME
|
---|
| 129 | },
|
---|
| 130 | {
|
---|
| 131 | "mtime", OP_MTIME
|
---|
| 132 | },
|
---|
| 133 | {
|
---|
| 134 | "exec", OP_EXEC
|
---|
| 135 | },
|
---|
| 136 | {
|
---|
| 137 | "ok", OP_OK
|
---|
| 138 | },
|
---|
| 139 | {
|
---|
| 140 | "print", OP_PRINT
|
---|
| 141 | },
|
---|
| 142 | {
|
---|
| 143 | "print0", OP_PRINT0
|
---|
| 144 | },
|
---|
| 145 | {
|
---|
| 146 | "newer", OP_NEWER
|
---|
| 147 | },
|
---|
| 148 | {
|
---|
| 149 | "cnewer", OP_CNEWER
|
---|
| 150 | },
|
---|
| 151 | {
|
---|
| 152 | "a", OP_AND
|
---|
| 153 | },
|
---|
| 154 | {
|
---|
| 155 | "o", OP_OR
|
---|
| 156 | },
|
---|
| 157 | {
|
---|
| 158 | "xdev", OP_XDEV
|
---|
| 159 | },
|
---|
| 160 | {
|
---|
| 161 | "depth", OP_DEPTH
|
---|
| 162 | },
|
---|
| 163 | {
|
---|
| 164 | "prune", OP_PRUNE
|
---|
| 165 | },
|
---|
| 166 | {
|
---|
| 167 | "nouser", OP_NOUSER
|
---|
| 168 | },
|
---|
| 169 | {
|
---|
| 170 | "nogroup", OP_NOGROUP
|
---|
| 171 | },
|
---|
| 172 | {
|
---|
| 173 | 0, 0
|
---|
| 174 | }
|
---|
| 175 | };
|
---|
| 176 |
|
---|
| 177 |
|
---|
| 178 | char **ipp; /* pointer to next argument during parsing */
|
---|
| 179 | char *prog; /* program name (== argv [0]) */
|
---|
| 180 | char *epath; /* value of PATH environment string */
|
---|
| 181 | long current_time; /* for computing age */
|
---|
| 182 | int tty; /* fd for /dev/tty when using -ok */
|
---|
| 183 | int xdev_flag = 0; /* cross device boundaries? */
|
---|
| 184 | int devnr; /* device nr of first inode */
|
---|
| 185 | int depth_flag = 0; /* descend before check? */
|
---|
| 186 | int prune_here; /* This is Baaaad! Don't ever do this again! */
|
---|
| 187 | int um; /* current umask() */
|
---|
| 188 | int needprint = 1; /* implicit -print needed? */
|
---|
| 189 |
|
---|
| 190 |
|
---|
| 191 | /* The prototypes: */
|
---|
| 192 | _PROTOTYPE(int main, (int argc, char **argv));
|
---|
| 193 | _PROTOTYPE(char *Malloc, (int n));
|
---|
| 194 | _PROTOTYPE(char *Salloc, (char *s));
|
---|
| 195 | _PROTOTYPE(void find, (char *path, struct node * pred, char *last));
|
---|
| 196 | _PROTOTYPE(int check, (char *path, struct stat * st, struct node * n, char *last));
|
---|
| 197 | _PROTOTYPE(int ichk, (long val, struct node * n));
|
---|
| 198 | _PROTOTYPE(int lex, (char *str));
|
---|
| 199 | _PROTOTYPE(struct node * newnode, (int t));
|
---|
| 200 | _PROTOTYPE(int isnumber, (char *str, int base, int sign));
|
---|
| 201 | _PROTOTYPE(void number, (char *str, int base, long *pl, int *ps));
|
---|
| 202 | _PROTOTYPE(void fmode, (char *str, long *pl, int *ps));
|
---|
| 203 | _PROTOTYPE(struct node * expr, (int t));
|
---|
| 204 | _PROTOTYPE(struct node * primary, (int t));
|
---|
| 205 | _PROTOTYPE(struct node * secondary, (int t));
|
---|
| 206 | _PROTOTYPE(void checkarg, (char *arg));
|
---|
| 207 | _PROTOTYPE(struct node * simple, (int t));
|
---|
| 208 | _PROTOTYPE(void nonfatal, (char *s1, char *s2));
|
---|
| 209 | _PROTOTYPE(void fatal, (char *s1, char *s2));
|
---|
| 210 | _PROTOTYPE(int smatch, (char *s, char *t));
|
---|
| 211 | _PROTOTYPE(char *find_bin, (char *s));
|
---|
| 212 | _PROTOTYPE(int execute, (int op, struct exec * e, char *path));
|
---|
| 213 | _PROTOTYPE(void domode, (int op, int *mode, int bits));
|
---|
| 214 |
|
---|
| 215 |
|
---|
| 216 | /* Malloc: a certified malloc */
|
---|
| 217 | char *Malloc(n)
|
---|
| 218 | int n;
|
---|
| 219 | {
|
---|
| 220 | char *m;
|
---|
| 221 |
|
---|
| 222 | if ((m = (char *) malloc(n)) == (char *) NULL) fatal("out of memory", "");
|
---|
| 223 | return m;
|
---|
| 224 | }
|
---|
| 225 |
|
---|
| 226 | /* Salloc: allocate space for a string */
|
---|
| 227 | char *Salloc(s)
|
---|
| 228 | char *s;
|
---|
| 229 | {
|
---|
| 230 | return strcpy(Malloc(strlen(s) + 1), s);
|
---|
| 231 | }
|
---|
| 232 |
|
---|
| 233 |
|
---|
| 234 | /* Main: the main body */
|
---|
| 235 | int main(argc, argv)
|
---|
| 236 | int argc;
|
---|
| 237 | char *argv[];
|
---|
| 238 | {
|
---|
| 239 | char **pathlist, *path, *last;
|
---|
| 240 | int pathcnt = 0, i;
|
---|
| 241 | struct node *pred;
|
---|
| 242 |
|
---|
| 243 | prog = *argv++; /* set program name (for diagnostics) */
|
---|
| 244 | if ((epath = getenv("PATH")) == (char *) NULL)
|
---|
| 245 | fatal("Can't get path from environment", "");
|
---|
| 246 | (void) umask(um = umask(0)); /* non-destructive get-umask :-) */
|
---|
| 247 | time(¤t_time); /* get current time */
|
---|
| 248 |
|
---|
| 249 | pathlist= argv;
|
---|
| 250 | while (--argc > 0 && lex(*argv) == NONE) { /* find paths */
|
---|
| 251 | pathcnt++;
|
---|
| 252 | argv++;
|
---|
| 253 | }
|
---|
| 254 | if (pathcnt == 0) /* there must be at least one path */
|
---|
| 255 | fatal("Usage: path-list [predicate-list]", "");
|
---|
| 256 |
|
---|
| 257 | ipp = argv; /* prepare for parsing */
|
---|
| 258 | if (argc != 0) { /* If there is anything to parse, */
|
---|
| 259 | pred = expr(lex(*ipp)); /* then do so */
|
---|
| 260 | if (lex(*++ipp) != EOI) /* Make sure there's nothing left */
|
---|
| 261 | fatal("syntax error: garbage at end of predicate", "");
|
---|
| 262 | } else /* No predicate list */
|
---|
| 263 | pred = (struct node *) NULL;
|
---|
| 264 |
|
---|
| 265 | for (i = 0; i < pathcnt; i++) {
|
---|
| 266 | if (xdev_flag) xdev_flag = 2;
|
---|
| 267 | path = pathlist[i];
|
---|
| 268 | if ((last = strrchr(path, '/')) == NULL) last = path; else last++;
|
---|
| 269 | find(path, pred, last);
|
---|
| 270 | }
|
---|
| 271 | return 0;
|
---|
| 272 | }
|
---|
| 273 |
|
---|
| 274 | void find(path, pred, last)
|
---|
| 275 | char *path, *last;
|
---|
| 276 | struct node *pred;
|
---|
| 277 | {
|
---|
| 278 | char spath[PATH_MAX];
|
---|
| 279 | register char *send = spath, *p;
|
---|
| 280 | struct stat st;
|
---|
| 281 | DIR *dp;
|
---|
| 282 | struct dirent *de;
|
---|
| 283 |
|
---|
| 284 | if (path[1] == '\0' && *path == '/') {
|
---|
| 285 | *send++ = '/';
|
---|
| 286 | *send = '\0';
|
---|
| 287 | } else
|
---|
| 288 | while (*send++ = *path++) {
|
---|
| 289 | }
|
---|
| 290 |
|
---|
| 291 | if (LSTAT(spath, &st) == -1)
|
---|
| 292 | nonfatal("can't get status of ", spath);
|
---|
| 293 | else {
|
---|
| 294 | switch (xdev_flag) {
|
---|
| 295 | case 0:
|
---|
| 296 | break;
|
---|
| 297 | case 1:
|
---|
| 298 | if (st.st_dev != devnr) return;
|
---|
| 299 | break;
|
---|
| 300 | case 2: /* set current device number */
|
---|
| 301 | xdev_flag = 1;
|
---|
| 302 | devnr = st.st_dev;
|
---|
| 303 | break;
|
---|
| 304 | }
|
---|
| 305 |
|
---|
| 306 | prune_here = 0;
|
---|
| 307 | if (!depth_flag && check(spath, &st, pred, last) && needprint)
|
---|
| 308 | printf("%s\n", spath);
|
---|
| 309 | if (!prune_here && (st.st_mode & S_IFMT) == S_IFDIR) {
|
---|
| 310 | if ((dp = opendir(spath)) == NULL) {
|
---|
| 311 | nonfatal("can't read directory ", spath);
|
---|
| 312 | perror( "Error" );
|
---|
| 313 | return;
|
---|
| 314 | }
|
---|
| 315 | send[-1] = '/';
|
---|
| 316 | while ((de = readdir(dp)) != NULL) {
|
---|
| 317 | p = de->d_name;
|
---|
| 318 | if ((de->d_name[0] != '.') || ((de->d_name[1])
|
---|
| 319 | && ((de->d_name[1] != '.')
|
---|
| 320 | || (de->d_name[2])))) {
|
---|
| 321 | strcpy(send, de->d_name);
|
---|
| 322 | find(spath, pred, send);
|
---|
| 323 | }
|
---|
| 324 | }
|
---|
| 325 | closedir(dp);
|
---|
| 326 | }
|
---|
| 327 | if (depth_flag) {
|
---|
| 328 | send[-1] = '\0';
|
---|
| 329 | if (check(spath, &st, pred, last) && needprint)
|
---|
| 330 | printf("%s\n", spath);
|
---|
| 331 | }
|
---|
| 332 | }
|
---|
| 333 | }
|
---|
| 334 |
|
---|
| 335 | int check(path, st, n, last)
|
---|
| 336 | char *path, *last;
|
---|
| 337 | register struct stat *st;
|
---|
| 338 | register struct node *n;
|
---|
| 339 | {
|
---|
| 340 | if (n == (struct node *) NULL) return 1;
|
---|
| 341 | switch (n->n_type) {
|
---|
| 342 | case OP_AND:
|
---|
| 343 | return check(path, st, n->n_info.n_opnd.n_left, last) &&
|
---|
| 344 | check(path, st, n->n_info.n_opnd.n_right, last);
|
---|
| 345 | case OP_OR:
|
---|
| 346 | return check(path, st, n->n_info.n_opnd.n_left, last) ||
|
---|
| 347 | check(path, st, n->n_info.n_opnd.n_right, last);
|
---|
| 348 | case NOT:
|
---|
| 349 | return !check(path, st, n->n_info.n_opnd.n_left, last);
|
---|
| 350 | case OP_NAME:
|
---|
| 351 | return smatch(last, n->n_info.n_str);
|
---|
| 352 | case OP_PERM:
|
---|
| 353 | if (n->n_info.n_int.n_sign < 0)
|
---|
| 354 | return(st->st_mode & (int) n->n_info.n_int.n_val) ==
|
---|
| 355 | (int) n->n_info.n_int.n_val;
|
---|
| 356 | return(st->st_mode & 07777) == (int) n->n_info.n_int.n_val;
|
---|
| 357 | case OP_NEWER:
|
---|
| 358 | return st->st_mtime > n->n_info.n_int.n_val;
|
---|
| 359 | case OP_CNEWER:
|
---|
| 360 | return st->st_ctime > n->n_info.n_int.n_val;
|
---|
| 361 | case OP_TYPE:
|
---|
| 362 | return(st->st_mode & S_IFMT) == (mode_t) n->n_info.n_int.n_val;
|
---|
| 363 | case OP_LINKS:
|
---|
| 364 | return ichk((long) (st->st_nlink), n);
|
---|
| 365 | case OP_USER:
|
---|
| 366 | return st->st_uid == n->n_info.n_int.n_val;
|
---|
| 367 | case OP_GROUP:
|
---|
| 368 | return st->st_gid == n->n_info.n_int.n_val;
|
---|
| 369 | case OP_SIZE:
|
---|
| 370 | return ichk((st->st_size == 0) ? 0L :
|
---|
| 371 | (long) ((st->st_size - 1) / BSIZE + 1), n);
|
---|
| 372 | case OP_SIZEC:
|
---|
| 373 | return ichk((long) st->st_size, n);
|
---|
| 374 | case OP_INUM:
|
---|
| 375 | return ichk((long) (st->st_ino), n);
|
---|
| 376 | case OP_ATIME:
|
---|
| 377 | return ichk(st->st_atime, n);
|
---|
| 378 | case OP_CTIME:
|
---|
| 379 | return ichk(st->st_ctime, n);
|
---|
| 380 | case OP_MTIME:
|
---|
| 381 | return ichk(st->st_mtime, n);
|
---|
| 382 | case OP_EXEC:
|
---|
| 383 | case OP_OK:
|
---|
| 384 | return execute(n->n_type, n->n_info.n_exec, path);
|
---|
| 385 | case OP_PRINT:
|
---|
| 386 | printf("%s\n", path);
|
---|
| 387 | return 1;
|
---|
| 388 | case OP_PRINT0:
|
---|
| 389 | printf("%s", path); putchar(0);
|
---|
| 390 | return 1;
|
---|
| 391 | case OP_XDEV:
|
---|
| 392 | case OP_DEPTH:
|
---|
| 393 | return 1;
|
---|
| 394 | case OP_PRUNE:
|
---|
| 395 | prune_here = 1;
|
---|
| 396 | return 1;
|
---|
| 397 | case OP_NOUSER:
|
---|
| 398 | return(getpwuid(st->st_uid) == (struct passwd *) NULL);
|
---|
| 399 | case OP_NOGROUP:
|
---|
| 400 | return(getgrgid(st->st_gid) == (struct group *) NULL);
|
---|
| 401 | }
|
---|
| 402 | fatal("ILLEGAL NODE", "");
|
---|
| 403 | return 0; /* Never reached */
|
---|
| 404 | }
|
---|
| 405 |
|
---|
| 406 | int ichk(val, n)
|
---|
| 407 | long val;
|
---|
| 408 | struct node *n;
|
---|
| 409 | {
|
---|
| 410 | switch (n->n_info.n_int.n_sign) {
|
---|
| 411 | case 0:
|
---|
| 412 | return val == n->n_info.n_int.n_val;
|
---|
| 413 | case 1:
|
---|
| 414 | return val > n->n_info.n_int.n_val;
|
---|
| 415 | case -1: return val < n->n_info.n_int.n_val;
|
---|
| 416 | }
|
---|
| 417 | fatal("internal: bad n_sign", "");
|
---|
| 418 | return 0; /* Never reached */
|
---|
| 419 | }
|
---|
| 420 |
|
---|
| 421 | int lex(str)
|
---|
| 422 | char *str;
|
---|
| 423 | {
|
---|
| 424 | if (str == (char *) NULL) return EOI;
|
---|
| 425 | if (*str == '-') {
|
---|
| 426 | register struct oper *op;
|
---|
| 427 |
|
---|
| 428 | str++;
|
---|
| 429 | for (op = ops; op->op_str; op++)
|
---|
| 430 | if (strcmp(str, op->op_str) == 0) break;
|
---|
| 431 | return op->op_val;
|
---|
| 432 | }
|
---|
| 433 | if (str[1] == 0) {
|
---|
| 434 | switch (*str) {
|
---|
| 435 | case '(':
|
---|
| 436 | return LPAR;
|
---|
| 437 | case ')':
|
---|
| 438 | return RPAR;
|
---|
| 439 | case '!': return NOT;
|
---|
| 440 | }
|
---|
| 441 | }
|
---|
| 442 | return NONE;
|
---|
| 443 | }
|
---|
| 444 |
|
---|
| 445 | struct node *
|
---|
| 446 | newnode(t)
|
---|
| 447 | int t;
|
---|
| 448 | {
|
---|
| 449 | struct node *n = (struct node *) Malloc(sizeof(struct node));
|
---|
| 450 |
|
---|
| 451 | n->n_type = t;
|
---|
| 452 | return n;
|
---|
| 453 | }
|
---|
| 454 |
|
---|
| 455 | /*########################### PARSER ###################################*/
|
---|
| 456 | /* Grammar:
|
---|
| 457 | * expr : primary | primary OR expr;
|
---|
| 458 | * primary : secondary | secondary AND primary | secondary primary;
|
---|
| 459 | * secondary : NOT secondary | LPAR expr RPAR | simple;
|
---|
| 460 | * simple : -OP args...
|
---|
| 461 | */
|
---|
| 462 |
|
---|
| 463 | /* Isnumber checks correct number syntax. A sign is allowed, but the '+'
|
---|
| 464 | * only if the number is to be in decimal.
|
---|
| 465 | */
|
---|
| 466 | int isnumber(str, base, sign)
|
---|
| 467 | register char *str;
|
---|
| 468 | int base;
|
---|
| 469 | int sign;
|
---|
| 470 | {
|
---|
| 471 | if (sign && ((*str == '-') || ((base == 8) && (*str == '+')))) str++;
|
---|
| 472 | while ((*str >= '0') && (*str < ('0' + base))) str++;
|
---|
| 473 | return(*str == '\0' ? 1 : 0);
|
---|
| 474 | }
|
---|
| 475 |
|
---|
| 476 | /* Convert a string to an integer, storing sign info in *ps. */
|
---|
| 477 | void number(str, base, pl, ps)
|
---|
| 478 | char *str;
|
---|
| 479 | int base;
|
---|
| 480 | long *pl;
|
---|
| 481 | int *ps;
|
---|
| 482 | {
|
---|
| 483 | int up = '0' + base - 1;
|
---|
| 484 | long val = 0;
|
---|
| 485 |
|
---|
| 486 | *ps = ((*str == '-' || *str == '+') ? ((*str++ == '-') ? -1 : 1) : 0);
|
---|
| 487 | while (*str >= '0' && *str <= up) val = base * val + *str++ - '0';
|
---|
| 488 | if (*str) fatal("syntax error: illegal numeric value", "");
|
---|
| 489 | *pl = val;
|
---|
| 490 | }
|
---|
| 491 |
|
---|
| 492 |
|
---|
| 493 | void domode(op, mode, bits)
|
---|
| 494 | int op;
|
---|
| 495 | int *mode;
|
---|
| 496 | int bits;
|
---|
| 497 | {
|
---|
| 498 | switch (op) {
|
---|
| 499 | case '-':
|
---|
| 500 | *mode &= ~bits;
|
---|
| 501 | break; /* clear bits */
|
---|
| 502 | case '=':
|
---|
| 503 | *mode |= bits;
|
---|
| 504 | break; /* set bits */
|
---|
| 505 | case '+':
|
---|
| 506 | *mode |= (bits & ~um); /* set, but take umask in account */
|
---|
| 507 | }
|
---|
| 508 | }
|
---|
| 509 |
|
---|
| 510 | void fmode(str, pl, ps)
|
---|
| 511 | char *str;
|
---|
| 512 | long *pl;
|
---|
| 513 | int *ps;
|
---|
| 514 | {
|
---|
| 515 | int m = 0, w, op;
|
---|
| 516 | char *p = str;
|
---|
| 517 |
|
---|
| 518 | if (*p == '-') {
|
---|
| 519 | *ps = -1;
|
---|
| 520 | p++;
|
---|
| 521 | } else
|
---|
| 522 | *ps = 0;
|
---|
| 523 |
|
---|
| 524 | while (*p) {
|
---|
| 525 | w = 0;
|
---|
| 526 | if (ISOPER(*p))
|
---|
| 527 | w = MUSER | MGROUP | MOTHERS;
|
---|
| 528 | else if (!ISWHO(*p))
|
---|
| 529 | fatal("u, g, o, or a expected: ", p);
|
---|
| 530 | else {
|
---|
| 531 | while (ISWHO(*p)) {
|
---|
| 532 | switch (*p) {
|
---|
| 533 | case 'u':
|
---|
| 534 | w |= MUSER;
|
---|
| 535 | break;
|
---|
| 536 | case 'g':
|
---|
| 537 | w |= MGROUP;
|
---|
| 538 | break;
|
---|
| 539 | case 'o':
|
---|
| 540 | w |= MOTHERS;
|
---|
| 541 | break;
|
---|
| 542 | case 'a':
|
---|
| 543 | w = MUSER | MGROUP | MOTHERS;
|
---|
| 544 | }
|
---|
| 545 | p++;
|
---|
| 546 | }
|
---|
| 547 | if (!ISOPER(*p)) fatal("-, + or = expected: ", p);
|
---|
| 548 | }
|
---|
| 549 | op = *p++;
|
---|
| 550 | while (ISMODE(*p)) {
|
---|
| 551 | switch (*p) {
|
---|
| 552 | case 'r':
|
---|
| 553 | if (w & MUSER) domode(op, &m, S_IRUSR);
|
---|
| 554 | if (w & MGROUP) domode(op, &m, S_IRGRP);
|
---|
| 555 | if (w & MOTHERS) domode(op, &m, S_IROTH);
|
---|
| 556 | break;
|
---|
| 557 | case 'w':
|
---|
| 558 | if (w & MUSER) domode(op, &m, S_IWUSR);
|
---|
| 559 | if (w & MGROUP) domode(op, &m, S_IWGRP);
|
---|
| 560 | if (w & MOTHERS) domode(op, &m, S_IWOTH);
|
---|
| 561 | break;
|
---|
| 562 | case 'x':
|
---|
| 563 | if (w & MUSER) domode(op, &m, S_IXUSR);
|
---|
| 564 | if (w & MGROUP) domode(op, &m, S_IXGRP);
|
---|
| 565 | if (w & MOTHERS) domode(op, &m, S_IXOTH);
|
---|
| 566 | break;
|
---|
| 567 | case 's':
|
---|
| 568 | if (w & MUSER) domode(op, &m, S_ISUID);
|
---|
| 569 | if (w & MGROUP) domode(op, &m, S_ISGID);
|
---|
| 570 | break;
|
---|
| 571 | case 't':
|
---|
| 572 | domode(op, &m, S_ISVTX);
|
---|
| 573 | }
|
---|
| 574 | p++;
|
---|
| 575 | }
|
---|
| 576 | if (*p) {
|
---|
| 577 | if (*p == ',')
|
---|
| 578 | p++;
|
---|
| 579 | else
|
---|
| 580 | fatal("garbage at end of mode string: ", p);
|
---|
| 581 | }
|
---|
| 582 | }
|
---|
| 583 | *pl = m;
|
---|
| 584 | }
|
---|
| 585 |
|
---|
| 586 | struct node *
|
---|
| 587 | expr(t)
|
---|
| 588 | int t;
|
---|
| 589 | {
|
---|
| 590 | struct node *nd, *p, *nd2;
|
---|
| 591 |
|
---|
| 592 | nd = primary(t);
|
---|
| 593 | if ((t = lex(*++ipp)) == OP_OR) {
|
---|
| 594 | nd2 = expr(lex(*++ipp));
|
---|
| 595 | p = newnode(OP_OR);
|
---|
| 596 | p->n_info.n_opnd.n_left = nd;
|
---|
| 597 | p->n_info.n_opnd.n_right = nd2;
|
---|
| 598 | return p;
|
---|
| 599 | }
|
---|
| 600 | ipp--;
|
---|
| 601 | return nd;
|
---|
| 602 | }
|
---|
| 603 |
|
---|
| 604 | struct node *
|
---|
| 605 | primary(t)
|
---|
| 606 | int t;
|
---|
| 607 | {
|
---|
| 608 | struct node *nd, *p, *nd2;
|
---|
| 609 |
|
---|
| 610 | nd = secondary(t);
|
---|
| 611 | if ((t = lex(*++ipp)) != OP_AND) {
|
---|
| 612 | ipp--;
|
---|
| 613 | if (t == EOI || t == RPAR || t == OP_OR) return nd;
|
---|
| 614 | }
|
---|
| 615 | nd2 = primary(lex(*++ipp));
|
---|
| 616 | p = newnode(OP_AND);
|
---|
| 617 | p->n_info.n_opnd.n_left = nd;
|
---|
| 618 | p->n_info.n_opnd.n_right = nd2;
|
---|
| 619 | return p;
|
---|
| 620 | }
|
---|
| 621 |
|
---|
| 622 | struct node *
|
---|
| 623 | secondary(t)
|
---|
| 624 | int t;
|
---|
| 625 | {
|
---|
| 626 | struct node *n, *p;
|
---|
| 627 |
|
---|
| 628 | if (t == LPAR) {
|
---|
| 629 | n = expr(lex(*++ipp));
|
---|
| 630 | if (lex(*++ipp) != RPAR) fatal("syntax error, ) expected", "");
|
---|
| 631 | return n;
|
---|
| 632 | }
|
---|
| 633 | if (t == NOT) {
|
---|
| 634 | n = secondary(lex(*++ipp));
|
---|
| 635 | p = newnode(NOT);
|
---|
| 636 | p->n_info.n_opnd.n_left = n;
|
---|
| 637 | return p;
|
---|
| 638 | }
|
---|
| 639 | return simple(t);
|
---|
| 640 | }
|
---|
| 641 |
|
---|
| 642 | void checkarg(arg)
|
---|
| 643 | char *arg;
|
---|
| 644 | {
|
---|
| 645 | if (arg == 0) fatal("syntax error, argument expected", "");
|
---|
| 646 | }
|
---|
| 647 |
|
---|
| 648 | struct node *
|
---|
| 649 | simple(t)
|
---|
| 650 | int t;
|
---|
| 651 | {
|
---|
| 652 | struct node *p = newnode(t);
|
---|
| 653 | struct exec *e;
|
---|
| 654 | struct stat est;
|
---|
| 655 | struct passwd *pw;
|
---|
| 656 | struct group *gr;
|
---|
| 657 | long l;
|
---|
| 658 | int i;
|
---|
| 659 |
|
---|
| 660 | switch (t) {
|
---|
| 661 | case OP_TYPE:
|
---|
| 662 | checkarg(*++ipp);
|
---|
| 663 | switch (**ipp) {
|
---|
| 664 | case 'b':
|
---|
| 665 | p->n_info.n_int.n_val = S_IFBLK;
|
---|
| 666 | break;
|
---|
| 667 | case 'c':
|
---|
| 668 | p->n_info.n_int.n_val = S_IFCHR;
|
---|
| 669 | break;
|
---|
| 670 | case 'd':
|
---|
| 671 | p->n_info.n_int.n_val = S_IFDIR;
|
---|
| 672 | break;
|
---|
| 673 | case 'f':
|
---|
| 674 | p->n_info.n_int.n_val = S_IFREG;
|
---|
| 675 | break;
|
---|
| 676 | case 'p':
|
---|
| 677 | p->n_info.n_int.n_val = S_IFIFO;
|
---|
| 678 | break;
|
---|
| 679 | case 's':
|
---|
| 680 | p->n_info.n_int.n_val = ~0;
|
---|
| 681 | break;
|
---|
| 682 | case 'l':
|
---|
| 683 | #ifdef S_IFLNK
|
---|
| 684 | p->n_info.n_int.n_val = S_IFLNK;
|
---|
| 685 | #else
|
---|
| 686 | p->n_info.n_int.n_val = ~0; /* Always unequal. */
|
---|
| 687 | #endif
|
---|
| 688 | break;
|
---|
| 689 | default:
|
---|
| 690 | fatal("-type needs b, c, d, f, p, s or l", "");
|
---|
| 691 | }
|
---|
| 692 | break;
|
---|
| 693 | case OP_USER:
|
---|
| 694 | checkarg(*++ipp);
|
---|
| 695 | if (((pw = getpwnam(*ipp)) == NULL)
|
---|
| 696 | && isnumber(*ipp, 10, 0))
|
---|
| 697 | number(*ipp, 10, &(p->n_info.n_int.n_val),
|
---|
| 698 | &(p->n_info.n_int.n_sign));
|
---|
| 699 | else {
|
---|
| 700 | if (pw == NULL)
|
---|
| 701 | fatal("unknown user: ", *ipp);
|
---|
| 702 | p->n_info.n_int.n_val = pw->pw_uid;
|
---|
| 703 | p->n_info.n_int.n_sign = 0;
|
---|
| 704 | }
|
---|
| 705 | break;
|
---|
| 706 | case OP_GROUP:
|
---|
| 707 | checkarg(*++ipp);
|
---|
| 708 | if (((gr = getgrnam(*ipp)) == NULL)
|
---|
| 709 | && isnumber(*ipp, 10, 0))
|
---|
| 710 | number(*ipp, 10, &(p->n_info.n_int.n_val),
|
---|
| 711 | &(p->n_info.n_int.n_sign));
|
---|
| 712 | else {
|
---|
| 713 | if (gr == NULL)
|
---|
| 714 | fatal("unknown group: ", *ipp);
|
---|
| 715 | p->n_info.n_int.n_val = gr->gr_gid;
|
---|
| 716 | p->n_info.n_int.n_sign = 0;
|
---|
| 717 | }
|
---|
| 718 | break;
|
---|
| 719 | case OP_SIZE:
|
---|
| 720 | checkarg(*++ipp);
|
---|
| 721 | i = strlen(*ipp) - 1;
|
---|
| 722 | if ((*ipp)[i] == 'c') {
|
---|
| 723 | p->n_type = OP_SIZEC; /* Count in bytes i.s.o. blocks */
|
---|
| 724 | (*ipp)[i] = '\0';
|
---|
| 725 | }
|
---|
| 726 | number(*ipp, 10, &(p->n_info.n_int.n_val),
|
---|
| 727 | &(p->n_info.n_int.n_sign));
|
---|
| 728 | break;
|
---|
| 729 | case OP_LINKS:
|
---|
| 730 | case OP_INUM:
|
---|
| 731 | checkarg(*++ipp);
|
---|
| 732 | number(*ipp, 10, &(p->n_info.n_int.n_val),
|
---|
| 733 | &(p->n_info.n_int.n_sign));
|
---|
| 734 | break;
|
---|
| 735 | case OP_PERM:
|
---|
| 736 | checkarg(*++ipp);
|
---|
| 737 | if (isnumber(*ipp, 8, 1)) number(*ipp, 8, &(p->n_info.n_int.n_val),
|
---|
| 738 | &(p->n_info.n_int.n_sign));
|
---|
| 739 | else
|
---|
| 740 | fmode(*ipp, &(p->n_info.n_int.n_val),
|
---|
| 741 | &(p->n_info.n_int.n_sign));
|
---|
| 742 | break;
|
---|
| 743 | case OP_ATIME:
|
---|
| 744 | case OP_CTIME:
|
---|
| 745 | case OP_MTIME:
|
---|
| 746 | checkarg(*++ipp);
|
---|
| 747 | number(*ipp, 10, &l, &(p->n_info.n_int.n_sign));
|
---|
| 748 | p->n_info.n_int.n_val = current_time - l * SECS_PER_DAY;
|
---|
| 749 | /* More than n days old means less than the absolute time */
|
---|
| 750 | p->n_info.n_int.n_sign *= -1;
|
---|
| 751 | break;
|
---|
| 752 | case OP_EXEC:
|
---|
| 753 | case OP_OK:
|
---|
| 754 | checkarg(*++ipp);
|
---|
| 755 | e = (struct exec *) Malloc(sizeof(struct exec));
|
---|
| 756 | e->e_cnt = 2;
|
---|
| 757 | e->e_vec[0] = SHELL;
|
---|
| 758 | p->n_info.n_exec = e;
|
---|
| 759 | while (*ipp) {
|
---|
| 760 | if (**ipp == ';' && (*ipp)[1] == '\0') {
|
---|
| 761 | e->e_vec[e->e_cnt] = 0;
|
---|
| 762 | break;
|
---|
| 763 | }
|
---|
| 764 | e->e_vec[(e->e_cnt)++] =
|
---|
| 765 | (**ipp == '{' && (*ipp)[1] == '}'
|
---|
| 766 | && (*ipp)[2] == '\0') ? (char *) (-1) : *ipp;
|
---|
| 767 | ipp++;
|
---|
| 768 | }
|
---|
| 769 | if (*ipp == 0) fatal("-exec/-ok: ; missing", "");
|
---|
| 770 | if ((e->e_vec[1] = find_bin(e->e_vec[2])) == 0)
|
---|
| 771 | fatal("can't find program ", e->e_vec[2]);
|
---|
| 772 | if (t == OP_OK)
|
---|
| 773 | if ((tty = open("/dev/tty", O_RDWR)) < 0)
|
---|
| 774 | fatal("can't open /dev/tty", "");
|
---|
| 775 | break;
|
---|
| 776 | case OP_CNEWER:
|
---|
| 777 | case OP_NEWER:
|
---|
| 778 | checkarg(*++ipp);
|
---|
| 779 | if (LSTAT(*ipp, &est) == -1)
|
---|
| 780 | fatal("-newer: can't get status of ", *ipp);
|
---|
| 781 | p->n_info.n_int.n_val = est.st_mtime;
|
---|
| 782 | break;
|
---|
| 783 | case OP_NAME:
|
---|
| 784 | checkarg(*++ipp);
|
---|
| 785 | p->n_info.n_str = *ipp;
|
---|
| 786 | break;
|
---|
| 787 | case OP_XDEV: xdev_flag = 1; break;
|
---|
| 788 | case OP_DEPTH: depth_flag = 1; break;
|
---|
| 789 | case OP_PRUNE:
|
---|
| 790 | case OP_PRINT:
|
---|
| 791 | case OP_PRINT0:
|
---|
| 792 | case OP_NOUSER: case OP_NOGROUP: break;
|
---|
| 793 | default:
|
---|
| 794 | fatal("syntax error, operator expected", "");
|
---|
| 795 | }
|
---|
| 796 | if ((t == OP_PRINT) || (t == OP_PRINT0) || (t == OP_EXEC) || (t == OP_OK))
|
---|
| 797 | needprint = 0;
|
---|
| 798 |
|
---|
| 799 | return p;
|
---|
| 800 | }
|
---|
| 801 |
|
---|
| 802 | /*######################## DIAGNOSTICS ##############################*/
|
---|
| 803 |
|
---|
| 804 | void nonfatal(s1, s2)
|
---|
| 805 | char *s1, *s2;
|
---|
| 806 | {
|
---|
| 807 | fprintf(stderr, "%s: %s%s\n", prog, s1, s2);
|
---|
| 808 | }
|
---|
| 809 |
|
---|
| 810 | void fatal(s1, s2)
|
---|
| 811 | char *s1, *s2;
|
---|
| 812 | {
|
---|
| 813 | nonfatal(s1, s2);
|
---|
| 814 | exit(1);
|
---|
| 815 | }
|
---|
| 816 |
|
---|
| 817 | /*################### SMATCH #########################*/
|
---|
| 818 | /* Don't try to understand the following one... */
|
---|
| 819 | int smatch(s, t) /* shell-like matching */
|
---|
| 820 | char *s, *t;
|
---|
| 821 | {
|
---|
| 822 | register n;
|
---|
| 823 |
|
---|
| 824 | if (*t == '\0') return *s == '\0';
|
---|
| 825 | if (*t == '*') {
|
---|
| 826 | ++t;
|
---|
| 827 | do
|
---|
| 828 | if (smatch(s, t)) return 1;
|
---|
| 829 | while (*s++ != '\0');
|
---|
| 830 | return 0;
|
---|
| 831 | }
|
---|
| 832 | if (*s == '\0') return 0;
|
---|
| 833 | if (*t == '\\') return (*s == *++t) ? smatch(++s, ++t) : 0;
|
---|
| 834 | if (*t == '?') return smatch(++s, ++t);
|
---|
| 835 | if (*t == '[') {
|
---|
| 836 | while (*++t != ']') {
|
---|
| 837 | if (*t == '\\') ++t;
|
---|
| 838 | if (*(t + 1) != '-')
|
---|
| 839 | if (*t == *s) {
|
---|
| 840 | while (*++t != ']')
|
---|
| 841 | if (*t == '\\') ++t;
|
---|
| 842 | return smatch(++s, ++t);
|
---|
| 843 | } else
|
---|
| 844 | continue;
|
---|
| 845 | if (*(t + 2) == ']') return(*s == *t || *s == '-');
|
---|
| 846 | n = (*(t + 2) == '\\') ? 3 : 2;
|
---|
| 847 | if (*s >= *t && *s <= *(t + n)) {
|
---|
| 848 | while (*++t != ']')
|
---|
| 849 | if (*t == '\\') ++t;
|
---|
| 850 | return smatch(++s, ++t);
|
---|
| 851 | }
|
---|
| 852 | t += n;
|
---|
| 853 | }
|
---|
| 854 | return 0;
|
---|
| 855 | }
|
---|
| 856 | return(*s == *t) ? smatch(++s, ++t) : 0;
|
---|
| 857 | }
|
---|
| 858 |
|
---|
| 859 | /*####################### EXECUTE ###########################*/
|
---|
| 860 | /* Do -exec or -ok */
|
---|
| 861 |
|
---|
| 862 | char *
|
---|
| 863 | find_bin(s)
|
---|
| 864 | char *s;
|
---|
| 865 | {
|
---|
| 866 | char *f, *l, buf[PATH_MAX];
|
---|
| 867 |
|
---|
| 868 | if (*s == '/') /* absolute path name */
|
---|
| 869 | return(access(s, 1) == 0) ? s : 0;
|
---|
| 870 | l = f = epath;
|
---|
| 871 | for (;;) {
|
---|
| 872 | if (*l == ':' || *l == 0) {
|
---|
| 873 | if (l == f) {
|
---|
| 874 | if (access(s, 1) == 0) return Salloc(s);
|
---|
| 875 | f++;
|
---|
| 876 | } else {
|
---|
| 877 | register char *p = buf, *q = s;
|
---|
| 878 |
|
---|
| 879 | while (f != l) *p++ = *f++;
|
---|
| 880 | f++;
|
---|
| 881 | *p++ = '/';
|
---|
| 882 | while (*p++ = *q++) {
|
---|
| 883 | }
|
---|
| 884 | if (access(buf, 1) == 0) return Salloc(buf);
|
---|
| 885 | }
|
---|
| 886 | if (*l == 0) break;
|
---|
| 887 | }
|
---|
| 888 | l++;
|
---|
| 889 | }
|
---|
| 890 | return 0;
|
---|
| 891 | }
|
---|
| 892 |
|
---|
| 893 | int execute(op, e, path)
|
---|
| 894 | int op;
|
---|
| 895 | struct exec *e;
|
---|
| 896 | char *path;
|
---|
| 897 | {
|
---|
| 898 | int s, pid;
|
---|
| 899 | char *argv[MAXARG];
|
---|
| 900 | register char **p, **q;
|
---|
| 901 |
|
---|
| 902 | for (p = e->e_vec, q = argv; *p;) /* replace the {}s */
|
---|
| 903 | if ((*q++ = *p++) == (char *) -1) q[-1] = path;
|
---|
| 904 | *q = '\0';
|
---|
| 905 | if (op == OP_OK) {
|
---|
| 906 | char answer[10];
|
---|
| 907 |
|
---|
| 908 | for (p = &argv[2]; *p; p++) {
|
---|
| 909 | write(tty, *p, strlen(*p));
|
---|
| 910 | write(tty, " ", 1);
|
---|
| 911 | }
|
---|
| 912 | write(tty, "? ", 2);
|
---|
| 913 | if (read(tty, answer, 10) < 2 || *answer != 'y') return 0;
|
---|
| 914 | }
|
---|
| 915 | if ((pid = fork()) == -1) fatal("can't fork", "");
|
---|
| 916 | if (pid == 0) {
|
---|
| 917 | register i = 3;
|
---|
| 918 |
|
---|
| 919 | while (close(i++) == 0) {
|
---|
| 920 | } /* wow!!! */
|
---|
| 921 | execv(argv[1], &argv[2]); /* binary itself? */
|
---|
| 922 | execv(argv[0], &argv[1]); /* shell command? */
|
---|
| 923 | fatal("exec failure: ", argv[1]); /* none of them! */
|
---|
| 924 | exit(127);
|
---|
| 925 | }
|
---|
| 926 | return wait(&s) == pid && s == 0;
|
---|
| 927 | }
|
---|