1*18277Sralph static char *sccsid = "@(#)rm.c 4.14 (Berkeley) 03/08/85"; 21083Sbill 3*18277Sralph /* 4*18277Sralph * rm - for ReMoving files, directories & trees. 5*18277Sralph */ 6*18277Sralph 71083Sbill #include <stdio.h> 86413Smckusic #include <sys/param.h> 91083Sbill #include <sys/stat.h> 1013491Ssam #include <sys/dir.h> 11*18277Sralph #include <sys/file.h> 121083Sbill 13*18277Sralph int fflg; /* -f force - supress error messages */ 14*18277Sralph int iflg; /* -i interrogate user on each file */ 15*18277Sralph int rflg; /* -r recurse */ 161083Sbill 17*18277Sralph int errcode; /* true if errors occured */ 18*18277Sralph 19*18277Sralph char *strcpy(); 20*18277Sralph 211083Sbill main(argc, argv) 22*18277Sralph char *argv[]; 231083Sbill { 241083Sbill register char *arg; 251083Sbill 26*18277Sralph fflg = !isatty(0); 271083Sbill iflg = 0; 281083Sbill rflg = 0; 29*18277Sralph while (argc > 1 && argv[1][0] == '-') { 301083Sbill arg = *++argv; 311083Sbill argc--; 321932Sroot 331932Sroot /* 341932Sroot * all files following a null option are considered file names 351932Sroot */ 36*18277Sralph if (arg[1] == '\0') 37*18277Sralph break; 381932Sroot 39*18277Sralph while (*++arg != '\0') 401083Sbill switch(*arg) { 411083Sbill case 'f': 421083Sbill fflg++; 431083Sbill break; 44*18277Sralph 451083Sbill case 'i': 461083Sbill iflg++; 471083Sbill break; 48*18277Sralph 4917964Sserge case 'R': 501083Sbill case 'r': 511083Sbill rflg++; 521083Sbill break; 53*18277Sralph 541083Sbill default: 55*18277Sralph fprintf(stderr, "usage: rm [-rif] file ...\n"); 561083Sbill exit(1); 571083Sbill } 581083Sbill } 5917964Sserge 6017964Sserge if (argc < 2) { 6117964Sserge fprintf(stderr, "usage: rm [-rif] file ...\n"); 6217964Sserge exit(1); 6317964Sserge } 6417964Sserge 65*18277Sralph while (--argc > 0) 66*18277Sralph (void) rm(*++argv, 0); 671083Sbill 68*18277Sralph exit(errcode != 0); 691083Sbill } 701083Sbill 71*18277Sralph struct nambuf { 72*18277Sralph char *name; /* pointer to name */ 73*18277Sralph struct nambuf *next; /* linked list of names */ 74*18277Sralph } path, *pathp; 75*18277Sralph 76*18277Sralph /* 77*18277Sralph * Return TRUE if sucessful. Recursive with -r (rflg) 78*18277Sralph */ 79*18277Sralph rm(arg, level) 80*18277Sralph char arg[]; 811083Sbill { 82*18277Sralph int ok; /* true if recursive rm succeeded */ 83*18277Sralph struct stat buf; /* for finding out what a file is */ 84*18277Sralph struct direct *dp; /* for reading a directory */ 85*18277Sralph DIR *dirp; /* for reading a directory */ 86*18277Sralph char name[MAXNAMLEN + 1]; /* buffer for file name */ 87*18277Sralph char prevname[MAXNAMLEN + 1]; /* previous name for -r */ 88*18277Sralph struct nambuf nambuf, *pp; 891083Sbill 90*18277Sralph if (dotname(arg)) { 91*18277Sralph fprintf(stderr, "rm: cannot remove `.' or `..'\n"); 92*18277Sralph return (0); 931083Sbill } 94*18277Sralph if (level == 0) { 95*18277Sralph path.name = arg; 96*18277Sralph path.next = NULL; 97*18277Sralph pathp = &path; 98*18277Sralph } 99*18277Sralph if (lstat(arg, &buf)) { 100*18277Sralph if (!fflg) 101*18277Sralph error("nonexistent"); 102*18277Sralph errcode++; 103*18277Sralph return (0); /* error */ 104*18277Sralph } 1051083Sbill if ((buf.st_mode&S_IFMT) == S_IFDIR) { 106*18277Sralph if (!rflg) { 107*18277Sralph error("directory"); 108*18277Sralph errcode++; 109*18277Sralph return (0); 110*18277Sralph } 111*18277Sralph if (access(arg, R_OK|W_OK|X_OK) != 0) { 112*18277Sralph if (rmdir(arg) == 0) 113*18277Sralph return (1); /* salvaged: removed empty dir */ 114*18277Sralph if (!fflg) 115*18277Sralph error("not changed"); 116*18277Sralph errcode++; 117*18277Sralph return (0); /* error */ 118*18277Sralph } 119*18277Sralph if (iflg && level != 0) { 120*18277Sralph if (!yes("remove directory")) 121*18277Sralph return (0); /* didn't remove everything */ 122*18277Sralph } 123*18277Sralph if (chdir(arg) < 0 || (dirp = opendir(".")) == NULL) { 124*18277Sralph if (!fflg) 125*18277Sralph error("cannot read?"); 126*18277Sralph errcode++; 127*18277Sralph return (0); 128*18277Sralph } 129*18277Sralph nambuf.name = name; 130*18277Sralph nambuf.next = NULL; 131*18277Sralph pathp->next = &nambuf; 132*18277Sralph pp = pathp; 133*18277Sralph pathp = &nambuf; 134*18277Sralph prevname[0] = '\0'; 135*18277Sralph while ((dp = readdir(dirp)) != NULL) { 136*18277Sralph if (dotname(dp->d_name)) { 137*18277Sralph strcpy(prevname, dp->d_name); 138*18277Sralph continue; 139*18277Sralph } 140*18277Sralph strcpy(name, dp->d_name); 141*18277Sralph closedir(dirp); 142*18277Sralph ok = rm(name, level + 1); 143*18277Sralph if ((dirp = opendir(".")) == NULL) { 144*18277Sralph if (!fflg) 145*18277Sralph error("cannot read?"); 1461083Sbill errcode++; 147*18277Sralph break; 1481083Sbill } 149*18277Sralph /* pick up where we left off */ 150*18277Sralph if (prevname[0] != '\0') { 151*18277Sralph while ((dp = readdir(dirp)) != NULL && 152*18277Sralph strcmp(prevname, dp->d_name) != 0) 153*18277Sralph ; 1541083Sbill } 155*18277Sralph /* skip the one we just failed to delete */ 156*18277Sralph if (!ok) { 157*18277Sralph dp = readdir(dirp); 158*18277Sralph if (dp != NULL && strcmp(name, dp->d_name) != 0) 159*18277Sralph error("internal synchronization error"); 160*18277Sralph strcpy(prevname, name); 1611083Sbill } 1621083Sbill } 163*18277Sralph closedir(dirp); 164*18277Sralph pathp = pp; 165*18277Sralph pathp->next = NULL; 166*18277Sralph if (chdir("..") < 0) { 167*18277Sralph if (!fflg) 168*18277Sralph error("cannot cd to '..'?"); 169*18277Sralph errcode++; 170*18277Sralph return (0); 171*18277Sralph } 172*18277Sralph if (iflg) { 173*18277Sralph if (!yes("remove")) 174*18277Sralph return (0); 175*18277Sralph } 176*18277Sralph if (rmdir(arg) < 0) { 177*18277Sralph if (!fflg || iflg) 178*18277Sralph error("not removed"); 179*18277Sralph errcode++; 180*18277Sralph return (0); 181*18277Sralph } 182*18277Sralph return (1); 1831083Sbill } 1841083Sbill 185*18277Sralph if (iflg) { 186*18277Sralph if (!yes("remove")) 187*18277Sralph return (0); 188*18277Sralph } else if (!fflg) { 189*18277Sralph if ((buf.st_mode&S_IFMT) != S_IFLNK && access(arg, W_OK) < 0) { 190*18277Sralph sprintf(name, "override protection %o for", 191*18277Sralph buf.st_mode&0777); 192*18277Sralph if (!yes(name)) 193*18277Sralph return (0); 1941083Sbill } 1951083Sbill } 196*18277Sralph if (unlink(arg) < 0) { 197*18277Sralph if (!fflg || iflg) 198*18277Sralph error("not removed"); 199*18277Sralph errcode++; 200*18277Sralph return (0); 2011083Sbill } 202*18277Sralph return (1); 2031083Sbill } 2041083Sbill 205*18277Sralph /* 206*18277Sralph * boolean: is it "." or ".." ? 207*18277Sralph */ 2081083Sbill dotname(s) 209*18277Sralph char *s; 2101083Sbill { 211*18277Sralph if (s[0] == '.') 212*18277Sralph if (s[1] == '.') 213*18277Sralph if (s[2] == '\0') 214*18277Sralph return (1); 2151083Sbill else 216*18277Sralph return (0); 217*18277Sralph else if (s[1] == '\0') 218*18277Sralph return (1); 219*18277Sralph return (0); 2201083Sbill } 2211083Sbill 222*18277Sralph /* 223*18277Sralph * Get a yes/no answer from the user. 224*18277Sralph */ 225*18277Sralph yes(msg) 226*18277Sralph char *msg; 2271083Sbill { 228*18277Sralph register struct nambuf *pp; 2291083Sbill int i, b; 2301083Sbill 231*18277Sralph printf("rm: %s %s", msg, path.name); 232*18277Sralph for (pp = &path; pp->next != NULL; pp = pp->next) 233*18277Sralph printf("/%s", pp->next->name); 234*18277Sralph printf("? "); 2351083Sbill i = b = getchar(); 236*18277Sralph while (b != '\n' && b != EOF) 2371083Sbill b = getchar(); 238*18277Sralph return (i == 'y'); 2391083Sbill } 240*18277Sralph 241*18277Sralph /* 242*18277Sralph * Print the current path and error message. 243*18277Sralph */ 244*18277Sralph error(msg) 245*18277Sralph char *msg; 246*18277Sralph { 247*18277Sralph register struct nambuf *pp; 248*18277Sralph 249*18277Sralph fprintf(stderr, "rm: %s", path.name); 250*18277Sralph for (pp = &path; pp->next != NULL; pp = pp->next) 251*18277Sralph fprintf(stderr, "/%s", pp->next->name); 252*18277Sralph fprintf(stderr, ": %s\n", msg); 253*18277Sralph } 254