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

Revision 23661, 11.4 KB checked in by broder, 16 years ago (diff)
In delete: * Apply patches from jik: - When printing an amount of space, print it in friendly units, e.g., KB, MB or GB, rather than always printing kb.
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
[23271]63#if defined(__APPLE__) && defined(__MACH__)
64     add_error_table(&et_del_error_table);
65#else
[2179]66     initialize_del_error_table();
[23271]67#endif
[2179]68     
[1704]69     whoami = lastpart(argv[0]);
70     if (*whoami == 'p') { /* we're doing a purge */
[2519]71          if (argc > 1) {
72               set_error(PURGE_TOO_MANY_ARGS);
73               error("");
74               exit(1);
75          }
[2179]76          if (purge())
77               error("purge");
78          exit(error_occurred ? 1 : 0);
[1704]79     }
[1732]80     timev = 0;
81     yield = interactive = recursive = noop = verbose = listfiles = force = 0;
[2221]82     while ((arg = getopt(argc, argv, "t:irfnvlysm")) != EOF) {
[1704]83          switch (arg) {
84          case 't':
[1732]85               timev = atoi(optarg);
[1704]86               break;
87          case 'i':
88               interactive++;
89               break;
90          case 'r':
91               recursive++;
92               break;
93          case 'f':
94               force++;
95               break;
96          case 'n':
97               noop++;
98               break;
99          case 'v':
100               verbose++;
101               break;
102          case 'l':
103               listfiles++;
104               break;
[1732]105          case 'y':
106               yield++;
107               break;
[2221]108          case 's':
109               f_links++;
110               break;
111          case 'm':
112               f_mounts++;
113               break;
[1704]114          default:
115               usage();
116               exit(1);
117          }
118     }
[2221]119     report_errors = ! force;
120     
[1704]121     if (optind == argc) {
122          char *dir;
[2179]123          dir = "."; /* current working directory */
124          if (expunge(&dir, 1))
125               error("expunging .");
[1704]126     }
[2179]127     else if (expunge(&argv[optind], argc - optind))
128          error("expunge");
129
130     exit((error_occurred && (! force)) ? 1 : 0);
[1704]131}
132
133
134
135
136
137purge()
138{
[2179]139     char *home;
140     int retval;
141     
[2367]142     home = Malloc((unsigned) MAXPATHLEN);
[2179]143     if (! home) {
144          set_error(errno);
145          error("purge");
146          return error_code;
[1704]147     }
[1732]148     timev = interactive = noop = verbose = force = 0;
149     yield = listfiles = recursive = 1;
[2179]150     if (retval = get_home(home)) {
151          error("purge");
152          return retval;
[1704]153     }
154
155     printf("Please be patient.... this may take a while.\n\n");
[2179]156
157     if (retval = expunge(&home, 1)) {
158          error("expunge");
159          return retval;
160     }
[2221]161     return 0;
[1704]162}
163
164
165
166
167usage()
168{
[2221]169     fprintf(stderr, "Usage: %s [ options ] [ filename [ ... ]]\n", whoami);
170     fprintf(stderr, "Options are:\n");
171     fprintf(stderr, "     -r     recursive\n");
172     fprintf(stderr, "     -i     interactive\n");
173     fprintf(stderr, "     -f     force\n");
174     fprintf(stderr, "     -t n   n-day-or-older expunge\n");
175     fprintf(stderr, "     -n     noop\n");
176     fprintf(stderr, "     -v     verbose\n");
177     fprintf(stderr, "     -l     list files before expunging\n");
178     fprintf(stderr, "     -s     follow symbolic links to directories\n");
179     fprintf(stderr, "     -m     follow mount points\n");
180     fprintf(stderr, "     -y     print yield of expunge\n");
181     fprintf(stderr, "     --     end options and start filenames\n");
[1704]182}
183
184
185
186
187
[2179]188int expunge(files, num)
[1704]189char **files;
190int num;
191{
192     char **found_files;
193     int num_found;
194     int status = 0;
195     int total = 0;
196     filerec *current;
[2179]197     int retval;
[1704]198     
199     if (initialize_tree())
200          exit(1);
201
202     for ( ; num ; num--) {
[2221]203          retval = get_the_files(files[num - 1], &num_found, &found_files);
[2179]204          if (retval) {
205               error(files[num - 1]);
206               return retval;
207          }
208               
209          if (num_found) {
[1732]210               num_found = process_files(found_files, num_found);
[2179]211               if (num_found < 0) {
212                    error("process_files");
213                    return error_code;
214               }
215          }
216         
[1732]217          total += num_found;
218          if (! num_found) if (! force) {
[1753]219               /*
220                * There are three different situations here.  Eiter we
221                * are dealing with an existing directory with no
222                * deleted files in it, or we are deleting with a
223                * non-existing deleted file with wildcards, or we are
224                * dealing with a non-existing deleted file without
225                * wildcards.  In the former case we print nothing, and
226                * in the latter cases we print either "no match" or
227                * "not found" respectively
228                */
[2221]229               if (no_wildcards(files[num - 1])) {
[1753]230                    if (! directory_exists(files[num - 1])) {
[2179]231                         set_error(ENOENT);
232                         error(files[num - 1]);
[1753]233                    }
234               }
235               else {
[23660]236                    set_error(DELETE_ENOMATCH);
[2179]237                    error(files[num - 1]);
[1753]238               }
[1704]239          }
240     }
241     if (total && listfiles) {
[2179]242          if (retval = list_files()) {
243               error("list_files");
244               return retval;
245          }
246          if (! force) if (! top_level()) {
247               set_status(EXPUNGE_NOT_EXPUNGED);
248               return error_code;
249          }
[1704]250     }
[1732]251     current = get_root_tree();
[2179]252     if (current) {
253          if (retval = expunge_specified(current)) {
254               error("expunge_specified");
255               status = retval;
256          }
257     }
[1732]258     current = get_cwd_tree();
[2179]259     if (current) {
260          if (retval = expunge_specified(current)) {
261               error("expunge_specified");
262               status = retval;
263          }
264     }
[1732]265     if (yield) {
[23661]266       char *friendly = space_to_friendly(space_removed);
267       if (noop)
268         printf("Total that would be expunged: %s\n", friendly);
269       else
270         printf("Total expunged: %s\n", friendly);
271       free(friendly);
[1732]272     }
[2179]273     return status;
[1704]274}
275
276
277
[1732]278expunge_specified(leaf)
279filerec *leaf;
280{
281     int status = 0;
[2179]282     int do_it = 1;
283     int retval;
284     
285     if ((leaf->specified) && ((leaf->specs.st_mode & S_IFMT) == S_IFDIR)) {
[6420]286          /*
287           * This is static so that we don't create a copy of it for
288           * every recursive invocation of expunge_specified.
289           */
290          static char buf[MAXPATHLEN];
[1704]291
[2179]292          if (retval = get_leaf_path(leaf, buf)) {
293               error("get_leaf_path");
294               return retval;
295          }
[2221]296          (void) convert_to_user_name(buf, buf);
[2179]297
298          if (interactive) {
299               printf("%s: Expunge directory %s? ", whoami, buf);
300               status = (! (do_it = yes()));
301          }
[1850]302     }
[2179]303     if (do_it) {
304          if (leaf->dirs) {
305               if (retval = expunge_specified(leaf->dirs)) {
306                    error("expunge_specified");
307                    status = retval;
308               }
309          }
310          if (leaf->files) {
311               if (retval = expunge_specified(leaf->files)) {
312                    error("expunge_specified");
313                    status = retval;
314               }
315          }
[1732]316     }
[2179]317     if (leaf->specified && (! status)) {
318          if (retval = really_do_expunge(leaf)) {
319               error("really_do_expunge");
320               status = retval;
321          }
322     }
323     if (leaf->next) {
324          if (retval = expunge_specified(leaf->next)) {
325               error("expunge_specified");
326               status = retval;
327          }
328     }
329
[1732]330     free_leaf(leaf);
[2179]331     return status;
[1732]332}
[1704]333
[1732]334
[1704]335process_files(files, num)
336char **files;
337int num;
338{
[1831]339     int i, skipped = 0;
[1732]340     filerec *leaf;
341     
[1704]342     for (i = 0; i < num; i++) {
[2179]343          if (add_path_to_tree(files[i], &leaf)) {
344               error("add_path_to_tree");
345               return -1;
[1704]346          }
[1732]347          free(files[i]);
348          if (! timed_out(leaf, current_time, timev)) {
349               free_leaf(leaf);
[1831]350               skipped++;
[1704]351          }
352     }
[2179]353     free((char *) files);
[1831]354     return(num-skipped);
[1704]355}
356
357
358
359
360
361
362
363
364
365really_do_expunge(file_ent)
366filerec *file_ent;
367{
368     char real[MAXPATHLEN], user[MAXPATHLEN];
369     int status;
[2179]370     int retval;
[1704]371     
[2179]372     if (retval = get_leaf_path(file_ent, real)) {
373          error("get_leaf_path");
374          return retval;
375     }
[2221]376     (void) convert_to_user_name(real, user);
[1704]377
378     if (interactive) {
[23661]379       char *friendly = specs_to_friendly(file_ent->specs);
380       printf ("%s: Expunge %s (%s)? ", whoami, user, friendly);
381       free(friendly);
[2179]382          if (! yes()) {
383               set_status(EXPUNGE_NOT_EXPUNGED);
384               return error_code;
385          }
[1704]386     }
387
388     if (noop) {
[4633]389          space_removed += specs_to_space(file_ent->specs);
[23661]390          char *friendly = space_to_friendly(space_removed);
391          char *friendly2 = specs_to_friendly(file_ent->specs);
392          printf("%s: %s (%s) would be expunged (%s total)\n", whoami, user,
393                 friendly2, friendly);
394          free(friendly);
395          free(friendly2);
[2179]396          return 0;
[1704]397     }
398
[1732]399     if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
[1704]400          status = rmdir(real);
401     else
402          status = unlink(real);
403     if (! status) {
[4633]404          space_removed += specs_to_space(file_ent->specs);
[23661]405          if (verbose) {
406            char *friendly = space_to_friendly(space_removed);
407            char *friendly2 = specs_to_friendly(file_ent->specs);
408            printf("%s: %s (%s) expunged (%s total)\n", whoami, user,
409                   friendly2, friendly);
410            free(friendly);
411            free(friendly2);
412          }
[2179]413          return 0;
[1704]414     }
415     else {
[2179]416          set_error(errno);
417          error(real);
418          return error_code;
[1704]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");
[1757]435printf("deleted.  Do you wish to continue [return = no]? ");
[1704]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");
[1757]440printf("Do you wish to continue [return = no]? ");
[1704]441     }
442     return (yes());
443}
444
[1732]445
446
447
448
[1704]449list_files()
450{
451     filerec *current;
[1732]452     char **strings;
453     int num;
[2179]454     int retval;
[1704]455     
[2367]456     strings = (char **) Malloc(sizeof(char *));
[1732]457     num = 0;
458     if (! strings) {
[2179]459          set_error(errno);
[2367]460          error("Malloc");
[2179]461          return error_code;
[1732]462     }
[2179]463
[1704]464     printf("The following deleted files are going to be expunged: \n\n");
465
466     current = get_root_tree();
[2179]467     if (retval = accumulate_names(current, &strings, &num)) {
468          error("accumulate_names");
469          return retval;
470     }
[1704]471     current = get_cwd_tree();
[2179]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     
[1704]482     printf("\n");
483     return(0);
484}
485     
486
487
488
489
[2221]490int get_the_files(name, num_found, found)
491char *name;
[1704]492int *num_found;
[2179]493char ***found;
[1704]494{
[2179]495     int retval;
[2221]496     int options;
[1704]497     
[2221]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;
[1704]505     
[2221]506     retval = find_matches(name, num_found, found, options);
507     if (retval) {
[2179]508          error("find_matches");
509          return retval;
510     }
[2221]511
[2179]512     return 0;
[1704]513}
Note: See TracBrowser for help on using the repository browser.