|
|
1.1 root 1: #include <stdio.h>
2: #include <sys/types.h>
3: #include <ndir.h>
4: #include <errno.h>
5:
6: int fflag;
7: int iflag;
8: int rflag;
9: int qflag;
10: int errcnt;
11:
12: extern char *strcpy(), *malloc(), *parent(), *child();
13:
14: main(argc, argv)
15: char **argv;
16: {
17: for( ; argc>1 && *argv[1]=='-'; argc--, argv++) {
18: for(;;) {
19: switch(*++argv[1]) {
20: case 'f':
21: fflag++;
22: continue;
23: case 'i':
24: iflag++;
25: continue;
26: case 'r':
27: rflag++;
28: continue;
29: default:
30: usage();
31: case 0: ;
32: }
33: break;
34: }
35: }
36: if(argc <= 1)
37: usage();
38: qflag = !fflag && !iflag && isatty(0);
39: while(--argc>0)
40: rm(*++argv);
41: return errcnt;
42: }
43:
44: usage()
45: {
46:
47: fprintf(stderr, "usage: rm [-fri] file ...\n");
48: exit(1);
49: }
50:
51: /* To avoid unnecessarily raising the process label in secure unix,
52: rm() and recurse() are coded without stat(). Except when
53: questions are asked, it takes between 1 and 6, typically 3,
54: system calls to remove a file.
55: */
56: rm(s)
57: register char *s;
58: {
59: if(strcmp(s, "..") == 0) {
60: errno = EINVAL;
61: error(s);
62: return;
63: }
64: if(iflag && access(parent(s),2)==0 && !query("%s: ", s) ||
65: qflag && access(s,2)==-1 &&
66: access(s,0)==0 && access(parent(s),2)==0 &&
67: !query("rm: %s unwritable; remove? ", s))
68: return;
69: /* Try rmdir first, to guard against superuser process
70: doing unlink on a directory, which would be bad.
71: Race conditions in which a directory might be unlinked:
72: (1) rmdir gives EBUSY; other proc cd's out before unlink
73: (2) rmdir gives EACCES; other proc changes parent's mode
74: (3) rmdir gives EPERM; other proc changes mode along path
75: */
76: if(rmdir(s) == 0)
77: return;
78: switch(errno) {
79: case EBUSY: /* text file or working directory */
80: case EPERM:
81: case EACCES: /* parent(s) unwritable; s may not be dir */
82: if(access(child(s),0) == 0) /* s searchable? */
83: goto case_ISDIR;
84: case ENOTDIR:
85: if(unlink(s) == 0)
86: return;
87: break;
88: case_ISDIR:
89: case EHASF:
90: case EINVAL: /* file name "." */
91: if(rflag) {
92: recurse(s);
93: return;
94: }
95: }
96: error(s);
97: }
98:
99: recurse(s)
100: char *s;
101: {
102: register struct direct *entryp;
103: register DIR *dirp = opendir(s);
104: char *path;
105:
106: if(dirp == 0) {
107: error(s);
108: return;
109: }
110: path = malloc(strlen(s)+MAXNAMLEN+2);
111: while(entryp = readdir(dirp)) {
112: char *ep = entryp->d_name;
113: if(strcmp(ep,".")==0 || strcmp(ep,"..")==0)
114: continue;
115: sprintf(path, "%s/%s", s, ep);
116: rm(path);
117: }
118: free(path);
119: closedir(dirp);
120: if(rmdir(s) == -1)
121: error(s);
122: }
123:
124: error(s)
125: char *s;
126: {
127: if(fflag) return;
128: fprintf(stderr, "rm: ");
129: perror(s);
130: errcnt++;
131: }
132:
133: query(f, s)
134: char *f, *s;
135: {
136: int c, reply;
137:
138: printf(f, s);
139: reply = c = getchar();
140: while(c != '\n') {
141: if(c == EOF)
142: return 0;
143: c = getchar();
144: }
145: return reply == 'y';
146: }
147:
148: char *
149: parent(s)
150: register char *s;
151: {
152: register n;
153: static char *p;
154: register char *t = s;
155:
156: while(*t)
157: t++;
158: while(t>s && t[-1]=='/')
159: t--;
160: while(t>s && t[-1]!='/')
161: t--;
162: if(t == s)
163: return ".";
164: while(t>s && t[-1]=='/')
165: t--;
166: if(t == s)
167: return "/";
168: n = t - s;
169: if(p) free(p);
170: p = malloc(n + 1);
171: strncpy(p, s, n);
172: p[n] = 0;
173: return p;
174: }
175:
176: char *
177: child(s)
178: char *s;
179: {
180: static char *p;
181: if(p) free(p);
182: p = malloc(strlen(s)+MAXNAMLEN+2);
183: strcat(strcpy(p, s), "/.");
184: return p;
185: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.