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