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