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