# /* UCB rmtree * rmtree dir . . . * author: Kurt Shoens * recursively removes files and directories * in a subtree. The -v flag prevents it from * removing the final directory, ie the one * you specify. The incredible danger of * this program must by now be apparent to you. It * asks you if you are sure on each argument. */ #define ENOTDIR 20 #define ENOENT 2 #define STACKSIZE 1024 int vflag; int errs; int fflag; int cflag; int active; /* set warnflag true to get "last chance before . . . " */ int warnflag 1; char pathname[STACKSIZE]; char *pathptr; char *myname; extern errno; main(ct,av) char **av; { int level,i,thiser; char crap[36]; setuid(getuid()); myname = av[0]; /* * if (getuid()) * { * printf("sorry, not super user\n"); * exit(1); * } */ if (ct<2) { usage(myname); exit(9); } for (i=1;i<ct;++i) { if (*av[i] == '-') { process(av[i]); continue; } ++active; if (stat(av[i],crap)) { perror(av[i]); errs++; continue; } if (!dir(av[i])) { errno = ENOTDIR; perror(av[i]); errs++; } else { if (warning(av[i],warnflag && !fflag)) { if (cflag && !vflag) chmod(av[i], 0700); pathptr = pathname; pushstr(av[i]); thiser = descend(); errs =+ thiser; if (!vflag && !thiser) errs =+ rmdir(av[i]); } } } if (!active) { usage(myname); exit(9); } exit(errs); } descend() { int offset,j,err,markerr,xcnt; static f,inum,*ip; register char *cp; char name[16]; markerr=0; offset=16; f=open(pathname,0); if (f==-1) { prs(pathname); prs(": no read permission\n"); return(1); } j=read(f,name,16); xcnt=0; while (j) { ip=name; inum= *ip; if (!scomp(&name[2],".") && !scomp(&name[2],"..") && inum) { if (!xcnt++) if (access(pathname,3)) { prs(pathname); prs(": need both X and W permission\n"); close(f); return(1); } pushstr(&name[2]); if (dir(pathname)) { close(f); if (cflag) chmod(pathname, 0700); err=descend(); if (!err) rmdir(pathname); else markerr=1; popstr(); f = open(pathname,0); seek(f,offset,0); } else { /* if unlink fails, keeps going ?? */ if (rm(pathname)) markerr=1; popstr(); } } j=read(f,name,16); offset=offset+16; } close(f); return(markerr); } rmdir(str) char *str; { int p; p = fork(); if (!p) { execl("/bin/rmdir","rmdir",str,0); perror("/bin/rmdir"); exit(1); } else wait(&p); return(p); } rm(f) char *f; { if (quota(f) && vflag) return(1); if (unlink(f)) { perror(f); return(1); } return(0); } popstr() { --pathptr; while (*pathptr != '/') --pathptr; while (*pathptr == '/') --pathptr; *++pathptr = 0; } dir(n) char *n; { struct inode { char minor; /* +0: minor device of i-node */ char major; /* +1: major device */ int inumber; /* +2 */ int flags; /* +4: see below */ char nlinks; /* +6: number of links to file */ char uid; /* +7: user ID of owner */ char gid; /* +8: group ID of owner */ char size0; /* +9: high byte of 24-bit size */ int size1; /* +10: low word of 24-bit size */ int addr[8]; /* +12: block numbers or device number */ int actime[2]; /* +28: time of last access */ int modtime[2]; /* +32: time of last modification */ } buf; if (stat(n,&buf)) return(0); return((buf.flags & 060000) == 040000); } quota(n) char *n; { struct inode { char minor; /* +0: minor device of i-node */ char major; /* +1: major device */ int inumber; /* +2 */ int flags; /* +4: see below */ char nlinks; /* +6: number of links to file */ char uid; /* +7: user ID of owner */ char gid; /* +8: group ID of owner */ char size0; /* +9: high byte of 24-bit size */ int size1; /* +10: low word of 24-bit size */ int addr[8]; /* +12: block numbers or device number */ int actime[2]; /* +28: time of last access */ int modtime[2]; /* +32: time of last modification */ } buf; if (stat(n,&buf)) return(0); return((buf.flags & 060000) == 020000 && buf.addr[0] == -1); } scomp(n1,n2) char *n1,*n2; { char left,right; left= *n1; right= *n2; while (left && right) { if (left!=right) return(0); ++n1; ++n2; left= *n1; right= *n2; } return(left==right); } actual(str) char *str; { register char *f; register slash; f = str; if (*f == '/') return(f); slash = 0; while (*f) if (*f++ == '/') slash++; if (!slash) return(str); while (*f != '/') --f; ++f; return(f); } warning(file,f) char *file; { char line[20]; if (!f) return; if (gtty(0,line)) return; printf("last chance before OBLITERATING %s\n",file); printf("ok? "); line[read(0,line,20)] = 0; return(*line == 'y' || *line == 'Y'); } process(str) char *str; { while (*str) switch(*str++) { case 'c': cflag++; break; case 'v': vflag = 1; break; case 'f': fflag = 1; break; case 's': fflag = 0; break; case 'a': vflag = 0; break; case '-': break; default: printf("unknown switch: %c\n", *--str); exit(1); } } usage(str) char *str; { printf("Usage: %s [ -acfsv ] dir ...\n",str); errs++; } prs(str) char *str; { register char *f; f = str; while (*f) ++f; write(2, str, f-str); } pushstr(str) char *str; { if (pathptr != pathname) *pathptr++ = '/'; while (*pathptr++ = *str++) if (pathptr >= pathname + STACKSIZE) panic("path name too long"); pathptr--; } panic(str) char *str; { prs("PANIC: "); prs(str); prs("\n"); exit(1); }