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

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