source: trunk/athena/bin/delete/expunge.c @ 10977

Revision 10977, 11.0 KB checked in by danw, 27 years ago (diff)
assume POSIX. (from svalente)
Line 
1/*
2 * $Source: /afs/dev.mit.edu/source/repository/athena/bin/delete/expunge.c,v $
3 * $Author: danw $
4 *
5 * This program is part of a package including delete, undelete,
6 * lsdel, expunge and purge.  The software suite is meant as a
7 * replacement for rm which allows for file recovery.
8 *
9 * Copyright (c) 1989 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, see the file "mit-copying.h."
11 */
12
13#if (!defined(lint) && !defined(SABER))
14     static char rcsid_expunge_c[] = "$Header: /afs/dev.mit.edu/source/repository/athena/bin/delete/expunge.c,v 1.23 1997-12-31 22:35:59 danw Exp $";
15#endif
16
17#include <stdio.h>
18#include <sys/types.h>
19#include <sys/time.h>
20#include <dirent.h>
21#include <sys/param.h>
22#include <string.h>
23#include <com_err.h>
24#include <errno.h>
25#include "col.h"
26#include "util.h"
27#include "directories.h"
28#include "pattern.h"
29#include "expunge.h"
30#include "shell_regexp.h"
31#include "mit-copying.h"
32#include "delete_errs.h"
33#include "errors.h"
34
35extern time_t current_time;
36
37char *whoami;
38
39time_t timev;           /* minimum mod time before undeletion */
40
41int  interactive,       /* query before each expunge */
42     recursive,         /* expunge undeleted directories recursively */
43     noop,              /* print what would be done instead of doing it */
44     verbose,           /* print a line as each file is deleted */
45     force,             /* do not ask for any confirmation */
46     listfiles,         /* list files at toplevel */
47     yield,             /* print yield of expunge at end */
48     f_links,           /* follow symbolic links */
49     f_mounts;          /* follow mount points */
50
51int space_removed = 0;
52
53
54
55
56main(argc, argv)
57int argc;
58char *argv[];
59{
60     extern char *optarg;
61     extern int optind;
62     int arg;
63
64     initialize_del_error_table();
65     
66     whoami = lastpart(argv[0]);
67     if (*whoami == 'p') { /* we're doing a purge */
68          if (argc > 1) {
69               set_error(PURGE_TOO_MANY_ARGS);
70               error("");
71               exit(1);
72          }
73          if (purge())
74               error("purge");
75          exit(error_occurred ? 1 : 0);
76     }
77     timev = 0;
78     yield = interactive = recursive = noop = verbose = listfiles = force = 0;
79     while ((arg = getopt(argc, argv, "t:irfnvlysm")) != EOF) {
80          switch (arg) {
81          case 't':
82               timev = atoi(optarg);
83               break;
84          case 'i':
85               interactive++;
86               break;
87          case 'r':
88               recursive++;
89               break;
90          case 'f':
91               force++;
92               break;
93          case 'n':
94               noop++;
95               break;
96          case 'v':
97               verbose++;
98               break;
99          case 'l':
100               listfiles++;
101               break;
102          case 'y':
103               yield++;
104               break;
105          case 's':
106               f_links++;
107               break;
108          case 'm':
109               f_mounts++;
110               break;
111          default:
112               usage();
113               exit(1);
114          }
115     }
116     report_errors = ! force;
117     
118     if (optind == argc) {
119          char *dir;
120          dir = "."; /* current working directory */
121          if (expunge(&dir, 1))
122               error("expunging .");
123     }
124     else if (expunge(&argv[optind], argc - optind))
125          error("expunge");
126
127     exit((error_occurred && (! force)) ? 1 : 0);
128}
129
130
131
132
133
134purge()
135{
136     char *home;
137     int retval;
138     
139     home = Malloc((unsigned) MAXPATHLEN);
140     if (! home) {
141          set_error(errno);
142          error("purge");
143          return error_code;
144     }
145     timev = interactive = noop = verbose = force = 0;
146     yield = listfiles = recursive = 1;
147     if (retval = get_home(home)) {
148          error("purge");
149          return retval;
150     }
151
152     printf("Please be patient.... this may take a while.\n\n");
153
154     if (retval = expunge(&home, 1)) {
155          error("expunge");
156          return retval;
157     }
158     return 0;
159}
160
161
162
163
164usage()
165{
166     fprintf(stderr, "Usage: %s [ options ] [ filename [ ... ]]\n", whoami);
167     fprintf(stderr, "Options are:\n");
168     fprintf(stderr, "     -r     recursive\n");
169     fprintf(stderr, "     -i     interactive\n");
170     fprintf(stderr, "     -f     force\n");
171     fprintf(stderr, "     -t n   n-day-or-older expunge\n");
172     fprintf(stderr, "     -n     noop\n");
173     fprintf(stderr, "     -v     verbose\n");
174     fprintf(stderr, "     -l     list files before expunging\n");
175     fprintf(stderr, "     -s     follow symbolic links to directories\n");
176     fprintf(stderr, "     -m     follow mount points\n");
177     fprintf(stderr, "     -y     print yield of expunge\n");
178     fprintf(stderr, "     --     end options and start filenames\n");
179}
180
181
182
183
184
185int expunge(files, num)
186char **files;
187int num;
188{
189     char **found_files;
190     int num_found;
191     int status = 0;
192     int total = 0;
193     filerec *current;
194     int retval;
195     
196     if (initialize_tree())
197          exit(1);
198
199     for ( ; num ; num--) {
200          retval = get_the_files(files[num - 1], &num_found, &found_files);
201          if (retval) {
202               error(files[num - 1]);
203               return retval;
204          }
205               
206          if (num_found) {
207               num_found = process_files(found_files, num_found);
208               if (num_found < 0) {
209                    error("process_files");
210                    return error_code;
211               }
212          }
213         
214          total += num_found;
215          if (! num_found) if (! force) {
216               /*
217                * There are three different situations here.  Eiter we
218                * are dealing with an existing directory with no
219                * deleted files in it, or we are deleting with a
220                * non-existing deleted file with wildcards, or we are
221                * dealing with a non-existing deleted file without
222                * wildcards.  In the former case we print nothing, and
223                * in the latter cases we print either "no match" or
224                * "not found" respectively
225                */
226               if (no_wildcards(files[num - 1])) {
227                    if (! directory_exists(files[num - 1])) {
228                         set_error(ENOENT);
229                         error(files[num - 1]);
230                    }
231               }
232               else {
233                    set_error(ENOMATCH);
234                    error(files[num - 1]);
235               }
236          }
237     }
238     if (total && listfiles) {
239          if (retval = list_files()) {
240               error("list_files");
241               return retval;
242          }
243          if (! force) if (! top_level()) {
244               set_status(EXPUNGE_NOT_EXPUNGED);
245               return error_code;
246          }
247     }
248     current = get_root_tree();
249     if (current) {
250          if (retval = expunge_specified(current)) {
251               error("expunge_specified");
252               status = retval;
253          }
254     }
255     current = get_cwd_tree();
256     if (current) {
257          if (retval = expunge_specified(current)) {
258               error("expunge_specified");
259               status = retval;
260          }
261     }
262     if (yield) {
263          if (noop)
264               printf("Total that would be expunged: %dk\n",
265                      space_to_k(space_removed));
266          else
267               printf("Total expunged: %dk\n", space_to_k(space_removed));
268     }
269     return status;
270}
271
272
273
274expunge_specified(leaf)
275filerec *leaf;
276{
277     int status = 0;
278     int do_it = 1;
279     int retval;
280     
281     if ((leaf->specified) && ((leaf->specs.st_mode & S_IFMT) == S_IFDIR)) {
282          /*
283           * This is static so that we don't create a copy of it for
284           * every recursive invocation of expunge_specified.
285           */
286          static char buf[MAXPATHLEN];
287
288          if (retval = get_leaf_path(leaf, buf)) {
289               error("get_leaf_path");
290               return retval;
291          }
292          (void) convert_to_user_name(buf, buf);
293
294          if (interactive) {
295               printf("%s: Expunge directory %s? ", whoami, buf);
296               status = (! (do_it = yes()));
297          }
298     }
299     if (do_it) {
300          if (leaf->dirs) {
301               if (retval = expunge_specified(leaf->dirs)) {
302                    error("expunge_specified");
303                    status = retval;
304               }
305          }
306          if (leaf->files) {
307               if (retval = expunge_specified(leaf->files)) {
308                    error("expunge_specified");
309                    status = retval;
310               }
311          }
312     }
313     if (leaf->specified && (! status)) {
314          if (retval = really_do_expunge(leaf)) {
315               error("really_do_expunge");
316               status = retval;
317          }
318     }
319     if (leaf->next) {
320          if (retval = expunge_specified(leaf->next)) {
321               error("expunge_specified");
322               status = retval;
323          }
324     }
325
326     free_leaf(leaf);
327     return status;
328}
329
330
331process_files(files, num)
332char **files;
333int num;
334{
335     int i, skipped = 0;
336     filerec *leaf;
337     
338     for (i = 0; i < num; i++) {
339          if (add_path_to_tree(files[i], &leaf)) {
340               error("add_path_to_tree");
341               return -1;
342          }
343          free(files[i]);
344          if (! timed_out(leaf, current_time, timev)) {
345               free_leaf(leaf);
346               skipped++;
347          }
348     }
349     free((char *) files);
350     return(num-skipped);
351}
352
353
354
355
356
357
358
359
360
361really_do_expunge(file_ent)
362filerec *file_ent;
363{
364     char real[MAXPATHLEN], user[MAXPATHLEN];
365     int status;
366     int retval;
367     
368     if (retval = get_leaf_path(file_ent, real)) {
369          error("get_leaf_path");
370          return retval;
371     }
372     (void) convert_to_user_name(real, user);
373
374     if (interactive) {
375          printf ("%s: Expunge %s (%dk)? ", whoami, user,
376                  specs_to_k(file_ent->specs));
377          if (! yes()) {
378               set_status(EXPUNGE_NOT_EXPUNGED);
379               return error_code;
380          }
381     }
382
383     if (noop) {
384          space_removed += specs_to_space(file_ent->specs);
385          printf("%s: %s (%dk) would be expunged (%dk total)\n", whoami, user,
386                 specs_to_k(file_ent->specs),
387                 space_to_k(space_removed));
388          return 0;
389     }
390
391     if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
392          status = rmdir(real);
393     else
394          status = unlink(real);
395     if (! status) {
396          space_removed += specs_to_space(file_ent->specs);
397          if (verbose)
398               printf("%s: %s (%dk) expunged (%dk total)\n", whoami, user,
399                      specs_to_k(file_ent->specs),
400                      space_to_k(space_removed));
401          return 0;
402     }
403     else {
404          set_error(errno);
405          error(real);
406          return error_code;
407     }
408}
409
410
411
412
413
414
415
416
417
418top_level()
419{
420     if (interactive) {
421printf("The above files, which have been marked for deletion, are about to be\n");
422printf("expunged forever!  You will be asked for confirmation before each file is\n");
423printf("deleted.  Do you wish to continue [return = no]? ");
424     }
425     else {
426printf("The above files, which have been marked for deletion, are about to be\n");
427printf("expunged forever!  Make sure you don't need any of them before continuing.\n");
428printf("Do you wish to continue [return = no]? ");
429     }
430     return (yes());
431}
432
433
434
435
436
437list_files()
438{
439     filerec *current;
440     char **strings;
441     int num;
442     int retval;
443     
444     strings = (char **) Malloc(sizeof(char *));
445     num = 0;
446     if (! strings) {
447          set_error(errno);
448          error("Malloc");
449          return error_code;
450     }
451
452     printf("The following deleted files are going to be expunged: \n\n");
453
454     current = get_root_tree();
455     if (retval = accumulate_names(current, &strings, &num)) {
456          error("accumulate_names");
457          return retval;
458     }
459     current = get_cwd_tree();
460     if (retval = accumulate_names(current, &strings, &num)) {
461          error("accumulate_names");
462          return retval;
463     }
464     if (retval = column_array(strings, num, DEF_SCR_WIDTH, 0, 0, 2, 1, 0,
465                               1, stdout)) {
466          error("column_array");
467          return retval;
468     }
469     
470     printf("\n");
471     return(0);
472}
473     
474
475
476
477
478int get_the_files(name, num_found, found)
479char *name;
480int *num_found;
481char ***found;
482{
483     int retval;
484     int options;
485     
486     options = FIND_DELETED | FIND_CONTENTS | RECURS_DELETED;
487     if (recursive)
488          options |= RECURS_FIND_DELETED;
489     if (f_mounts)
490          options |= FOLLW_MOUNTPOINTS;
491     if (f_links)
492          options |= FOLLW_LINKS;
493     
494     retval = find_matches(name, num_found, found, options);
495     if (retval) {
496          error("find_matches");
497          return retval;
498     }
499
500     return 0;
501}
Note: See TracBrowser for help on using the repository browser.