1 static char *sccsid = "@(#)rm.c 4.18 (Berkeley) 01/06/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 } 263