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

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