BSD 1 development
[unix-history] / s6 / rmtree.c
CommitLineData
0598a28e
KS
1#
2/* UCB rmtree
3 * rmtree dir . . .
4 * author: Kurt Shoens
5 * recursively removes files and directories
6 * in a subtree. The -v flag prevents it from
7 * removing the final directory, ie the one
8 * you specify. The incredible danger of
9 * this program must by now be apparent to you. It
10 * asks you if you are sure on each argument.
11 */
12
13
14#define ENOTDIR 20
15#define ENOENT 2
16
17#define STACKSIZE 1024
18
19int vflag;
20int errs;
21int fflag;
22int cflag;
23int active;
24
25/* set warnflag true to get "last chance before . . . " */
26
27int warnflag 1;
28
29char pathname[STACKSIZE];
30
31char *pathptr;
32char *myname;
33
34extern errno;
35
36main(ct,av)
37 char **av;
38{
39 int level,i,thiser;
40 char crap[36];
41 setuid(getuid());
42 myname = av[0];
43/*
44 * if (getuid())
45 * {
46 * printf("sorry, not super user\n");
47 * exit(1);
48 * }
49 */
50 if (ct<2)
51 {
52 usage(myname);
53 exit(9);
54 }
55 for (i=1;i<ct;++i)
56 {
57 if (*av[i] == '-')
58 {
59 process(av[i]);
60 continue;
61 }
62 ++active;
63 if (stat(av[i],crap))
64 {
65 perror(av[i]);
66 errs++;
67 continue;
68 }
69 if (!dir(av[i]))
70 {
71 errno = ENOTDIR;
72 perror(av[i]);
73 errs++;
74 }
75 else
76 {
77 if (warning(av[i],warnflag && !fflag))
78 {
79 if (cflag && !vflag) chmod(av[i], 0700);
80 pathptr = pathname;
81 pushstr(av[i]);
82 thiser = descend();
83 errs =+ thiser;
84 if (!vflag && !thiser) errs =+ rmdir(av[i]);
85 }
86 }
87 }
88 if (!active)
89 {
90 usage(myname);
91 exit(9);
92 }
93 exit(errs);
94}
95
96descend()
97{
98 int offset,j,err,markerr,xcnt;
99 static f,inum,*ip;
100 register char *cp;
101 char name[16];
102 markerr=0;
103 offset=16;
104 f=open(pathname,0);
105 if (f==-1)
106 {
107 prs(pathname);
108 prs(": no read permission\n");
109 return(1);
110 }
111 j=read(f,name,16);
112 xcnt=0;
113 while (j)
114 {
115 ip=name;
116 inum= *ip;
117 if (!scomp(&name[2],".") && !scomp(&name[2],"..") && inum)
118 {
119 if (!xcnt++) if (access(pathname,3))
120 {
121 prs(pathname);
122 prs(": need both X and W permission\n");
123 close(f);
124 return(1);
125 }
126 pushstr(&name[2]);
127 if (dir(pathname))
128 {
129 close(f);
130 if (cflag) chmod(pathname, 0700);
131 err=descend();
132 if (!err) rmdir(pathname);
133 else markerr=1;
134 popstr();
135 f = open(pathname,0);
136 seek(f,offset,0);
137 }
138 else
139 {
140
141 /* if unlink fails, keeps going ?? */
142
143 if (rm(pathname)) markerr=1;
144 popstr();
145 }
146 }
147 j=read(f,name,16);
148 offset=offset+16;
149 }
150 close(f);
151 return(markerr);
152}
153
154rmdir(str)
155 char *str;
156{
157 int p;
158 p = fork();
159 if (!p)
160 {
161 execl("/bin/rmdir","rmdir",str,0);
162 perror("/bin/rmdir");
163 exit(1);
164 }
165 else wait(&p);
166 return(p);
167}
168
169rm(f)
170 char *f;
171{
172 if (quota(f) && vflag) return(1);
173 if (unlink(f))
174 {
175 perror(f);
176 return(1);
177 }
178 return(0);
179}
180
181popstr()
182{
183 --pathptr;
184 while (*pathptr != '/') --pathptr;
185 while (*pathptr == '/') --pathptr;
186 *++pathptr = 0;
187}
188
189dir(n)
190 char *n;
191{
192 struct inode {
193 char minor; /* +0: minor device of i-node */
194 char major; /* +1: major device */
195 int inumber; /* +2 */
196 int flags; /* +4: see below */
197 char nlinks; /* +6: number of links to file */
198 char uid; /* +7: user ID of owner */
199 char gid; /* +8: group ID of owner */
200 char size0; /* +9: high byte of 24-bit size */
201 int size1; /* +10: low word of 24-bit size */
202 int addr[8]; /* +12: block numbers or device number */
203 int actime[2]; /* +28: time of last access */
204 int modtime[2]; /* +32: time of last modification */
205 } buf;
206 if (stat(n,&buf)) return(0);
207 return((buf.flags & 060000) == 040000);
208}
209
210quota(n)
211 char *n;
212{
213 struct inode {
214 char minor; /* +0: minor device of i-node */
215 char major; /* +1: major device */
216 int inumber; /* +2 */
217 int flags; /* +4: see below */
218 char nlinks; /* +6: number of links to file */
219 char uid; /* +7: user ID of owner */
220 char gid; /* +8: group ID of owner */
221 char size0; /* +9: high byte of 24-bit size */
222 int size1; /* +10: low word of 24-bit size */
223 int addr[8]; /* +12: block numbers or device number */
224 int actime[2]; /* +28: time of last access */
225 int modtime[2]; /* +32: time of last modification */
226 } buf;
227 if (stat(n,&buf)) return(0);
228 return((buf.flags & 060000) == 020000 && buf.addr[0] == -1);
229}
230
231scomp(n1,n2)
232 char *n1,*n2;
233{
234 char left,right;
235 left= *n1;
236 right= *n2;
237 while (left && right)
238 {
239 if (left!=right) return(0);
240 ++n1;
241 ++n2;
242 left= *n1;
243 right= *n2;
244 }
245 return(left==right);
246}
247
248actual(str)
249 char *str;
250{
251 register char *f;
252 register slash;
253 f = str;
254 if (*f == '/') return(f);
255 slash = 0;
256 while (*f) if (*f++ == '/') slash++;
257 if (!slash) return(str);
258 while (*f != '/') --f;
259 ++f;
260 return(f);
261}
262
263warning(file,f)
264 char *file;
265{
266 char line[20];
267 if (!f) return;
268 if (gtty(0,line)) return;
269 printf("last chance before OBLITERATING %s\n",file);
270 printf("ok? ");
271 line[read(0,line,20)] = 0;
272 return(*line == 'y' || *line == 'Y');
273}
274
275process(str)
276 char *str;
277{
278 while (*str) switch(*str++)
279 {
280 case 'c':
281 cflag++;
282 break;
283
284 case 'v':
285 vflag = 1;
286 break;
287
288 case 'f':
289 fflag = 1;
290 break;
291
292 case 's':
293 fflag = 0;
294 break;
295
296 case 'a':
297 vflag = 0;
298 break;
299
300 case '-':
301 break;
302
303 default:
304 printf("unknown switch: %c\n", *--str);
305 exit(1);
306 }
307}
308
309usage(str)
310 char *str;
311{
312 printf("Usage: %s [ -acfsv ] dir ...\n",str);
313 errs++;
314}
315
316prs(str)
317 char *str;
318{
319 register char *f;
320 f = str;
321 while (*f) ++f;
322 write(2, str, f-str);
323}
324
325pushstr(str)
326 char *str;
327{
328 if (pathptr != pathname) *pathptr++ = '/';
329 while (*pathptr++ = *str++) if (pathptr >= pathname + STACKSIZE)
330 panic("path name too long");
331 pathptr--;
332}
333
334panic(str)
335 char *str;
336{
337 prs("PANIC: ");
338 prs(str);
339 prs("\n");
340 exit(1);
341}