1 static char *sccsid = "@(#)rm.c 4.22 (Berkeley) 04/21/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(), *malloc(); 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; 77 78 if (isdot(arg)) { 79 fprintf(stderr, "rm: cannot remove `.' or `..'\n"); 80 return (0); 81 } 82 if (lstat(arg, &buf)) { 83 if (!fflg) { 84 fprintf(stderr, "rm: %s nonexistent\n", arg); 85 errcode++; 86 } 87 return (0); /* error */ 88 } 89 if ((buf.st_mode&S_IFMT) == S_IFDIR) { 90 if (!rflg) { 91 if (!fflg) { 92 fprintf(stderr, "rm: %s directory\n", arg); 93 errcode++; 94 } 95 return (0); 96 } 97 if (iflg && level != 0) { 98 printf("rm: remove directory %s? ", arg); 99 if (!yes()) 100 return (0); /* didn't remove everything */ 101 } 102 if (access(arg, R_OK|W_OK|X_OK) != 0) { 103 if (rmdir(arg) == 0) 104 return (1); /* salvaged: removed empty dir */ 105 if (!fflg) { 106 fprintf(stderr, "rm: %s not changed\n", arg); 107 errcode++; 108 } 109 return (0); /* error */ 110 } 111 if ((dirp = opendir(arg)) == NULL) { 112 if (!fflg) { 113 fprintf(stderr, "rm: cannot read %s?\n", arg); 114 errcode++; 115 } 116 return (0); 117 } 118 if (level == 0) 119 append(arg); 120 prevname[0] = '\0'; 121 while ((dp = readdir(dirp)) != NULL) { 122 if (isdot(dp->d_name)) { 123 strcpy(prevname, dp->d_name); 124 continue; 125 } 126 append(dp->d_name); 127 closedir(dirp); 128 ok = rm(path, level + 1); 129 for (cp = pathp; *--cp != '/' && cp > path; ) 130 ; 131 pathp = cp; 132 *cp++ = '\0'; 133 if ((dirp = opendir(arg)) == NULL) { 134 if (!fflg) { 135 fprintf(stderr, "rm: cannot read %s?\n", arg); 136 errcode++; 137 } 138 break; 139 } 140 /* pick up where we left off */ 141 if (prevname[0] != '\0') { 142 while ((dp = readdir(dirp)) != NULL && 143 strcmp(prevname, dp->d_name) != 0) 144 ; 145 } 146 /* skip the one we just failed to delete */ 147 if (!ok) { 148 dp = readdir(dirp); 149 if (dp != NULL && strcmp(cp, dp->d_name)) { 150 fprintf(stderr, 151 "rm: internal synchronization error: %s, %s, %s\n", 152 arg, cp, dp->d_name); 153 } 154 strcpy(prevname, dp->d_name); 155 } 156 } 157 closedir(dirp); 158 if (level == 0) { 159 pathp = path; 160 *pathp = '\0'; 161 } 162 if (iflg) { 163 printf("rm: remove %s? ", arg); 164 if (!yes()) 165 return (0); 166 } 167 if (rmdir(arg) < 0) { 168 if (!fflg || iflg) { 169 fprintf(stderr, "rm: %s not removed\n", arg); 170 errcode++; 171 } 172 return (0); 173 } 174 return (1); 175 } 176 177 if (!fflg) { 178 if ((buf.st_mode&S_IFMT) != S_IFLNK && access(arg, W_OK) < 0) { 179 printf("rm: override protection %o for %s? ", 180 buf.st_mode&0777, arg); 181 if (!yes()) 182 return (0); 183 goto rm; 184 } 185 } 186 if (iflg) { 187 printf("rm: remove %s? ", arg); 188 if (!yes()) 189 return (0); 190 } 191 rm: if (unlink(arg) < 0) { 192 if (!fflg || iflg) { 193 fprintf(stderr, "rm: %s: ", arg); 194 perror((char *)NULL); 195 errcode++; 196 } 197 return (0); 198 } 199 return (1); 200 } 201 202 /* 203 * Get a yes/no answer from the user. 204 */ 205 yes() 206 { 207 int i, b; 208 209 i = b = getchar(); 210 while (b != '\n' && b != EOF) 211 b = getchar(); 212 return (i == 'y'); 213 } 214 215 /* 216 * Append 'name' to 'path'. 217 */ 218 append(name) 219 char *name; 220 { 221 register int n; 222 223 n = strlen(name); 224 if (path == NULL) { 225 pathsz = MAXNAMLEN + MAXPATHLEN + 2; 226 if ((path = malloc((u_int)pathsz)) == NULL) { 227 fprintf(stderr, "rm: ran out of memory\n"); 228 exit(1); 229 } 230 pathp = path; 231 } else if (pathp + n + 2 > path + pathsz) { 232 fprintf(stderr, "rm: path name too long: %s\n", path); 233 exit(1); 234 } else if (pathp != path && pathp[-1] != '/') 235 *pathp++ = '/'; 236 strcpy(pathp, name); 237 pathp += n; 238 } 239 240 usage() 241 { 242 fputs("usage: rm [-rif] file ...\n", stderr); 243 exit(1); 244 } 245