|
|
1.1 root 1: static char *sccsid = "@(#)rm.c 4.22 (Berkeley) 4/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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.