*/
static int is_dir(char *fname);
+/* Is fname an empty file?
+ *
+ * @param fname: filename (fully qualified)
+ * @returns: boolean
+ */
+static int is_emptyfile(char *fname);
+
/* sanity check that datestamp is of the form YYYYMMDD or
* YYYYMMDDhhmmss
*
*/
static int is_datestr(char *fname);
-/*
- * Static variables */
-static int verbose = 0;
-
/*
* Static functions */
}
/*
- * Verbosity
+ * Recursion functions
+ *
+ * These implement a general-purpose walk down the holding-* hierarchy.
*/
-int
-holding_set_verbosity(int v)
-{
- int old = verbose;
- verbose = v;
- return old;
-}
-/*
- * Holding directories
+/* Perform a custom action for this holding element (disk, dir, file, chunk).
+ *
+ * If the element is not cruft, the next step into the tree will only take place
+ * if this function returns a nonzero value.
+ *
+ * The walk is depth-first, with the callback for an element invoked
+ * before entering that element. Callbacks may depend on this behavior.
+ *
+ * @param datap: generic user-data pointer
+ * @param base: the parent of the element being examined, or NULL for
+ * holding disks
+ * @param element: the name of the element being examined
+ * @param fqpath: fully qualified path to 'element'
+ * @param is_cruft: nonzero if this element doesn't belong here
+ * @returns: nonzero if the walk should descend into this element.
*/
-
-static void
-holding_get_directories_per_disk(
- char *hdisk,
- sl_t *date_list,
- int fullpaths,
- sl_t *rv)
+typedef int (*holding_walk_fn)(
+ gpointer datap,
+ char *base,
+ char *element,
+ char *fqpath,
+ int is_cruft);
+
+typedef enum {
+ STOP_AT_DISK,
+ STOP_AT_DIR,
+ STOP_AT_FILE,
+ STOP_AT_CHUNK
+} stop_at_t;
+
+/* Recurse over all holding chunks in a holding file.
+ *
+ * Call per_chunk_fn for each chunk of the given file
+ *
+ * datap is passed, unchanged, to all holding_walk_fns.
+ *
+ * @param hfile: holding file to examine (fully qualified path)
+ * @param datap: generic user-data pointer
+ * @param per_chunk_fn: function to call for each holding chunk
+ */
+static void holding_walk_file(
+ char *hfile,
+ gpointer datap,
+ holding_walk_fn per_chunk_fn)
{
- DIR *dir;
- struct dirent *workdir;
- char *hdir = NULL;
- sle_t *dl;
- int date_found;
-
- if ((dir = opendir(hdisk)) == NULL) {
- if (verbose && errno != ENOENT)
- printf(_("Warning: could not open holding disk %s: %s\n"),
- hdisk, strerror(errno));
- return;
- }
-
- if (verbose)
- printf(_("Scanning %s...\n"), hdisk);
-
- while ((workdir = readdir(dir)) != NULL) {
- if (is_dot_or_dotdot(workdir->d_name))
- continue;
+ dumpfile_t file;
+ char *filename = NULL;
- if(verbose)
- printf(" %s: ", workdir->d_name);
-
- hdir = newvstralloc(hdir,
- hdisk, "/", workdir->d_name,
- NULL);
+ /* Loop through all cont_filenames (subsequent chunks) */
+ filename = stralloc(hfile);
+ while (filename != NULL && filename[0] != '\0') {
+ int is_cruft = 0;
- /* filter out various undesirables */
- if (!is_dir(hdir)) {
- if (verbose)
- puts(_("skipping cruft file, perhaps you should delete it."));
- } else if (!is_datestr(workdir->d_name)) {
- /* EXT2/3 leave these in the root of each volume */
- if (strcmp(workdir->d_name, "lost+found")==0)
- puts(_("skipping system directory"));
- if (verbose)
- puts(_("skipping cruft directory, perhaps you should delete it."));
- } else {
- /* found a holding directory -- keep it */
- if (date_list) {
- date_found = 0;
- for (dl= date_list->first; dl != NULL; dl = dl->next) {
- if (strcmp(dl->name, workdir->d_name) == 0) {
- date_found = 1;
- break;
- }
- }
- } else {
- date_found = 1;
- }
- if (date_found == 1) {
- if (fullpaths)
- rv = insert_sort_sl(rv, hdir);
- else
- rv = insert_sort_sl(rv, workdir->d_name);
- if (verbose) {
- puts(_("found Amanda directory."));
- }
- }
+ /* get the header to look for cont_filename */
+ if (!holding_file_get_dumpfile(filename, &file)) {
+ is_cruft = 1;
}
- }
-
- if (hdir) amfree(hdir);
-}
-
-
-sl_t *
-holding_get_directories(
- char *hdisk,
- sl_t *date_list,
- int fullpaths)
-{
- holdingdisk_t *hdisk_conf;
- sl_t *rv;
- rv = new_sl();
- if (!rv) {
- return NULL;
- }
-
- /* call _per_disk for the hdisk we were given, or for all
- * hdisks if we were given NULL */
- if (hdisk) {
- holding_get_directories_per_disk(hdisk, date_list, fullpaths, rv);
- } else {
- for (hdisk_conf = getconf_holdingdisks();
- hdisk_conf != NULL;
- hdisk_conf = hdisk_conf->next) {
- hdisk = holdingdisk_get_diskdir(hdisk_conf);
- holding_get_directories_per_disk(hdisk, date_list, fullpaths, rv);
- }
+ if (per_chunk_fn)
+ per_chunk_fn(datap,
+ hfile,
+ filename,
+ filename,
+ is_cruft);
+ amfree(filename);
+
+ /* and go on to the next chunk if this wasn't cruft */
+ if (!is_cruft)
+ filename = stralloc(file.cont_filename);
+ dumpfile_free_data(&file);
}
- return rv;
+ amfree(filename);
}
-/*
- * Holding files
+/* Recurse over all holding files in a holding directory.
+ *
+ * Call per_file_fn for each file, and so on, stopping at the level given by
+ * stop_at.
+ *
+ * datap is passed, unchanged, to all holding_walk_fns.
+ *
+ * @param hdir: holding directory to examine (fully qualified path)
+ * @param datap: generic user-data pointer
+ * @param stop_at: do not proceed beyond this level of the hierarchy
+ * @param per_file_fn: function to call for each holding file
+ * @param per_chunk_fn: function to call for each holding chunk
*/
-static void
-holding_get_files_per_dir(
+static void holding_walk_dir(
char *hdir,
- int fullpaths,
- sl_t *rv)
+ gpointer datap,
+ stop_at_t stop_at,
+ holding_walk_fn per_file_fn,
+ holding_walk_fn per_chunk_fn)
{
DIR *dir;
struct dirent *workdir;
char *hfile = NULL;
dumpfile_t dumpf;
int dumpf_ok;
+ int proceed = 1;
if ((dir = opendir(hdir)) == NULL) {
- if (verbose && errno != ENOENT)
- printf(_("Warning: could not open holding dir %s: %s\n"),
+ if (errno != ENOENT)
+ dbprintf(_("Warning: could not open holding dir %s: %s\n"),
hdir, strerror(errno));
return;
}
- if (verbose)
- printf(_("Scanning %s...\n"), hdir);
-
while ((workdir = readdir(dir)) != NULL) {
+ int is_cruft = 0;
+
if (is_dot_or_dotdot(workdir->d_name))
- continue;
+ continue; /* expected cruft */
hfile = newvstralloc(hfile,
hdir, "/", workdir->d_name,
/* filter out various undesirables */
if (is_emptyfile(hfile))
- continue;
+ is_cruft = 1;
if (is_dir(hfile)) {
- if (verbose)
- printf(_("%s: ignoring directory\n"), hfile);
- continue;
+ is_cruft= 1;
}
if (!(dumpf_ok=holding_file_get_dumpfile(hfile, &dumpf)) ||
dumpf.type != F_DUMPFILE) {
if (dumpf_ok && dumpf.type == F_CONT_DUMPFILE)
continue; /* silently skip expected file */
- if (verbose)
- printf(_("%s: not a dumpfile\n"), hfile);
- continue;
+
+ is_cruft = 1;
}
if (dumpf.dumplevel < 0 || dumpf.dumplevel > 9) {
- if (verbose)
- printf(_("%s: ignoring file with bogus dump level %d.\n"),
- hfile, dumpf.dumplevel);
- continue;
+ is_cruft = 1;
}
- /* found a holding file -- keep it */
- if (fullpaths)
- rv = insert_sort_sl(rv, hfile);
- else
- rv = insert_sort_sl(rv, workdir->d_name);
+ if (per_file_fn)
+ proceed = per_file_fn(datap,
+ hdir,
+ workdir->d_name,
+ hfile,
+ is_cruft);
+ if (!is_cruft && proceed && stop_at != STOP_AT_FILE)
+ holding_walk_file(hfile,
+ datap,
+ per_chunk_fn);
+ dumpfile_free_data(&dumpf);
+ }
+
+ closedir(dir);
+ amfree(hfile);
+}
+
+/* Recurse over all holding directories in a holding disk.
+ *
+ * Call per_dir_fn for each dir, and so on, stopping at the level given by
+ * stop_at.
+ *
+ * datap is passed, unchanged, to all holding_walk_fns.
+ *
+ * @param hdisk: holding disk to examine (fully qualified path)
+ * @param datap: generic user-data pointer
+ * @param stop_at: do not proceed beyond this level of the hierarchy
+ * @param per_dir_fn: function to call for each holding dir
+ * @param per_file_fn: function to call for each holding file
+ * @param per_chunk_fn: function to call for each holding chunk
+ */
+static void
+holding_walk_disk(
+ char *hdisk,
+ gpointer datap,
+ stop_at_t stop_at,
+ holding_walk_fn per_dir_fn,
+ holding_walk_fn per_file_fn,
+ holding_walk_fn per_chunk_fn)
+{
+ DIR *dir;
+ struct dirent *workdir;
+ char *hdir = NULL;
+ int proceed = 1;
+
+ if ((dir = opendir(hdisk)) == NULL) {
+ if (errno != ENOENT)
+ dbprintf(_("Warning: could not open holding disk %s: %s\n"),
+ hdisk, strerror(errno));
+ return;
+ }
+
+ while ((workdir = readdir(dir)) != NULL) {
+ int is_cruft = 0;
+
+ if (is_dot_or_dotdot(workdir->d_name))
+ continue; /* expected cruft */
+
+ hdir = newvstralloc(hdir,
+ hdisk, "/", workdir->d_name,
+ NULL);
+
+ /* detect cruft */
+ if (!is_dir(hdir)) {
+ is_cruft = 1;
+ } else if (!is_datestr(workdir->d_name)) {
+ /* EXT2/3 leave these in the root of each volume */
+ if (strcmp(workdir->d_name, "lost+found") == 0)
+ continue; /* expected cruft */
+ else
+ is_cruft = 1; /* unexpected */
+ }
+
+ if (per_dir_fn)
+ proceed = per_dir_fn(datap,
+ hdisk,
+ workdir->d_name,
+ hdir,
+ is_cruft);
+ if (!is_cruft && proceed && stop_at != STOP_AT_DIR)
+ holding_walk_dir(hdir,
+ datap,
+ stop_at,
+ per_file_fn,
+ per_chunk_fn);
+ }
+
+ closedir(dir);
+ amfree(hdir);
+}
+
+/* Recurse over all holding disks.
+ *
+ * Call per_disk_fn for each disk, per_dir_fn for each dir, and so on, stopping
+ * at the level given by stop_at.
+ *
+ * datap is passed, unchanged, to all holding_walk_fns.
+ *
+ * @param datap: generic user-data pointer
+ * @param stop_at: do not proceed beyond this level of the hierarchy
+ * @param per_disk_fn: function to call for each holding disk
+ * @param per_dir_fn: function to call for each holding dir
+ * @param per_file_fn: function to call for each holding file
+ * @param per_chunk_fn: function to call for each holding chunk
+ */
+static void
+holding_walk(
+ gpointer datap,
+ stop_at_t stop_at,
+ holding_walk_fn per_disk_fn,
+ holding_walk_fn per_dir_fn,
+ holding_walk_fn per_file_fn,
+ holding_walk_fn per_chunk_fn)
+{
+ holdingdisk_t *hdisk_conf;
+ char *hdisk;
+ int proceed = 1;
+
+ for (hdisk_conf = getconf_holdingdisks();
+ hdisk_conf != NULL;
+ hdisk_conf = holdingdisk_next(hdisk_conf)) {
+ int is_cruft = 0;
+
+ hdisk = holdingdisk_get_diskdir(hdisk_conf);
+ if (!is_dir(hdisk))
+ is_cruft = 1;
+
+ if (per_disk_fn)
+ proceed = per_disk_fn(datap,
+ NULL,
+ hdisk,
+ hdisk,
+ 0);
+ if (proceed && stop_at != STOP_AT_DISK)
+ holding_walk_disk(hdisk,
+ datap,
+ stop_at,
+ per_dir_fn,
+ per_file_fn,
+ per_chunk_fn);
}
+}
- if (hfile) amfree(hfile);
+/*
+ * holding_get_* functions
+ */
+typedef struct {
+ GSList *result;
+ int fullpaths;
+} holding_get_datap_t;
+
+/* Functor for holding_get_*; adds 'element' or 'fqpath' to
+ * the result.
+ */
+static int
+holding_get_walk_fn(
+ gpointer datap,
+ G_GNUC_UNUSED char *base,
+ char *element,
+ char *fqpath,
+ int is_cruft)
+{
+ holding_get_datap_t *data = (holding_get_datap_t *)datap;
+
+ /* ignore cruft */
+ if (is_cruft) return 0;
+
+ if (data->fullpaths)
+ data->result = g_slist_insert_sorted(data->result,
+ stralloc(fqpath),
+ g_compare_strings);
+ else
+ data->result = g_slist_insert_sorted(data->result,
+ stralloc(element),
+ g_compare_strings);
+
+ /* don't proceed any deeper */
+ return 0;
}
-sl_t *
+GSList *
+holding_get_disks(void)
+{
+ holding_get_datap_t data;
+ data.result = NULL;
+ data.fullpaths = 1; /* ignored anyway */
+
+ holding_walk((gpointer)&data,
+ STOP_AT_DISK,
+ holding_get_walk_fn, NULL, NULL, NULL);
+
+ return data.result;
+}
+
+GSList *
holding_get_files(
char *hdir,
- sl_t *date_list,
int fullpaths)
{
- sl_t *hdirs;
- sle_t *e;
- sl_t *rv;
-
- rv = new_sl();
- if (!rv) {
- return NULL;
- }
+ holding_get_datap_t data;
+ data.result = NULL;
+ data.fullpaths = fullpaths;
- /* call _per_dir for the hdir we were given, or for all
- * hdir if we were given NULL */
if (hdir) {
- holding_get_files_per_dir(hdir, fullpaths, rv);
+ holding_walk_dir(hdir, (gpointer)&data,
+ STOP_AT_FILE,
+ holding_get_walk_fn, NULL);
} else {
- hdirs = holding_get_directories(NULL, date_list, 1);
- for (e = hdirs->first; e != NULL; e = e->next) {
- holding_get_files_per_dir(e->name, fullpaths, rv);
- }
+ holding_walk((gpointer)&data,
+ STOP_AT_FILE,
+ NULL, NULL, holding_get_walk_fn, NULL);
}
- return rv;
+ return data.result;
+}
+
+GSList *
+holding_get_file_chunks(char *hfile)
+{
+ holding_get_datap_t data;
+ data.result = NULL;
+ data.fullpaths = 1;
+
+ holding_walk_file(hfile, (gpointer)&data,
+ holding_get_walk_fn);
+
+ return data.result;
}
-sl_t *
+GSList *
holding_get_files_for_flush(
- sl_t *dateargs,
- int interactive)
+ GSList *dateargs)
{
- sl_t *date_list;
- sl_t *file_list;
- sl_t *result_list;
- sle_t *datearg;
- sle_t *date, *next_date;
- sle_t *file_elt;
+ GSList *file_list, *file_elt;
+ GSList *date;
+ int date_matches;
disk_t *dp;
- char *host;
- char *disk;
- char *datestamp;
- filetype_t filetype;
-
- /* make date_list the intersection of available holding directories and
- * the dateargs parameter. */
- if (dateargs) {
- int ok;
-
- date_list = pick_all_datestamp(verbose);
- for (date = date_list->first; date != NULL;) {
- next_date = date->next;
- ok = 0;
- for(datearg=dateargs->first; datearg != NULL && ok==0;
- datearg = datearg->next) {
- ok = match_datestamp(datearg->name, date->name);
- }
- if(ok == 0) { /* remove dir */
- remove_sl(date_list, date);
- }
- date = next_date;
- }
- }
- else {
- /* no date args were provided, so use everything */
- if (interactive)
- date_list = pick_datestamp(verbose);
- else
- date_list = pick_all_datestamp(verbose);
- }
-
- result_list = new_sl();
- if (!result_list) {
- return NULL;
- }
+ dumpfile_t file;
+ GSList *result_list = NULL;
- /* loop over *all* files, checking each one */
- file_list = holding_get_files(NULL, date_list, 1);
- for (file_elt = file_list->first; file_elt != NULL; file_elt = file_elt->next) {
+ /* loop over *all* files, checking each one's datestamp against the expressions
+ * in dateargs */
+ file_list = holding_get_files(NULL, 1);
+ for (file_elt = file_list; file_elt != NULL; file_elt = file_elt->next) {
/* get info on that file */
- filetype = holding_file_read_header(file_elt->name, &host, &disk, NULL, &datestamp);
- if (filetype != F_DUMPFILE)
+ if (!holding_file_get_dumpfile((char *)file_elt->data, &file))
+ continue;
+
+ if (file.type != F_DUMPFILE) {
+ dumpfile_free_data(&file);
+ continue;
+ }
+
+ if (dateargs) {
+ date_matches = 0;
+ /* loop over date args, until we find a match */
+ for (date = dateargs; date !=NULL; date = date->next) {
+ if (strcmp((char *)date->data, file.datestamp) == 0) {
+ date_matches = 1;
+ break;
+ }
+ }
+ } else {
+ /* if no date list was provided, then all dates match */
+ date_matches = 1;
+ }
+ if (!date_matches) {
+ dumpfile_free_data(&file);
continue;
+ }
/* check that the hostname and disk are in the disklist */
- dp = lookup_disk(host, disk);
+ dp = lookup_disk(file.name, file.disk);
if (dp == NULL) {
- if (verbose)
- printf(_("%s: disk %s:%s not in database, skipping it."),
- file_elt->name, host, disk);
+ dbprintf(_("%s: disk %s:%s not in database, skipping it."),
+ (char *)file_elt->data, file.name, file.disk);
+ dumpfile_free_data(&file);
continue;
}
/* passed all tests -- we'll flush this file */
- result_list = insert_sort_sl(result_list, file_elt->name);
+ result_list = g_slist_insert_sorted(result_list,
+ stralloc(file_elt->data),
+ g_compare_strings);
+ dumpfile_free_data(&file);
}
- if (date_list) free_sl(date_list);
- if (file_list) free_sl(file_list);
+ if (file_list) g_slist_free_full(file_list);
return result_list;
}
-sl_t *
-holding_get_file_chunks(char *hfile)
+GSList *
+holding_get_all_datestamps(void)
{
- dumpfile_t file;
- char *filename;
- sl_t *rv = new_sl();
-
- if (!rv) {
- return NULL;
+ GSList *all_files, *file;
+ GSList *datestamps = NULL;
+
+ /* enumerate all files */
+ all_files = holding_get_files(NULL, 1);
+ for (file = all_files; file != NULL; file = file->next) {
+ dumpfile_t dfile;
+ if (!holding_file_get_dumpfile((char *)file->data, &dfile))
+ continue;
+ if (!g_slist_find_custom(datestamps, dfile.datestamp,
+ g_compare_strings)) {
+ datestamps = g_slist_insert_sorted(datestamps,
+ stralloc(dfile.datestamp),
+ g_compare_strings);
+ }
+ dumpfile_free_data(&dfile);
}
- /* Loop through all cont_filenames (subsequent chunks) */
- filename = stralloc(hfile);
- while (filename != NULL && filename[0] != '\0') {
- /* get the header to look for cont_filename */
- if (!holding_file_get_dumpfile(filename, &file)) {
- if (verbose)
- printf(_("holding_get_file_chunks: open of %s failed.\n"), filename);
- amfree(filename);
- return rv;
- }
-
- /* add the file to the results */
- insert_sort_sl(rv, filename);
+ g_slist_free_full(all_files);
- /* and go on to the next chunk */
- filename = newstralloc(filename, file.cont_filename);
- }
- amfree(filename);
- return rv;
+ return datestamps;
}
off_t
while (filename != NULL && filename[0] != '\0') {
/* stat the file for its size */
if (stat(filename, &finfo) == -1) {
- if (verbose)
- printf(_("stat %s: %s\n"), filename, strerror(errno));
- return (off_t)-1;
+ dbprintf(_("stat %s: %s\n"), filename, strerror(errno));
+ size = -1;
+ break;
}
size += (finfo.st_size+(off_t)1023)/(off_t)1024;
if (strip_headers)
/* get the header to look for cont_filename */
if (!holding_file_get_dumpfile(filename, &file)) {
- if (verbose)
- printf(_("holding_file_size: open of %s failed.\n"), filename);
- amfree(filename);
- return (off_t)-1;
+ dbprintf(_("holding_file_size: open of %s failed.\n"), filename);
+ size = -1;
+ break;
}
/* on to the next chunk */
filename = newstralloc(filename, file.cont_filename);
+ dumpfile_free_data(&file);
}
amfree(filename);
return size;
holding_file_unlink(
char *hfile)
{
- sl_t *chunklist;
- sle_t *chunk;
+ GSList *chunklist;
+ GSList *chunk;
chunklist = holding_get_file_chunks(hfile);
if (!chunklist)
return 0;
- for (chunk = chunklist->first; chunk != NULL; chunk = chunk->next) {
- if (unlink(chunk->name)<0) {
- if (verbose)
- printf(_("holding_file_unlink: could not unlink %s: %s\n"),
- chunk->name, strerror(errno));
+ for (chunk = chunklist; chunk != NULL; chunk = chunk->next) {
+ if (unlink((char *)chunk->data)<0) {
+ dbprintf(_("holding_file_unlink: could not unlink %s: %s\n"),
+ (char *)chunk->data, strerror(errno));
return 0;
}
}
-
return 1;
}
-filetype_t
-holding_file_read_header(
- char * fname,
- char ** hostname,
- char ** diskname,
- int * level,
- char ** datestamp)
-{
- dumpfile_t file;
-
- if (hostname) *hostname = NULL;
- if (diskname) *diskname = NULL;
- if (datestamp) *datestamp = NULL;
-
- if (!holding_file_get_dumpfile(fname, &file)) {
- return F_UNKNOWN;
- }
-
- if(file.type != F_DUMPFILE && file.type != F_CONT_DUMPFILE) {
- return file.type;
- }
-
- if (hostname) *hostname = stralloc(file.name);
- if (diskname) *diskname = stralloc(file.disk);
- if (level) *level = file.dumplevel;
- if (datestamp) *datestamp = stralloc(file.datestamp);
-
- return file.type;
-}
-
-
int
holding_file_get_dumpfile(
char * fname,
fh_init(file);
file->type = F_UNKNOWN;
- if((fd = open(fname, O_RDONLY)) == -1)
+ if((fd = robust_open(fname, O_RDONLY, 0)) == -1)
return 0;
- if(fullread(fd, buffer, SIZEOF(buffer)) != (ssize_t)sizeof(buffer)) {
+ if(full_read(fd, buffer, SIZEOF(buffer)) != sizeof(buffer)) {
aclose(fd);
return 0;
}
}
/*
- * Interactive functions
+ * Cleanup
*/
-sl_t *
-pick_all_datestamp(
- int v)
+typedef struct {
+ corrupt_dle_fn corrupt_dle;
+ FILE *verbose_output;
+} holding_cleanup_datap_t;
+
+static int
+holding_cleanup_disk(
+ gpointer datap,
+ G_GNUC_UNUSED char *base,
+ G_GNUC_UNUSED char *element,
+ char *fqpath,
+ int is_cruft)
+{
+ holding_cleanup_datap_t *data = (holding_cleanup_datap_t *)datap;
+
+ if (data->verbose_output) {
+ if (is_cruft)
+ g_fprintf(data->verbose_output,
+ _("Invalid holding disk '%s'\n"), fqpath);
+ else
+ g_fprintf(data->verbose_output,
+ _("Cleaning up holding disk '%s'\n"), fqpath);
+ }
+
+ return 1;
+}
+
+static int
+holding_cleanup_dir(
+ gpointer datap,
+ G_GNUC_UNUSED char *base,
+ char *element,
+ char *fqpath,
+ int is_cruft)
{
- int old_verbose = holding_set_verbosity(v);
- sl_t *rv;
+ holding_cleanup_datap_t *data = (holding_cleanup_datap_t *)datap;
+
+ if (is_cruft) {
+ if (data->verbose_output)
+ g_fprintf(data->verbose_output,
+ _("Invalid holding directory '%s'\n"), fqpath);
+ return 0;
+ }
+
+ /* try removing it */
+ if (rmdir(fqpath) == 0) {
+ /* success, so don't try to walk into it */
+ if (data->verbose_output)
+ g_fprintf(data->verbose_output,
+ _(" ..removed empty directory '%s'\n"), element);
+ return 0;
+ }
- /* get all holding directories, without full paths -- this
- * will be datestamps only */
- rv = holding_get_directories(NULL, NULL, 0);
+ if (data->verbose_output)
+ g_fprintf(data->verbose_output,
+ _(" ..cleaning up holding directory '%s'\n"), element);
- holding_set_verbosity(old_verbose);
- return rv;
+ return 1;
}
-sl_t *
-pick_datestamp(
- int verbose)
+static int
+holding_cleanup_file(
+ gpointer datap,
+ G_GNUC_UNUSED char *base,
+ char *element,
+ char *fqpath,
+ int is_cruft)
{
- sl_t *holding_list;
- sl_t *r_holding_list = NULL;
- sle_t *dir;
- char **directories = NULL;
- int i;
- char *answer = NULL;
- char *a = NULL;
- int ch = 0;
- char max_char = '\0', chupper = '\0';
-
- holding_list = pick_all_datestamp(verbose);
-
- if(holding_list->nb_element == 0) {
- return holding_list;
+ holding_cleanup_datap_t *data = (holding_cleanup_datap_t *)datap;
+ int stat;
+ int l;
+ dumpfile_t file;
+ disk_t *dp;
+
+ if (is_cruft) {
+ if (data->verbose_output)
+ g_fprintf(data->verbose_output,
+ _("Invalid holding file '%s'\n"), element);
+ return 0;
}
- else if(holding_list->nb_element == 1 || !verbose) {
- return holding_list;
+
+
+ stat = holding_file_get_dumpfile(fqpath, &file);
+
+ if (!stat) {
+ if (data->verbose_output)
+ g_fprintf(data->verbose_output,
+ _("Could not read read header from '%s'\n"), element);
+ dumpfile_free_data(&file);
+ return 0;
}
- else {
- directories = alloc((holding_list->nb_element) * SIZEOF(char *));
- for(dir = holding_list->first, i=0; dir != NULL; dir = dir->next,i++) {
- directories[i] = dir->name;
- }
- while(1) {
- puts(_("\nMultiple Amanda directories, please pick one by letter:"));
- for(dir = holding_list->first, max_char = 'A';
- dir != NULL && max_char <= 'Z';
- dir = dir->next, max_char++) {
- printf(" %c. %s\n", max_char, dir->name);
- }
- max_char--;
- printf(_("Select directories to flush [A..%c]: [ALL] "), max_char);
- fflush(stdout); fflush(stderr);
- amfree(answer);
- if ((answer = agets(stdin)) == NULL) {
- clearerr(stdin);
- continue;
- }
+ if (file.type != F_DUMPFILE && file.type != F_CONT_DUMPFILE) {
+ if (data->verbose_output)
+ g_fprintf(data->verbose_output,
+ _("File '%s' is not a dump file\n"), element);
+ dumpfile_free_data(&file);
+ return 0;
+ }
- if (*answer == '\0' || strncasecmp(answer, "ALL", 3) == 0) {
- break;
- }
+ if(file.dumplevel < 0 || file.dumplevel > 9) {
+ if (data->verbose_output)
+ g_fprintf(data->verbose_output,
+ _("File '%s' has invalid level %d\n"), element, file.dumplevel);
+ dumpfile_free_data(&file);
+ return 0;
+ }
- a = answer;
- while ((ch = *a++) != '\0') {
- if (!isspace(ch))
- break;
- }
+ dp = lookup_disk(file.name, file.disk);
- do {
- if (isspace(ch) || ch == ',') {
- continue;
- }
- chupper = (char)toupper(ch);
- if (chupper < 'A' || chupper > max_char) {
- free_sl(r_holding_list);
- r_holding_list = NULL;
- break;
- }
- r_holding_list = append_sl(r_holding_list,
- directories[chupper - 'A']);
- } while ((ch = *a++) != '\0');
- if (r_holding_list && ch == '\0') {
- free_sl(holding_list);
- holding_list = r_holding_list;
- break;
- }
+ if (dp == NULL) {
+ if (data->verbose_output)
+ g_fprintf(data->verbose_output,
+ _("File '%s' is for '%s:%s', which is not in the disklist\n"),
+ element, file.name, file.disk);
+ dumpfile_free_data(&file);
+ return 0;
+ }
+
+ if ((l = strlen(element)) >= 7 && strncmp(&fqpath[l-4],".tmp",4) == 0) {
+ char *destname;
+
+ /* generate a name without '.tmp' */
+ destname = stralloc(fqpath);
+ destname[strlen(destname) - 4] = '\0';
+
+ /* OK, it passes muster -- rename it to salvage some data,
+ * and mark the DLE as corrupted */
+ if (data->verbose_output)
+ g_fprintf(data->verbose_output,
+ _("Processing partial holding file '%s'\n"), element);
+
+ if(rename_tmp_holding(destname, 0)) {
+ if (data->corrupt_dle)
+ data->corrupt_dle(dp->host->hostname, dp->name);
+ } else {
+ dbprintf(_("rename_tmp_holding(%s) failed\n"), destname);
+ if (data->verbose_output)
+ g_fprintf(data->verbose_output,
+ _("Rename of '%s' to '%s' failed.\n"), element, destname);
}
+
+ amfree(destname);
}
- amfree(directories);
- amfree(answer);
- return holding_list;
+
+ dumpfile_free_data(&file);
+ return 1;
+}
+
+void
+holding_cleanup(
+ corrupt_dle_fn corrupt_dle,
+ FILE *verbose_output)
+{
+ holding_cleanup_datap_t data;
+ data.corrupt_dle = corrupt_dle;
+ data.verbose_output = verbose_output;
+
+ holding_walk((gpointer)&data,
+ STOP_AT_FILE,
+ holding_cleanup_disk,
+ holding_cleanup_dir,
+ holding_cleanup_file,
+ NULL);
}
/*
int complete)
{
int fd;
- ssize_t buflen;
+ size_t buflen;
char buffer[DISK_BLOCK_BYTES];
dumpfile_t file;
char *filename;
filename = stralloc(holding_file);
while(filename != NULL && filename[0] != '\0') {
filename_tmp = newvstralloc(filename_tmp, filename, ".tmp", NULL);
- if((fd = open(filename_tmp,O_RDONLY)) == -1) {
- fprintf(stderr,_("rename_tmp_holding: open of %s failed: %s\n"),filename_tmp,strerror(errno));
+ if((fd = robust_open(filename_tmp,O_RDONLY, 0)) == -1) {
+ dbprintf(_("rename_tmp_holding: open of %s failed: %s\n"),filename_tmp,strerror(errno));
amfree(filename);
amfree(filename_tmp);
return 0;
}
- buflen = fullread(fd, buffer, SIZEOF(buffer));
+ buflen = full_read(fd, buffer, SIZEOF(buffer));
close(fd);
if(rename(filename_tmp, filename) != 0) {
- fprintf(stderr,
- _("rename_tmp_holding: could not rename \"%s\" to \"%s\": %s"),
+ dbprintf(_("rename_tmp_holding: could not rename \"%s\" to \"%s\": %s"),
filename_tmp, filename, strerror(errno));
}
if (buflen <= 0) {
- fprintf(stderr,_("rename_tmp_holding: %s: empty file?\n"), filename);
+ dbprintf(_("rename_tmp_holding: %s: empty file?\n"), filename);
amfree(filename);
amfree(filename_tmp);
return 0;
}
parse_file_header(buffer, &file, (size_t)buflen);
if(complete == 0 ) {
- if((fd = open(filename, O_RDWR)) == -1) {
- fprintf(stderr, _("rename_tmp_holdingX: open of %s failed: %s\n"),
+ char * header;
+ if((fd = robust_open(filename, O_RDWR, 0)) == -1) {
+ dbprintf(_("rename_tmp_holdingX: open of %s failed: %s\n"),
filename, strerror(errno));
+ dumpfile_free_data(&file);
amfree(filename);
amfree(filename_tmp);
return 0;
}
file.is_partial = 1;
- build_header(buffer, &file, SIZEOF(buffer));
- fullwrite(fd, buffer, SIZEOF(buffer));
+ header = build_header(&file, DISK_BLOCK_BYTES);
+ if (full_write(fd, header, DISK_BLOCK_BYTES) != DISK_BLOCK_BYTES) {
+ dbprintf(_("rename_tmp_holding: writing new header failed: %s"),
+ strerror(errno));
+ dumpfile_free_data(&file);
+ amfree(filename);
+ amfree(filename_tmp);
+ close(fd);
+ return 0;
+ }
close(fd);
}
filename = newstralloc(filename, file.cont_filename);
+ dumpfile_free_data(&file);
}
amfree(filename);
amfree(filename_tmp);
return 1;
}
-void
-cleanup_holdingdisk(
- char * diskdir,
- int verbose)
-{
- DIR *topdir;
- struct dirent *workdir;
-
- if((topdir = opendir(diskdir)) == NULL) {
- if(verbose && errno != ENOENT)
- printf(_("Warning: could not open holding dir %s: %s\n"),
- diskdir, strerror(errno));
- return;
- }
-
- /* find all directories of the right format */
-
- if(verbose)
- printf(_("Scanning %s...\n"), diskdir);
- if ((chdir(diskdir)) == -1) {
- log_add(L_INFO, _("%s: could not chdir: %s"),
- diskdir, strerror(errno));
- }
- while((workdir = readdir(topdir)) != NULL) {
- if(strcmp(workdir->d_name, ".") == 0
- || strcmp(workdir->d_name, "..") == 0
- || strcmp(workdir->d_name, "lost+found") == 0)
- continue;
-
- if(verbose)
- printf(" %s: ", workdir->d_name);
- if(!is_dir(workdir->d_name)) {
- if(verbose)
- puts(_("skipping cruft file, perhaps you should delete it."));
- }
- else if(!is_datestr(workdir->d_name)) {
- if(verbose && (strcmp(workdir->d_name, "lost+found")!=0) )
- puts(_("skipping cruft directory, perhaps you should delete it."));
- }
- else if(rmdir(workdir->d_name) == 0) {
- if(verbose)
- puts(_("deleted empty Amanda directory."));
- }
- }
- closedir(topdir);
-}
-
int
mkholdingdir(