find.c (36563B)
1 /* find COMPILE: cc -o find -s -O -i find.c -lS */ 2 /* 3 * Changes by Gunnar Ritter, Freiburg i. Br., Germany, September 2003. 4 */ 5 /* from Unix 7th Edition /usr/src/cmd/find.c */ 6 /* 7 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * Redistributions of source code and documentation must retain the 13 * above copyright notice, this list of conditions and the following 14 * disclaimer. 15 * Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed or owned by Caldera 21 * International, Inc. 22 * Neither the name of Caldera International, Inc. nor the names of 23 * other contributors may be used to endorse or promote products 24 * derived from this software without specific prior written permission. 25 * 26 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 27 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 29 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE 31 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 34 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 35 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 36 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 37 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4 41 #define USED __attribute__ ((used)) 42 #elif defined __GNUC__ 43 #define USED __attribute__ ((unused)) 44 #else 45 #define USED 46 #endif 47 #if defined (SU3) 48 static const char sccsid[] USED = "@(#)find_su3.sl 1.45 (gritter) 5/8/06"; 49 #elif defined (SUS) 50 static const char sccsid[] USED = "@(#)find_sus.sl 1.45 (gritter) 5/8/06"; 51 #else 52 static const char sccsid[] USED = "@(#)find.sl 1.45 (gritter) 5/8/06"; 53 #endif 54 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <sys/types.h> 59 #include <sys/stat.h> 60 #include <sys/wait.h> 61 #include <sys/resource.h> 62 #include <fcntl.h> 63 #include <unistd.h> 64 #include <pwd.h> 65 #include <time.h> 66 #include <grp.h> 67 #include <stdarg.h> 68 #include <libgen.h> 69 #include <errno.h> 70 #include <locale.h> 71 #include <signal.h> 72 #if defined (SUS) || defined (SU3) 73 #include <fnmatch.h> 74 #endif 75 #if defined (__linux__) || defined (_AIX) || defined (__hpux) 76 #include <mntent.h> 77 #endif 78 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || \ 79 defined (__DragonFly__) || defined (__APPLE__) 80 #include <sys/param.h> 81 #include <sys/mount.h> 82 #endif 83 #ifdef _AIX 84 #include <sys/sysmacros.h> 85 #endif 86 #ifndef major 87 #include <sys/mkdev.h> 88 #endif 89 #if __NetBSD_Version__>= 300000000 90 #include <sys/statvfs.h> 91 #define statfs statvfs 92 #endif 93 #include "getdir.h" 94 #include "atoll.h" 95 #define A_DAY 86400L /* a day full of seconds */ 96 #define EQ(x, y) (strcmp(x, y)==0) 97 98 #ifndef MNTTYPE_IGNORE 99 #define MNTTYPE_IGNORE "" 100 #endif 101 102 #ifndef S_IFDOOR 103 #define S_IFDOOR 0xD000 104 #endif 105 106 #ifndef S_IFNWK 107 #define S_IFNWK 0x9000 108 #endif 109 110 #undef ctime 111 #define ctime find_ctime 112 113 static char *Pathname; 114 115 struct aggregate { /* for exec ... {} + */ 116 long a_cnt; /* count of arguments */ 117 long a_cur; /* current position in aggregate */ 118 long a_csz; /* aggregate current length */ 119 long a_msz; /* aggregate maximum length */ 120 char **a_vec; /* arguments */ 121 char *a_spc; /* aggregate space */ 122 long a_maxarg; /* maximum arguments in e_vec */ 123 }; 124 125 struct anode { 126 int (*F)(struct anode *); 127 union anode_l { 128 struct anode *L; 129 char *pat; 130 time_t t; 131 uid_t u; 132 gid_t g; 133 ino_t i; 134 nlink_t link; 135 off_t sz; 136 mode_t per; 137 int com; 138 FILE *fp; 139 char *fstype; 140 } l; 141 union anode_r { 142 struct anode *R; 143 int s; 144 pid_t pid; 145 struct aggregate *a; 146 } r; 147 }; 148 static char *Fname; 149 static time_t Now; 150 static int Argc, 151 Ai, 152 Pi; 153 static char **Argv; 154 /* cpio stuff */ 155 static int Cpio; 156 157 static struct stat Statb; 158 159 /* 160 * Keep track of all visited directories, to avoid loops caused by 161 * symbolic links and to free storage and close files after fork(). 162 */ 163 static struct visit { 164 struct getdb *v_db; /* getdb struct for this level */ 165 ino_t v_ino; /* inode number */ 166 int v_fd; /* file descriptor */ 167 dev_t v_dev; /* device id */ 168 } *visited; 169 static int vismax; /* number of members in visited */ 170 171 /* 172 * For -fstype, keep track of all filesystem types known to the system. If 173 * we had st_fstype in struct stat as SVR4 does, this would be far more 174 * reliable. 175 */ 176 #if defined (__linux__) || defined (_AIX) || defined (__hpux) 177 static struct fstype { 178 dev_t fsdev; /* device id of filesystem */ 179 char *fstype; /* filesystem type */ 180 } *fstypes, *fscur; 181 #endif /* __linux__ || _AIX || __hpux */ 182 183 static int Home = -1; 184 static int wanthome; 185 static mode_t um; /* user's umask */ 186 static const char *progname; 187 static int status; /* exit status */ 188 static int depth; /* -depth flag */ 189 static int Print = 1; /* implicit -print */ 190 static int Prune; /* -prune at this point */ 191 static int Mount; /* -mount, -xdev */ 192 static int Execplus; /* have a -exec command {} + node */ 193 static int HLflag; /* -H or -L option given */ 194 static char *Statfs; /* result of statfs() on FreeBSD */ 195 static int incomplete; /* encountered an incomplete statement */ 196 extern int sysv3; 197 198 static int (*statfn)(const char *, struct stat *) = lstat; 199 200 static struct anode *expr(void); 201 static struct anode *e1(void); 202 static struct anode *e2(void); 203 static struct anode *e3(void); 204 static struct anode *mk(struct anode *); 205 static void oper(const char **); 206 static char *nxtarg(int); 207 static int and(struct anode *); 208 static int or(struct anode *); 209 static int not(struct anode *); 210 static int glob(struct anode *); 211 static int print(struct anode *); 212 static int prune(struct anode *); 213 static int null(struct anode *); 214 static int mtime(struct anode *); 215 static int atime(struct anode *); 216 static int ctime(struct anode *); 217 static int user(struct anode *); 218 static int ino(struct anode *); 219 static int group(struct anode *); 220 static int nogroup(struct anode *); 221 static int nouser(struct anode *); 222 static int links(struct anode *); 223 static int size(struct anode *); 224 static int sizec(struct anode *); 225 static int perm(struct anode *); 226 static int type(struct anode *); 227 static int exeq(struct anode *); 228 static int ok(struct anode *); 229 static int cpio(struct anode *); 230 static int newer(struct anode *); 231 static int cnewer(struct anode *); 232 static int anewer(struct anode *); 233 static int fstype(struct anode *); 234 static int local(struct anode *); 235 static int scomp(long long, long long, char); 236 static int doex(int, struct aggregate *); 237 static struct aggregate *mkagg(long); 238 static uid_t getunum(const char *); 239 static gid_t getgnum(const char *); 240 static const char *getuser(uid_t); 241 static const char *getgroup(gid_t); 242 #if defined (__linux__) || defined (_AIX) || defined (__hpux) 243 static void getfscur(dev_t); 244 static void getfstypes(void); 245 #endif /* __linux__ || _AIX || __hpux */ 246 static int descend(char *, struct anode *, int); 247 static int descend1(char *, struct anode *, int); 248 static int descend2(char *, struct anode *, int); 249 static void setpath(char *, const char *, int); 250 static void pr(const char *, ...); 251 static void er(const char *, ...); 252 static void usage(void); 253 static void *srealloc(void *, size_t); 254 static void mkcpio(struct anode *, const char *, int); 255 static void trailer(struct anode *, int); 256 static void mknewer(struct anode *, const char *, int (*)(struct anode *)); 257 static mode_t newmode(const char *ms, const mode_t pm); 258 259 int 260 main(int argc, char **argv) 261 { 262 struct anode *exlist; 263 struct anode nlist = { null, { 0 }, { 0 } }; 264 int paths; 265 register char *sp = 0; 266 int i, j; 267 268 time(&Now); 269 umask(um = umask(0)); 270 progname = basename(argv[0]); 271 setlocale(LC_COLLATE, ""); 272 setlocale(LC_CTYPE, ""); 273 if (getenv("SYSV3") != NULL) 274 sysv3 = 1; 275 for (i = 1; i < argc; i++) { 276 if (argv[i][0] != '-' || argv[i][1] == '\0') 277 break; 278 if (argv[i][1] == '-') { 279 i++; 280 break; 281 } 282 for (j = 1; argv[i][j]; j++) 283 if (argv[i][j] != 'H' && argv[i][j] != 'L') 284 goto brk; 285 for (j = 1; argv[i][j]; j++) 286 HLflag = argv[i][j]; 287 } 288 brk: if (HLflag == 'L') 289 statfn = stat; 290 argc -= i - 1; 291 argv += i - 1; 292 Argc = argc; Argv = argv; 293 if(argc<2) { 294 pr("insufficient number of arguments"); 295 usage(); 296 } 297 for(Ai = paths = 1; Ai < argc; ++Ai, ++paths) 298 if(*Argv[Ai] == '-' || EQ(Argv[Ai], "(") || EQ(Argv[Ai], "!")) 299 break; 300 if(paths == 1) /* no path-list */ 301 usage(); 302 if(Ai<argc) { 303 if(!(exlist = expr())) /* parse and compile the arguments */ 304 er("find: parsing error"); 305 if(Ai<argc) { 306 pr("bad option %s", argv[Ai]); 307 usage(); 308 } 309 } else 310 exlist = &nlist; 311 if (paths > 2) 312 wanthome = 1; 313 if (wanthome && (Home = open(".", O_RDONLY)) < 0) 314 er("bad starting directory"); 315 for(Pi = 1; Pi < paths; ++Pi) { 316 if (Pi > 1 && Home >= 0 && fchdir(Home) < 0) 317 er("bad starting directory"); 318 setpath(Pathname, Argv[Pi], 0); 319 Fname = sp = Pathname; 320 do 321 if (sp[0] == '/') 322 Fname = &sp[1]; 323 while (*sp++); 324 descend(Pathname, exlist, 0); /* to find files that match */ 325 } 326 if(Cpio || Execplus) 327 trailer(exlist, 1); 328 exit(status); 329 } 330 331 /* compile time functions: priority is expr()<e1()<e2()<e3() */ 332 333 /*ARGSUSED*/ 334 static struct anode *expr(void) { /* parse ALTERNATION (-o) */ 335 register struct anode * p1; 336 struct anode n = { 0, { 0 }, { 0 } }; 337 338 p1 = e1() /* get left operand */ ; 339 if(EQ(nxtarg(0), "-o")) { 340 const char *ops[] = { "-o", "-a", 0 }; 341 oper(ops); 342 n.F = or, n.l.L = p1, n.r.R = expr(); 343 return(mk(&n)); 344 } 345 else if(Ai <= Argc) --Ai; 346 return(p1); 347 } 348 static struct anode *e1(void) { /* parse CONCATENATION (formerly -a) */ 349 register struct anode * p1; 350 register char *a; 351 struct anode n = { 0, { 0 }, { 0 } }; 352 353 p1 = e2(); 354 a = nxtarg(0); 355 if(EQ(a, "-a")) { 356 const char *ops[] = { "-o", "-a", 0 }; 357 oper(ops); 358 And: 359 n.F = and, n.l.L = p1, n.r.R = e1(); 360 return(mk(&n)); 361 } else if(EQ(a, "(") || EQ(a, "!") || (*a=='-' && !EQ(a, "-o"))) { 362 --Ai; 363 goto And; 364 } else if(Ai <= Argc) --Ai; 365 return(p1); 366 } 367 static struct anode *e2(void) { /* parse NOT (!) */ 368 struct anode n = { 0, { 0 }, { 0 } }; 369 if(EQ(nxtarg(0), "!")) { 370 const char *ops[] = { "-o", "-a", "!", 0 }; 371 oper(ops); 372 n.F = not, n.l.L = e3(); 373 return(mk(&n)); 374 } 375 else if(Ai <= Argc) --Ai; 376 return(e3()); 377 } 378 static struct anode *e3(void) { /* parse parens and predicates */ 379 struct anode *p1; 380 struct anode n = { 0, { 0 }, { 0 } }; 381 long i, k; 382 register char *a, *b, s, *p, *q; 383 384 a = nxtarg(0); 385 if(EQ(a, "(")) { 386 const char *ops[] = { "-o", "-a", 0 }; 387 oper(ops); 388 p1 = expr(); 389 a = nxtarg(1); 390 if(!EQ(a, ")")) goto err; 391 return(p1); 392 } 393 else if(EQ(a, "-depth")) { 394 depth = 1; 395 n.F = null; 396 } else if(EQ(a, "-follow")) { 397 statfn = stat; 398 n.F = null; 399 } else if(EQ(a, "-mount") || EQ(a, "-xdev")) { 400 Mount = 1; 401 n.F = null; 402 } else if(EQ(a, "-print")) { 403 Print = 0; 404 n.F = print; 405 } else if(EQ(a, "-prune")) 406 n.F = prune; 407 else if(EQ(a, "-nogroup")) 408 n.F = nogroup; 409 else if(EQ(a, "-nouser")) 410 n.F = nouser; 411 else if(EQ(a, "-local")) { 412 #if defined (__linux__) || defined (_AIX) || defined (__hpux) 413 getfstypes(); 414 #endif /* __linux__ || _AIX || __hpux */ 415 n.F = local; 416 Statfs = a; 417 } 418 if (n.F) 419 return mk(&n); 420 b = nxtarg(2); 421 s = *b; 422 /*if(s=='+') b++;*/ 423 if(EQ(a, "-name")) 424 n.F = glob, n.l.pat = b; 425 else if(EQ(a, "-mtime")) 426 n.F = mtime, n.l.t = atol(b), n.r.s = s; 427 else if(EQ(a, "-atime")) 428 n.F = atime, n.l.t = atol(b), n.r.s = s; 429 else if(EQ(a, "-ctime")) 430 n.F = ctime, n.l.t = atol(b), n.r.s = s; 431 else if(EQ(a, "-user")) 432 n.F = user, n.l.u = getunum(b), n.r.s = s; 433 else if(EQ(a, "-inum")) 434 n.F = ino, n.l.i = atoll(b), n.r.s = s; 435 else if(EQ(a, "-group")) 436 n.F = group, n.l.g = getgnum(b), n.r.s = s; 437 else if(EQ(a, "-size")) { 438 n.l.sz = atoll(b), n.r.s = s; 439 while (b[0] && b[1]) 440 b++; 441 if (b[0] == 'c') 442 n.F = sizec; 443 else 444 n.F = size; 445 } 446 else if(EQ(a, "-links")) 447 n.F = links, n.l.link = atol(b), n.r.s = s; 448 else if(EQ(a, "-perm")) { 449 while (*b == '-') 450 b++; 451 n.F = perm, n.l.per = newmode(b, 0), n.r.s = s; 452 #if defined (SUS) || defined (SU3) 453 if (s == '-') 454 n.l.per &= 07777; 455 #endif 456 } 457 else if(EQ(a, "-type")) { 458 i = b[0] == '-' || b[0] == '+' ? b[1] : b[0]; 459 i = i=='d' ? S_IFDIR : 460 i=='b' ? S_IFBLK : 461 i=='c' ? S_IFCHR : 462 i=='D' ? S_IFDOOR : 463 i=='f' ? S_IFREG : 464 i=='l' ? S_IFLNK : 465 i=='n' ? S_IFNWK : 466 i=='p' ? S_IFIFO : 467 i=='s' ? S_IFSOCK : 468 0; 469 n.F = type, n.l.per = i; 470 } 471 else if (EQ(a, "-exec")) { 472 Print = 0; 473 wanthome = 1; 474 i = Ai - 1; 475 q = ""; 476 k = 0; 477 while(!EQ(p = nxtarg(1), ";")) { 478 if (EQ(p, "+") && EQ(q, "{}")) { 479 n.r.a = mkagg(k); 480 break; 481 } 482 q = p; 483 k += strlen(p) + 1; 484 } 485 n.F = exeq, n.l.com = i; 486 } 487 else if (EQ(a, "-ok")) { 488 Print = 0; 489 wanthome = 1; 490 i = Ai - 1; 491 while(!EQ(p = nxtarg(1), ";")); 492 n.F = ok, n.l.com = i; 493 } 494 else if(EQ(a, "-cpio")) 495 mkcpio(&n, b, 0); 496 else if(EQ(a, "-ncpio")) 497 mkcpio(&n, b, 1); 498 else if(EQ(a, "-newer")) 499 mknewer(&n, b, newer); 500 else if(EQ(a, "-anewer")) 501 mknewer(&n, b, anewer); 502 else if(EQ(a, "-cnewer")) 503 mknewer(&n, b, cnewer); 504 else if(EQ(a, "-fstype")) { 505 #if defined (__linux__) || defined (_AIX) || defined (__hpux) 506 getfstypes(); 507 #endif /* __linux__ || _AIX || __hpux */ 508 n.F = fstype, n.l.fstype = b; 509 Statfs = a; 510 } 511 if (n.F) { 512 if (incomplete) 513 nxtarg(1); 514 return mk(&n); 515 } 516 err: pr("bad option %s", a); 517 usage(); 518 /*NOTREACHED*/ 519 return 0; 520 } 521 static struct anode *mk(struct anode *p) 522 { 523 struct anode *n; 524 525 n = srealloc(NULL, sizeof *n); 526 *n = *p; 527 return(n); 528 } 529 static void oper(const char **ops) 530 { 531 char *a; 532 533 a = nxtarg(-1); 534 while (*ops) 535 if (EQ(a, *ops++)) 536 er("operand follows operand"); 537 Ai--; 538 } 539 540 static char *nxtarg(int must) { /* get next arg from command line */ 541 static int strikes = 0; 542 543 if(must==1 && Ai>=Argc || strikes==3) 544 er("incomplete statement"); 545 if(Ai>=Argc) { 546 if (must >= 0) 547 strikes++; 548 incomplete = 1; 549 Ai = Argc + 1; 550 return(""); 551 } 552 return(Argv[Ai++]); 553 } 554 555 /* execution time functions */ 556 static int and(register struct anode *p) 557 { 558 return(((*p->l.L->F)(p->l.L)) && ((*p->r.R->F)(p->r.R))?1:0); 559 } 560 static int or(register struct anode *p) 561 { 562 return(((*p->l.L->F)(p->l.L)) || ((*p->r.R->F)(p->r.R))?1:0); 563 } 564 static int not(register struct anode *p) 565 { 566 return( !((*p->l.L->F)(p->l.L))); 567 } 568 #if !defined (SUS) && !defined (SU3) 569 static int glob(register struct anode *p) 570 { 571 extern int gmatch(const char *, const char *); 572 return(gmatch(Fname, p->l.pat)); 573 } 574 #else /* SUS, SU3 */ 575 static int glob(register struct anode *p) 576 { 577 int val; 578 #ifdef __GLIBC__ 579 /* avoid glibc's broken [^...] */ 580 extern char **environ; 581 char **savenv = environ; 582 char *newenv[] = { "POSIXLY_CORRECT=", NULL }; 583 environ = newenv; 584 #endif /* __GLIBC__ */ 585 val = fnmatch(p->l.pat, Fname, FNM_PATHNAME) == 0; 586 #ifdef __GLIBC__ 587 environ = savenv; 588 #endif /* __GLIBC__ */ 589 return val; 590 } 591 #endif /* SUS, SU3 */ 592 /*ARGSUSED*/ 593 static int print(register struct anode *p) 594 { 595 puts(Pathname); 596 return(1); 597 } 598 /*ARGSUSED*/ 599 static int prune(register struct anode *p) 600 { 601 if (!depth) 602 Prune = 1; 603 return(1); 604 } 605 /*ARGSUSED*/ 606 static int null(register struct anode *p) 607 { 608 return(1); 609 } 610 static int mtime(register struct anode *p) 611 { 612 return(scomp((Now - Statb.st_mtime) / A_DAY, p->l.t, p->r.s)); 613 } 614 static int atime(register struct anode *p) 615 { 616 return(scomp((Now - Statb.st_atime) / A_DAY, p->l.t, p->r.s)); 617 } 618 static int ctime(register struct anode *p) 619 { 620 return(scomp((Now - Statb.st_ctime) / A_DAY, p->l.t, p->r.s)); 621 } 622 static int user(register struct anode *p) 623 { 624 return(scomp(Statb.st_uid, p->l.u, p->r.s)); 625 } 626 static int ino(register struct anode *p) 627 { 628 return(scomp(Statb.st_ino, p->l.u, p->r.s)); 629 } 630 static int group(register struct anode *p) 631 { 632 return(p->l.u == Statb.st_gid); 633 } 634 static int nogroup(register struct anode *p) 635 { 636 return(getgroup(Statb.st_gid) == NULL); 637 } 638 static int nouser(register struct anode *p) 639 { 640 return(getuser(Statb.st_uid) == NULL); 641 } 642 static int links(register struct anode *p) 643 { 644 return(scomp(Statb.st_nlink, p->l.link, p->r.s)); 645 } 646 static int size(register struct anode *p) 647 { 648 return(scomp(Statb.st_size?(Statb.st_size+511)>>9:0, p->l.sz, p->r.s)); 649 } 650 static int sizec(register struct anode *p) 651 { 652 return(scomp(Statb.st_size, p->l.sz, p->r.s)); 653 } 654 static int perm(register struct anode *p) 655 { 656 register int i; 657 i = (p->r.s=='-') ? p->l.per : 07777; /* '-' means only arg bits */ 658 return((Statb.st_mode & i & 07777) == p->l.per); 659 } 660 static int type(register struct anode *p) 661 { 662 return((Statb.st_mode&S_IFMT)==p->l.per); 663 } 664 static int exeq(register struct anode *p) 665 { 666 if (p->r.a) { 667 if (Pathname) { 668 size_t sz = strlen(Pathname) + 1; 669 if (p->r.a->a_csz + sz <= p->r.a->a_msz && 670 p->r.a->a_cur < p->r.a->a_maxarg-1) { 671 strcpy(p->r.a->a_vec[p->r.a->a_cur++] = 672 &p->r.a->a_spc[p->r.a->a_csz], 673 Pathname); 674 p->r.a->a_csz += sz; 675 return 1; 676 } else { 677 if (p->r.a->a_cur == 0) { 678 p->r.a->a_vec[p->r.a->a_cur++] = 679 Pathname; 680 p->r.a->a_vec[p->r.a->a_cur] = NULL; 681 } 682 else { 683 p->r.a->a_vec[p->r.a->a_cur] = NULL; 684 fflush(stdout); 685 doex(p->l.com, p->r.a); 686 return exeq(p); 687 } 688 } 689 } else { 690 if (p->r.a->a_cur == 0) 691 return 1; 692 p->r.a->a_vec[p->r.a->a_cur] = NULL; 693 } 694 } 695 fflush(stdout); /* to flush possible `-print' */ 696 return(doex(p->l.com, p->r.a)); 697 } 698 static int ok(struct anode *p) 699 { 700 char c; int yes; 701 yes = 0; 702 fflush(stdout); /* to flush possible `-print' */ 703 fprintf(stderr, "< %s ... %s >? ", Argv[p->l.com], Pathname); 704 if (read(0, &c, 1) != 1) 705 exit(2); 706 yes = c == 'y'; 707 if (c != '\n') 708 while (read(0, &c, 1) == 1 && c != '\n'); 709 if(yes) return(doex(p->l.com, 0)); 710 return(0); 711 } 712 713 static int cpio(struct anode *p) 714 { 715 if (strchr(Pathname, '\n')) { 716 pr("file name \"%s\" contains a newline character; " 717 "file not archived", Pathname); 718 status |= 1; 719 } else 720 fprintf(p->l.fp, "%s\n", Pathname); 721 return(1); 722 } 723 static int newer(register struct anode *p) 724 { 725 return Statb.st_mtime > p->l.t; 726 } 727 static int anewer(register struct anode *p) 728 { 729 return Statb.st_atime > p->l.t; 730 } 731 static int cnewer(register struct anode *p) 732 { 733 return Statb.st_ctime > p->l.t; 734 } 735 static int fstype(register struct anode *p) 736 { 737 #if defined (__linux__) || defined (_AIX) || defined (__hpux) 738 return(EQ(fscur->fstype, p->l.fstype)); 739 #elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \ 740 || defined (__DragonFly__) || defined (__APPLE__) 741 return(EQ(Statfs, p->l.fstype)); 742 #else 743 return(EQ(Statb.st_fstype, p->l.fstype)); 744 #endif 745 } 746 static int local(register struct anode *p) 747 { 748 #if defined (__linux__) || defined (_AIX) || defined (__hpux) 749 return(strcmp(fscur->fstype, "nfs") && strcmp(fscur->fstype, "smbfs")); 750 #elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \ 751 || defined (__DragonFly__) || defined (__APPLE__) 752 return(strcmp(Statfs, "nfs") != 0); 753 #else 754 return(strcmp(Statb.st_fstype, "nfs") != 0); 755 #endif 756 } 757 758 /* support functions */ 759 /* funny signed compare */ 760 static int scomp(register long long a, register long long b, register char s) 761 { 762 if(s == '+') 763 return(a > b); 764 if(s == '-') 765 return(a < (b * -1)); 766 return(a == b); 767 } 768 769 static int 770 doex(int com, struct aggregate *a) 771 { 772 register int np; 773 register char *na; 774 char **oargv; 775 int oargc; 776 static char **nargv; 777 static int narga; 778 static int ccode; 779 pid_t pid; 780 781 ccode = np = 0; 782 oargv = Argv; 783 oargc = com; 784 while (na=oargv[oargc++]) { 785 if (np >= narga-1) 786 nargv = srealloc(nargv, (narga+=20) * sizeof *nargv); 787 if(strcmp(na, ";")==0 && oargv == Argv) break; 788 if(strcmp(na, "{}")==0 && oargv == Argv) { 789 if (a) { 790 oargv = a->a_vec; 791 oargc = 0; 792 } else 793 nargv[np++] = Pathname; 794 } 795 else nargv[np++] = na; 796 } 797 if (a) { 798 a->a_cur = 0; 799 a->a_csz = 0; 800 } 801 if (np==0) return(9); 802 nargv[np] = 0; 803 if(pid = fork()) /*parent*/ while (wait(&ccode) != pid); 804 else { /*child*/ 805 if (fchdir(Home) < 0) { 806 pr("bad starting directory"); 807 _exit(1); 808 } 809 execvp(nargv[0], nargv); 810 _exit(1); 811 } 812 if (a && ccode) { 813 if (WIFSIGNALED(ccode)) 814 status |= WTERMSIG(ccode) | 0200; 815 else if (WIFEXITED(ccode)) 816 status |= WEXITSTATUS(ccode); 817 } 818 return(ccode && a==NULL ? 0:1); 819 } 820 821 static struct aggregate *mkagg(long baselen) 822 { 823 static size_t envsz; 824 extern char **environ; 825 register int i; 826 struct aggregate *a; 827 828 a = srealloc(NULL, sizeof *a); 829 if (envsz == 0) 830 for (i = 0; environ[i]; i++) 831 envsz += strlen(environ[i]) + 1; 832 a->a_msz = sysconf(_SC_ARG_MAX) - baselen - envsz - 2048; 833 a->a_spc = srealloc(NULL, a->a_msz); 834 a->a_maxarg = 8192; 835 a->a_vec = srealloc(NULL, a->a_maxarg * sizeof *a->a_vec); 836 a->a_csz = 0; 837 a->a_cur = 0; 838 Execplus = 1; 839 return a; 840 } 841 842 static uid_t getunum(const char *s) { /* find user name and return number */ 843 struct passwd *pwd; 844 char *x; 845 uid_t u; 846 847 if ((pwd = getpwnam(s)) != NULL) 848 return pwd->pw_uid; 849 u = strtol(s, &x, 10); 850 if (*x == '\0') 851 return u; 852 er("cannot find %s name", s); 853 /*NOTREACHED*/ 854 return 0; 855 } 856 857 static gid_t getgnum(const char *s) { /* find group name and return number */ 858 struct group *grp; 859 char *x; 860 gid_t g; 861 862 if ((grp = getgrnam(s)) != NULL) 863 return grp->gr_gid; 864 g = strtol(s, &x, 10); 865 if (*x == '\0') 866 return g; 867 er("cannot find %s name", s); 868 /*NOTREACHED*/ 869 return 0; 870 } 871 872 #define CACHESIZE 16 873 874 static const char *getuser(uid_t uid) 875 { 876 static struct { 877 char *name; 878 uid_t uid; 879 } cache[CACHESIZE]; 880 static int last; 881 int i; 882 struct passwd *pwd; 883 const char *name; 884 885 for (i = 0; i < CACHESIZE && cache[i].name; i++) 886 if (cache[i].uid == uid) 887 goto found; 888 if ((pwd = getpwuid(uid)) != NULL) 889 name = pwd->pw_name; 890 else 891 name = ""; 892 if (i >= CACHESIZE) { 893 if (last >= CACHESIZE) 894 last = 0; 895 i = last++; 896 } 897 if (cache[i].name) 898 free(cache[i].name); 899 cache[i].name = strdup(name); 900 cache[i].uid = uid; 901 found: return cache[i].name[0] ? cache[i].name : NULL; 902 } 903 904 static const char *getgroup(gid_t gid) 905 { 906 static struct { 907 char *name; 908 gid_t gid; 909 } cache[CACHESIZE]; 910 static int last; 911 int i; 912 struct group *grp; 913 const char *name; 914 915 for (i = 0; i < CACHESIZE && cache[i].name; i++) 916 if (cache[i].gid == gid) 917 goto found; 918 if ((grp = getgrgid(gid)) != NULL) 919 name = grp->gr_name; 920 else 921 name = ""; 922 if (i >= CACHESIZE) { 923 if (last >= CACHESIZE) 924 last = 0; 925 i = last++; 926 } 927 if (cache[i].name) 928 free(cache[i].name); 929 cache[i].name = strdup(name); 930 cache[i].gid = gid; 931 found: return cache[i].name[0] ? cache[i].name : NULL; 932 } 933 934 #if defined (__linux__) || defined (_AIX) || defined (__hpux) 935 static void getfscur(dev_t dev) 936 { 937 int i; 938 939 for (i = 0; fstypes[i].fstype; i++) 940 if (fstypes[i].fsdev == dev) { 941 fscur = &fstypes[i]; 942 return; 943 } 944 er("filesystem type for %s unknown", Pathname); 945 } 946 947 static void getfstypes(void) 948 { 949 struct stat st; 950 FILE *fp; 951 struct mntent *mp; 952 #ifdef __hpux 953 const char mtab[] = "/etc/mnttab"; 954 #else /* __linux__, _AIX */ 955 const char mtab[] = "/etc/mtab"; 956 #endif /* __linux__, _AIX */ 957 int i = 0; 958 959 if (fstypes) 960 return; 961 if ((fp = setmntent(mtab, "r")) == NULL) 962 er("cannot open %s: %s", mtab, strerror(errno)); 963 while ((mp = getmntent(fp)) != NULL) { 964 if (EQ(mp->mnt_type, MNTTYPE_IGNORE)) 965 continue; 966 if (stat(mp->mnt_dir, &st) < 0) 967 continue; 968 fstypes = srealloc(fstypes, (i+1) * sizeof *fstypes); 969 fstypes[i].fsdev = st.st_dev; 970 fstypes[i].fstype = strdup(mp->mnt_type); 971 i++; 972 } 973 endmntent(fp); 974 } 975 #endif /* __linux__ || _AIX || __hpux */ 976 977 /* 978 * First part of descend, called for any file found. 979 */ 980 static int descend(char *fname, struct anode *exlist, int level) 981 { 982 struct stat ost; 983 register char *c1; 984 int i; 985 int rv = 0; 986 987 if(statfn(fname, &Statb)<0) { 988 if (statfn != lstat && lstat(fname, &Statb) == 0) 989 nof: c1 = "cannot follow symbolic link %s: %s"; 990 else if (sysv3) 991 c1 = "stat() failed: %s: %s"; 992 else if (errno == ENOENT || errno == ENOTDIR) 993 c1 = "cannot open %s: %s"; 994 else 995 c1 = "stat() error %s: %s"; 996 pr(c1, Pathname, strerror(errno)); 997 status = 18; 998 return(0); 999 } 1000 if (level == 0 && HLflag == 'H' && (Statb.st_mode&S_IFMT) == S_IFLNK) { 1001 struct stat nst; 1002 if (stat(fname, &nst) == 0) 1003 Statb = nst; 1004 else if (errno == ELOOP) 1005 goto nof; 1006 } 1007 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || \ 1008 defined (__DragonFly__) || defined (__APPLE__) 1009 if (Statfs != NULL) { 1010 static struct statfs sf; 1011 if (statfs(fname, &sf) < 0) { 1012 pr("statfs() error %s: %s", Pathname, strerror(errno)); 1013 status = 18; 1014 return(0); 1015 } 1016 Statfs = sf.f_fstypename; 1017 } 1018 #endif /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */ 1019 if (Mount) { 1020 static dev_t curdev; 1021 if (level == 0) 1022 curdev = Statb.st_dev; 1023 else if (curdev != Statb.st_dev) 1024 return(0); 1025 } 1026 Prune = 0; 1027 if (!depth) { 1028 #if defined (__linux__) || defined (_AIX) || defined (__hpux) 1029 if (fstypes) 1030 getfscur(Statb.st_dev); 1031 #endif /* __linux__ || _AIX || __hpux */ 1032 if((*exlist->F)(exlist) && Print) 1033 puts(Pathname); 1034 } else 1035 ost = Statb; 1036 if(Prune || (Statb.st_mode&S_IFMT)!=S_IFDIR) 1037 goto reg; 1038 if (statfn != lstat) { 1039 for (i = 0; i < level; i++) 1040 if (Statb.st_dev == visited[i].v_dev && 1041 Statb.st_ino == visited[i].v_ino) { 1042 #ifdef SU3 1043 pr("Symbolic link loop at %s", Pathname); 1044 status = 18; 1045 #endif /* SU3 */ 1046 goto reg; 1047 } 1048 } 1049 if (level >= vismax) { 1050 vismax += 20; 1051 visited = srealloc(visited, sizeof *visited * vismax); 1052 } 1053 visited[level].v_dev = Statb.st_dev; 1054 visited[level].v_ino = Statb.st_ino; 1055 1056 rv = descend1(fname, exlist, level); 1057 1058 reg: 1059 if (depth) { 1060 Statb = ost; 1061 #if defined (__linux__) || defined (_AIX) || defined (__hpux) 1062 if (fstypes) 1063 getfscur(Statb.st_dev); 1064 #endif /* __linux__ || _AIX || __hpux */ 1065 if ((*exlist->F)(exlist) && Print) 1066 puts(Pathname); 1067 } 1068 return(rv); 1069 } 1070 1071 /* 1072 * Second part of descend, called for any directory found. 1073 */ 1074 static int descend1(char *fname, struct anode *exlist, int level) 1075 { 1076 int dir = 0; /* open directory */ 1077 register char *c1; 1078 struct getdb *db; 1079 register struct direc *dp; 1080 int endofname; 1081 int err; 1082 int oflags = O_RDONLY; 1083 1084 #ifdef O_DIRECTORY 1085 oflags |= O_DIRECTORY; 1086 #endif 1087 #ifdef O_NOFOLLOW 1088 if (statfn == lstat && (HLflag != 'H' || level > 0)) 1089 oflags |= O_NOFOLLOW; 1090 #endif 1091 if ((dir = open(fname, oflags)) < 0 || 1092 fcntl(dir, F_SETFD, FD_CLOEXEC) < 0 || 1093 fchdir(dir) < 0) { 1094 if (dir >= 0) 1095 close(dir); 1096 else if (errno == EMFILE && descend2(fname, exlist, level)) 1097 /* 1098 * A possible performance improvement would be to 1099 * call descend2() in the directory above, since 1100 * the current method involves one fork() call per 1101 * subdirectory at this level. The condition occurs 1102 * so rarely that it seems hardly worth optimization 1103 * though. 1104 */ 1105 return 0; 1106 pr("cannot open %s: %s", Pathname, strerror(errno)); 1107 status = 18; 1108 return 0; 1109 } 1110 if ((db = getdb_alloc(Pathname, dir)) == NULL) { 1111 write(2, "no memory\n", 10); 1112 _exit(077); 1113 } 1114 visited[level].v_db = db; 1115 visited[level].v_fd = dir; 1116 for(c1 = Pathname; *c1; ++c1); 1117 if(*(c1-1) == '/') 1118 --c1; 1119 endofname = c1 - Pathname; 1120 1121 while ((dp = getdir(db, &err)) != NULL) { 1122 if((dp->d_name[0]=='.' && dp->d_name[1]=='\0') || 1123 (dp->d_name[0]=='.' && 1124 dp->d_name[1]=='.' && dp->d_name[2]=='\0')) 1125 continue; 1126 setpath(&Pathname[endofname], dp->d_name, 1); 1127 Fname = &Pathname[endofname+1]; 1128 if(descend(Fname, exlist, level+1)) { 1129 if (fchdir(dir) < 0) 1130 er("bad directory tree"); 1131 } 1132 } 1133 Pathname[endofname] = '\0'; 1134 getdb_free(db); 1135 if (err) { 1136 pr("cannot read dir %s: %s", Pathname, strerror(errno)); 1137 status = 18; 1138 } 1139 close(dir); 1140 visited[level].v_fd = -1; 1141 return 1; 1142 } 1143 1144 /* 1145 * Third part of descend, called if the limit of open file descriptors 1146 * is exceeded (EMFILE). 1147 */ 1148 static int descend2(char *fname, struct anode *exlist, int level) 1149 { 1150 pid_t pid; 1151 int i; 1152 1153 if (Cpio || Execplus) 1154 trailer(exlist, 0); 1155 fflush(stdout); 1156 switch (pid = fork()) { 1157 case 0: 1158 for (i = 0; i < level-1; i++) { 1159 if (visited[i].v_fd >= 0) { 1160 getdb_free(visited[i].v_db); 1161 close(visited[i].v_fd); 1162 visited[i].v_fd = -1; 1163 } 1164 } 1165 status |= 0; 1166 descend1(fname, exlist, level); 1167 if (Cpio || Execplus) 1168 trailer(exlist, 0); 1169 exit(status); 1170 /*NOTREACHED*/ 1171 default: 1172 while (waitpid(pid, &i, 0) != pid); 1173 if (i && WIFSIGNALED(i)) { 1174 struct rlimit rl; 1175 1176 rl.rlim_cur = rl.rlim_max = 0; 1177 setrlimit(RLIMIT_CORE, &rl); 1178 raise(WTERMSIG(i)); 1179 pause(); 1180 } 1181 if (i) 1182 status |= WEXITSTATUS(i); 1183 return 1; 1184 case -1: 1185 return 0; 1186 } 1187 } 1188 static void setpath(char *eos, const char *fn, int slash) 1189 { 1190 static char *pathend; 1191 char *opath; 1192 1193 for (;;) { 1194 if (eos >= pathend) { 1195 pathend += 14; 1196 opath = Pathname; 1197 Pathname = srealloc(Pathname, pathend - Pathname); 1198 eos += Pathname - opath; 1199 pathend += Pathname - opath; 1200 } 1201 if (slash) { 1202 *eos++ = '/'; 1203 slash = 0; 1204 } else 1205 if ((*eos++ = *fn++) == '\0') 1206 break; 1207 } 1208 } 1209 1210 static void pr(const char *s, ...) 1211 { 1212 va_list ap; 1213 1214 fprintf(stderr, "%s: ", progname); 1215 va_start(ap, s); 1216 vfprintf(stderr, s, ap); 1217 va_end(ap); 1218 fprintf(stderr, "\n"); 1219 } 1220 1221 static void er(const char *s, ...) 1222 { 1223 va_list ap; 1224 1225 fprintf(stderr, "%s: ", progname); 1226 va_start(ap, s); 1227 vfprintf(stderr, s, ap); 1228 va_end(ap); 1229 fprintf(stderr, "\n"); 1230 exit(1); 1231 } 1232 1233 static void usage(void) 1234 { 1235 er("path-list predicate-list"); 1236 } 1237 1238 static void *srealloc(void *op, size_t n) 1239 { 1240 void *np; 1241 1242 if ((np = realloc(op, n)) == NULL) { 1243 write(2, "no memory\n", 10); 1244 _exit(077); 1245 } 1246 return np; 1247 } 1248 1249 static void mkcpio(struct anode *p, const char *b, int ascii) 1250 { 1251 int fd, pd[2]; 1252 char flags[20], *cp; 1253 1254 p->F = cpio; 1255 if (*b == '\0') 1256 return; 1257 depth = 1; 1258 Print = 0; 1259 Cpio = 1; 1260 if (pipe(pd) < 0 || (p->l.fp = fdopen(pd[1], "w")) == NULL) 1261 er("pipe() %s", strerror(errno)); 1262 if ((fd = creat(b, 0666)) < 0) 1263 er("cannot create %s", b); 1264 switch (p->r.pid = fork()) { 1265 case -1: 1266 er("can't fork"); 1267 /*NOTREACHED*/ 1268 case 0: 1269 dup2(pd[0], 0); 1270 close(pd[0]); 1271 close(pd[1]); 1272 dup2(fd, 1); 1273 close(fd); 1274 cp = flags; 1275 *cp++ = '-'; 1276 *cp++ = 'o'; 1277 *cp++ = 'B'; 1278 if (ascii) 1279 *cp++ = 'c'; 1280 if (statfn == stat) 1281 *cp++ = 'L'; 1282 *cp = '\0'; 1283 execlp("cpio", "cpio", flags, NULL); 1284 pr("cannot exec cpio: %s", strerror(errno)); 1285 _exit(0177); 1286 /*NOTREACHED*/ 1287 } 1288 close(pd[0]); 1289 close(fd); 1290 } 1291 1292 static void 1293 trailer(register struct anode *p, int termcpio) 1294 { 1295 char *Opath = Pathname; 1296 Pathname = 0; 1297 if (p->F == or || p->F == and) { 1298 trailer(p->l.L, termcpio); 1299 trailer(p->r.R, termcpio); 1300 } else if (p->F == not) 1301 trailer(p->l.L, termcpio); 1302 else if (p->F == cpio) { 1303 if (termcpio) { 1304 int s; 1305 1306 fclose(p->l.fp); 1307 while (waitpid(p->r.pid, &s, 0) != p->r.pid); 1308 if (s) { 1309 if (WIFEXITED(s)) 1310 status |= WEXITSTATUS(s); 1311 else if (WIFSIGNALED(s)) 1312 status |= WTERMSIG(s) | 0200; 1313 } 1314 } else 1315 fflush(p->l.fp); 1316 } else if (p->F == exeq && p->r.a) 1317 exeq(p); 1318 Pathname = Opath; 1319 } 1320 1321 static void 1322 mknewer(struct anode *p, const char *b, int (*f)(struct anode *)) 1323 { 1324 if (*b && stat(b, &Statb) < 0) 1325 er("cannot access %s", b); 1326 p->l.t = Statb.st_mtime; 1327 p->F = f; 1328 } 1329 1330 /* 1331 * Changes by Gunnar Ritter, Freiburg i. Br., Germany, September 2003. 1332 */ 1333 /* from Unix 7th Edition /usr/src/cmd/chmod.c */ 1334 /* 1335 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. 1336 * 1337 * Redistribution and use in source and binary forms, with or without 1338 * modification, are permitted provided that the following conditions 1339 * are met: 1340 * Redistributions of source code and documentation must retain the 1341 * above copyright notice, this list of conditions and the following 1342 * disclaimer. 1343 * Redistributions in binary form must reproduce the above copyright 1344 * notice, this list of conditions and the following disclaimer in the 1345 * documentation and/or other materials provided with the distribution. 1346 * All advertising materials mentioning features or use of this software 1347 * must display the following acknowledgement: 1348 * This product includes software developed or owned by Caldera 1349 * International, Inc. 1350 * Neither the name of Caldera International, Inc. nor the names of 1351 * other contributors may be used to endorse or promote products 1352 * derived from this software without specific prior written permission. 1353 * 1354 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 1355 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 1356 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1357 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1358 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE 1359 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR 1360 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1361 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 1362 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 1363 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 1364 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 1365 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1366 */ 1367 1368 #define USER 05700 /* user's bits */ 1369 #define GROUP 02070 /* group's bits */ 1370 #define OTHER 00007 /* other's bits */ 1371 #define ALL 07777 /* all */ 1372 1373 #define READ 00444 /* read permit */ 1374 #define WRITE 00222 /* write permit */ 1375 #define EXEC 00111 /* exec permit */ 1376 #define SETID 06000 /* set[ug]id */ 1377 #define STICKY 01000 /* sticky bit */ 1378 1379 #ifndef S_ENFMT 1380 #define S_ENFMT 02000 /* mandatory locking bit */ 1381 #endif 1382 1383 static mode_t absol(const char **); 1384 static mode_t who(const char **, mode_t *); 1385 static int what(const char **); 1386 static mode_t where(const char **, mode_t, int *, int *, const mode_t); 1387 1388 static mode_t 1389 newmode(const char *ms, const mode_t pm) 1390 { 1391 register mode_t o, m, b; 1392 int lock, setsgid = 0, cleared = 0, copy = 0; 1393 mode_t nm, om, mm; 1394 const char *mo = ms; 1395 1396 nm = om = pm; 1397 m = absol(&ms); 1398 if (!*ms) { 1399 nm = m; 1400 goto out; 1401 } 1402 if ((lock = (nm&S_IFMT) != S_IFDIR && (nm&(S_ENFMT|S_IXGRP)) == S_ENFMT) 1403 == 01) 1404 nm &= ~(mode_t)S_ENFMT; 1405 do { 1406 m = who(&ms, &mm); 1407 while (o = what(&ms)) { 1408 b = where(&ms, nm, &lock, ©, pm); 1409 switch (o) { 1410 case '+': 1411 nm |= b & m & ~mm; 1412 if (b & S_ISGID) 1413 setsgid = 1; 1414 if (lock & 04) 1415 lock |= 02; 1416 break; 1417 case '-': 1418 nm &= ~(b & m & ~mm); 1419 if (b & S_ISGID) 1420 setsgid = 1; 1421 if (lock & 04) 1422 lock = 0; 1423 break; 1424 case '=': 1425 nm &= ~m; 1426 nm |= b & m & ~mm; 1427 lock &= ~01; 1428 if (lock & 04) 1429 lock |= 02; 1430 om = 0; 1431 if (copy == 0) 1432 cleared = 1; 1433 break; 1434 } 1435 lock &= ~04; 1436 } 1437 } while (*ms++ == ','); 1438 if (*--ms) 1439 er("bad permissions: %s", mo); 1440 out: if (pm & S_IFDIR) { 1441 if ((pm & S_ISGID) && setsgid == 0) 1442 nm |= S_ISGID; 1443 else if ((nm & S_ISGID) && setsgid == 0) 1444 nm &= ~(mode_t)S_ISGID; 1445 } 1446 return(nm); 1447 } 1448 1449 static mode_t 1450 absol(const char **ms) 1451 { 1452 register int c, i; 1453 1454 i = 0; 1455 while ((c = *(*ms)++) >= '0' && c <= '7') 1456 i = (i << 3) + (c - '0'); 1457 (*ms)--; 1458 return(i); 1459 } 1460 1461 static mode_t 1462 who(const char **ms, mode_t *mp) 1463 { 1464 register int m; 1465 1466 m = 0; 1467 *mp = 0; 1468 for (;;) switch (*(*ms)++) { 1469 case 'u': 1470 m |= USER; 1471 continue; 1472 case 'g': 1473 m |= GROUP; 1474 continue; 1475 case 'o': 1476 m |= OTHER; 1477 continue; 1478 case 'a': 1479 m |= ALL; 1480 continue; 1481 default: 1482 (*ms)--; 1483 if (m == 0) { 1484 m = ALL; 1485 *mp = um; 1486 } 1487 return m; 1488 } 1489 } 1490 1491 static int 1492 what(const char **ms) 1493 { 1494 switch (**ms) { 1495 case '+': 1496 case '-': 1497 case '=': 1498 return *(*ms)++; 1499 } 1500 return(0); 1501 } 1502 1503 static mode_t 1504 where(const char **ms, mode_t om, int *lock, int *copy, const mode_t pm) 1505 { 1506 register mode_t m; 1507 1508 m = 0; 1509 *copy = 0; 1510 switch (**ms) { 1511 case 'u': 1512 m = (om & USER) >> 6; 1513 goto dup; 1514 case 'g': 1515 m = (om & GROUP) >> 3; 1516 goto dup; 1517 case 'o': 1518 m = (om & OTHER); 1519 dup: 1520 *copy = 1; 1521 m &= (READ|WRITE|EXEC); 1522 m |= (m << 3) | (m << 6); 1523 ++(*ms); 1524 return m; 1525 } 1526 for (;;) switch (*(*ms)++) { 1527 case 'r': 1528 m |= READ; 1529 continue; 1530 case 'w': 1531 m |= WRITE; 1532 continue; 1533 case 'x': 1534 m |= EXEC; 1535 continue; 1536 case 'X': 1537 if ((pm&S_IFMT) == S_IFDIR || (pm & EXEC)) 1538 m |= EXEC; 1539 continue; 1540 case 'l': 1541 if ((pm&S_IFMT) != S_IFDIR) 1542 *lock |= 04; 1543 continue; 1544 case 's': 1545 m |= SETID; 1546 continue; 1547 case 't': 1548 m |= STICKY; 1549 continue; 1550 default: 1551 (*ms)--; 1552 return m; 1553 } 1554 }