1: static char *sccsid = "@(#)rm.c 4.18 (Berkeley) 1/6/86"; 2: 3: /* 4: * rm - for ReMoving files, directories & trees. 5: */ 6: 7: #include <stdio.h> 8: #include <sys/param.h> 9: #include <sys/stat.h> 10: #include <sys/dir.h> 11: #include <sys/file.h> 12: 13: int fflg; /* -f force - supress error messages */ 14: int iflg; /* -i interrogate user on each file */ 15: int rflg; /* -r recurse */ 16: 17: int errcode; /* true if errors occured */ 18: 19: char *strcpy(), *malloc(), *realloc(); 20: 21: main(argc, argv) 22: char *argv[]; 23: { 24: register char *arg; 25: 26: fflg = !isatty(0); 27: iflg = 0; 28: rflg = 0; 29: while (argc > 1 && argv[1][0] == '-') { 30: arg = *++argv; 31: argc--; 32: 33: /* 34: * all files following a null option are considered file names 35: */ 36: if (arg[1] == '\0') 37: break; 38: 39: while (*++arg != '\0') 40: switch(*arg) { 41: case 'f': 42: fflg++; 43: break; 44: 45: case 'i': 46: iflg++; 47: break; 48: 49: case 'R': 50: case 'r': 51: rflg++; 52: break; 53: 54: default: 55: fprintf(stderr, "usage: rm [-rif] file ...\n"); 56: exit(1); 57: } 58: } 59: 60: if (argc < 2 && !fflg) { 61: fprintf(stderr, "usage: rm [-rif] file ...\n"); 62: exit(1); 63: } 64: 65: while (--argc > 0) 66: (void) rm(*++argv, 0); 67: 68: exit(errcode != 0); 69: } 70: 71: char *path; /* pointer to malloc'ed buffer for path */ 72: char *pathp; /* current pointer to end of path */ 73: int pathsz; /* size of path */ 74: 75: /* 76: * Return TRUE if sucessful. Recursive with -r (rflg) 77: */ 78: rm(arg, level) 79: char arg[]; 80: { 81: int ok; /* true if recursive rm succeeded */ 82: struct stat buf; /* for finding out what a file is */ 83: struct direct *dp; /* for reading a directory */ 84: DIR *dirp; /* for reading a directory */ 85: char prevname[MAXNAMLEN + 1]; /* previous name for -r */ 86: char *cp; 87: 88: if (dotname(arg)) { 89: fprintf(stderr, "rm: cannot remove `.' or `..'\n"); 90: return (0); 91: } 92: if (lstat(arg, &buf)) { 93: if (!fflg) { 94: fprintf(stderr, "rm: %s nonexistent\n", arg); 95: errcode++; 96: } 97: return (0); /* error */ 98: } 99: if ((buf.st_mode&S_IFMT) == S_IFDIR) { 100: if (!rflg) { 101: if (!fflg) { 102: fprintf(stderr, "rm: %s directory\n", arg); 103: errcode++; 104: } 105: return (0); 106: } 107: if (iflg && level != 0) { 108: printf("rm: remove directory %s? ", arg); 109: if (!yes()) 110: return (0); /* didn't remove everything */ 111: } 112: if (access(arg, R_OK|W_OK|X_OK) != 0) { 113: if (rmdir(arg) == 0) 114: return (1); /* salvaged: removed empty dir */ 115: if (!fflg) { 116: fprintf(stderr, "rm: %s not changed\n", arg); 117: errcode++; 118: } 119: return (0); /* error */ 120: } 121: if ((dirp = opendir(arg)) == NULL) { 122: if (!fflg) { 123: fprintf(stderr, "rm: cannot read %s?\n", arg); 124: errcode++; 125: } 126: return (0); 127: } 128: if (level == 0) 129: append(arg); 130: prevname[0] = '\0'; 131: while ((dp = readdir(dirp)) != NULL) { 132: if (dotname(dp->d_name)) { 133: strcpy(prevname, dp->d_name); 134: continue; 135: } 136: append(dp->d_name); 137: closedir(dirp); 138: ok = rm(path, level + 1); 139: for (cp = pathp; *--cp != '/' && cp > path; ) 140: ; 141: pathp = cp; 142: *cp++ = '\0'; 143: if ((dirp = opendir(arg)) == NULL) { 144: if (!fflg) { 145: fprintf(stderr, "rm: cannot read %s?\n", arg); 146: errcode++; 147: } 148: break; 149: } 150: /* pick up where we left off */ 151: if (prevname[0] != '\0') { 152: while ((dp = readdir(dirp)) != NULL && 153: strcmp(prevname, dp->d_name) != 0) 154: ; 155: } 156: /* skip the one we just failed to delete */ 157: if (!ok) { 158: dp = readdir(dirp); 159: if (dp != NULL && strcmp(cp, dp->d_name)) { 160: fprintf(stderr, 161: "rm: internal synchronization error: %s, %s, %s\n", 162: arg, cp, dp->d_name); 163: } 164: strcpy(prevname, dp->d_name); 165: } 166: } 167: closedir(dirp); 168: if (level == 0) { 169: pathp = path; 170: *pathp = '\0'; 171: } 172: if (iflg) { 173: printf("rm: remove %s? ", arg); 174: if (!yes()) 175: return (0); 176: } 177: if (rmdir(arg) < 0) { 178: if (!fflg || iflg) { 179: fprintf(stderr, "rm: %s not removed\n", arg); 180: errcode++; 181: } 182: return (0); 183: } 184: return (1); 185: } 186: 187: if (iflg) { 188: printf("rm: remove %s? ", arg); 189: if (!yes()) 190: return (0); 191: } else if (!fflg) { 192: if ((buf.st_mode&S_IFMT) != S_IFLNK && access(arg, W_OK) < 0) { 193: printf("rm: override protection %o for %s? ", 194: buf.st_mode&0777, arg); 195: if (!yes()) 196: return (0); 197: } 198: } 199: if (unlink(arg) < 0) { 200: if (!fflg || iflg) { 201: fprintf(stderr, "rm: %s not removed\n", arg); 202: errcode++; 203: } 204: return (0); 205: } 206: return (1); 207: } 208: 209: /* 210: * boolean: is it "." or ".." ? 211: */ 212: dotname(s) 213: char *s; 214: { 215: if (s[0] == '.') 216: if (s[1] == '.') 217: if (s[2] == '\0') 218: return (1); 219: else 220: return (0); 221: else if (s[1] == '\0') 222: return (1); 223: return (0); 224: } 225: 226: /* 227: * Get a yes/no answer from the user. 228: */ 229: yes() 230: { 231: int i, b; 232: 233: i = b = getchar(); 234: while (b != '\n' && b != EOF) 235: b = getchar(); 236: return (i == 'y'); 237: } 238: 239: /* 240: * Append 'name' to 'path'. 241: */ 242: append(name) 243: char *name; 244: { 245: register int n; 246: 247: n = strlen(name); 248: if (path == NULL) { 249: pathsz = MAXNAMLEN + MAXPATHLEN + 2; 250: if ((path = malloc(pathsz)) == NULL) { 251: fprintf(stderr, "rm: ran out of memory\n"); 252: exit(1); 253: } 254: pathp = path; 255: } else if (pathp + n + 2 > path + pathsz) { 256: fprintf(stderr, "rm: path name too long: %s\n", path); 257: exit(1); 258: } else if (pathp != path && pathp[-1] != '/') 259: *pathp++ = '/'; 260: strcpy(pathp, name); 261: pathp += n; 262: }