2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: holding.c,v 1.56 2006/06/09 23:07:26 martinea Exp $
29 * Functions to access holding disk
35 #include "fileheader.h"
38 static sl_t *scan_holdingdisk(sl_t *holding_list, char *diskdir, int verbose);
39 static sl_t *scan_holdingdir(sl_t *holding_list, holdingdisk_t *holdp, char *datestamp);
47 if(stat(fname, &statbuf) == -1) return 0;
49 return (statbuf.st_mode & S_IFDIR) == S_IFDIR;
58 if(stat(fname, &statbuf) == -1) return 0;
60 return ((statbuf.st_mode & S_IFDIR) != S_IFDIR) &&
61 (statbuf.st_size == (off_t)0);
66 * sanity check on datestamp of the form YYYYMMDD or YYYYMMDDhhmmss
74 int ch, num, date, year, month, hour, minute, second;
77 /* must be 8 digits */
78 for(cp = fname; (ch = *cp) != '\0'; cp++) {
83 if(ch != '\0' || (cp-fname != 8 && cp-fname != 14)) {
87 /* sanity check year, month, and day */
89 strncpy(ymd, fname, 8);
93 month = (num / 100) % 100;
95 if(year<1990 || year>2100 || month<1 || month>12 || date<1 || date>31)
101 /* sanity check hour, minute, and second */
102 strncpy(hms, fname+8, 6);
106 minute = (num / 100) % 100;
108 if(hour> 23 || minute>59 || second>59)
111 /* yes, we passed all the checks */
122 struct dirent *entry;
125 if((dir = opendir(fname)) == NULL)
129 while(!gotentry && (entry = readdir(dir)) != NULL) {
130 gotentry = !is_dot_or_dotdot(entry->d_name);
145 struct dirent *workdir;
146 char *entryname = NULL;
148 if((topdir = opendir(diskdir)) == NULL) {
149 if(verbose && errno != ENOENT)
150 printf("Warning: could not open holding dir %s: %s\n",
151 diskdir, strerror(errno));
155 /* find all directories of the right format */
158 printf("Scanning %s...\n", diskdir);
159 while((workdir = readdir(topdir)) != NULL) {
160 if(is_dot_or_dotdot(workdir->d_name)) {
163 entryname = newvstralloc(entryname,
164 diskdir, "/", workdir->d_name, NULL);
166 printf(" %s: ", workdir->d_name);
168 if(!is_dir(entryname)) {
170 puts("skipping cruft file, perhaps you should delete it.");
172 } else if(!is_datestr(workdir->d_name)) {
173 if(verbose && (strcmp(workdir->d_name, "lost+found")!=0) ) {
174 puts("skipping cruft directory, perhaps you should delete it.");
177 holding_list = insert_sort_sl(holding_list, workdir->d_name);
179 puts("found Amanda directory.");
192 holdingdisk_t * holdp,
196 struct dirent *entry;
197 char *dirname = NULL;
198 char *destname = NULL;
202 dirname = vstralloc(holdingdisk_get_diskdir(holdp), "/", datestamp, NULL);
203 if((workdir = opendir(dirname)) == NULL) {
205 log_add(L_INFO, "%s: could not open dir: %s",
206 dirname, strerror(errno));
210 if ((chdir(dirname)) == -1) {
211 log_add(L_INFO, "%s: could not chdir: %s",
212 dirname, strerror(errno));
217 while((entry = readdir(workdir)) != NULL) {
218 if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
221 if(is_emptyfile(entry->d_name))
224 destname = newvstralloc(destname,
225 dirname, "/", entry->d_name,
227 get_dumpfile(destname, &file);
228 if( file.type != F_DUMPFILE) {
229 if( file.type != F_CONT_DUMPFILE )
230 log_add(L_INFO, "%s: ignoring cruft file.", entry->d_name);
234 dp = lookup_disk(file.name, file.disk);
237 log_add(L_INFO, "%s: disk %s:%s not in database, skipping it.",
238 entry->d_name, file.name, file.disk);
242 if(file.dumplevel < 0 || file.dumplevel > 9) {
243 log_add(L_INFO, "%s: ignoring file with bogus dump level %d.",
244 entry->d_name, file.dumplevel);
248 holding_list = append_sl(holding_list, destname);
261 char *datestamp, /* don't do this date */
268 sle_t *date, *next_date;
269 holdingdisk_t *hdisk;
270 char current_dir[PATH_MAX];
272 holding_list = new_sl();
274 if (getcwd(current_dir, SIZEOF(current_dir)-1) == NULL) {
275 log_add(L_INFO, "get_flush: could get current working directory: %s",
283 date_list = pick_all_datestamp(verbose);
284 for(date = date_list->first; date != NULL;) {
285 next_date = date->next;
287 for(datearg=dateargs->first; datearg != NULL && ok==0;
288 datearg = datearg->next) {
289 ok = match_datestamp(datearg->name, date->name);
291 if(ok == 0) { /* remove dir */
292 remove_sl(date_list, date);
298 date_list = pick_datestamp(verbose);
301 date_list = pick_all_datestamp(verbose);
304 for(date = date_list->first; date !=NULL; date = date->next) {
305 if(!datestamp || strcmp(datestamp,date->name) != 0) {
306 for(hdisk = getconf_holdingdisks(); hdisk != NULL;
307 hdisk = hdisk->next) {
308 holding_list = scan_holdingdir(holding_list, hdisk, date->name);
315 if (chdir(current_dir) == -1) {
316 log_add(L_INFO, "%s: could not chdir: %s",
317 current_dir, strerror(errno));
319 return(holding_list);
327 sl_t *holding_list = NULL;
328 holdingdisk_t *hdisk;
330 holding_list = new_sl();
331 for(hdisk = getconf_holdingdisks(); hdisk != NULL; hdisk = hdisk->next)
332 holding_list = scan_holdingdisk(holding_list, holdingdisk_get_diskdir(hdisk), verbose);
343 sl_t *r_holding_list = NULL;
345 char **directories = NULL;
350 char max_char = '\0', chupper = '\0';
352 holding_list = pick_all_datestamp(verbose);
354 if(holding_list->nb_element == 0) {
357 else if(holding_list->nb_element == 1 || !verbose) {
361 directories = alloc((holding_list->nb_element) * SIZEOF(char *));
362 for(dir = holding_list->first, i=0; dir != NULL; dir = dir->next,i++) {
363 directories[i] = dir->name;
367 puts("\nMultiple Amanda directories, please pick one by letter:");
368 for(dir = holding_list->first, max_char = 'A';
369 dir != NULL && max_char <= 'Z';
370 dir = dir->next, max_char++) {
371 printf(" %c. %s\n", max_char, dir->name);
374 printf("Select directories to flush [A..%c]: [ALL] ", max_char);
375 fflush(stdout); fflush(stderr);
377 if ((answer = agets(stdin)) == NULL) {
382 if (*answer == '\0' || strncasecmp(answer, "ALL", 3) == 0) {
387 while ((ch = *a++) != '\0') {
393 if (isspace(ch) || ch == ',') {
396 chupper = (char)toupper(ch);
397 if (chupper < 'A' || chupper > max_char) {
398 free_sl(r_holding_list);
399 r_holding_list = NULL;
402 r_holding_list = append_sl(r_holding_list,
403 directories[chupper - 'A']);
404 } while ((ch = *a++) != '\0');
405 if (r_holding_list && ch == '\0') {
406 free_sl(holding_list);
407 holding_list = r_holding_list;
419 get_amanda_names( char * fname,
425 char buffer[DISK_BLOCK_BYTES];
427 *hostname = *diskname = NULL;
429 memset(buffer, 0, sizeof(buffer));
430 if((fd = open(fname, O_RDONLY)) == -1)
433 if(fullread(fd, buffer, SIZEOF(buffer)) != (ssize_t)sizeof(buffer)) {
439 parse_file_header(buffer, &file, SIZEOF(buffer));
440 if(file.type != F_DUMPFILE && file.type != F_CONT_DUMPFILE) {
443 *hostname = stralloc(file.name);
444 *diskname = stralloc(file.disk);
445 *level = file.dumplevel;
456 char buffer[DISK_BLOCK_BYTES];
459 memset(buffer, 0, sizeof(buffer));
462 file->type = F_UNKNOWN;
463 if((fd = open(fname, O_RDONLY)) == -1)
466 if(fullread(fd, buffer, SIZEOF(buffer)) != (ssize_t)sizeof(buffer)) {
472 parse_file_header(buffer, file, SIZEOF(buffer));
484 char buffer[DISK_BLOCK_BYTES];
487 off_t size = (off_t)0;
490 memset(buffer, 0, sizeof(buffer));
491 filename = stralloc(holding_file);
492 while(filename != NULL && filename[0] != '\0') {
493 if((fd = open(filename,O_RDONLY)) == -1) {
494 fprintf(stderr,"size_holding_files: open of %s failed: %s\n",filename,strerror(errno));
498 if ((buflen = fullread(fd, buffer, SIZEOF(buffer))) > 0) {
499 parse_file_header(buffer, &file, (size_t)buflen);
502 if(stat(filename, &finfo) == -1) {
503 printf("stat %s: %s\n", filename, strerror(errno));
504 finfo.st_size = (off_t)0;
506 size += (finfo.st_size+(off_t)1023)/(off_t)1024;
508 size -= (off_t)(DISK_BLOCK_BYTES / 1024);
510 filename = newstralloc(filename, file.cont_filename);
522 unlink_holding_files(
527 char buffer[DISK_BLOCK_BYTES];
531 memset(buffer, 0, sizeof(buffer));
532 filename = stralloc(holding_file);
533 while(filename != NULL && filename[0] != '\0') {
534 if((fd = open(filename,O_RDONLY)) == -1) {
535 fprintf(stderr,"unlink_holding_files: open of %s failed: %s\n",filename,strerror(errno));
539 if ((buflen = fullread(fd, buffer, SIZEOF(buffer))) > 0) {
540 parse_file_header(buffer, &file, (size_t)buflen);
545 filename = newstralloc(filename, file.cont_filename);
563 char buffer[DISK_BLOCK_BYTES];
566 char *filename_tmp = NULL;
568 memset(buffer, 0, sizeof(buffer));
569 filename = stralloc(holding_file);
570 while(filename != NULL && filename[0] != '\0') {
571 filename_tmp = newvstralloc(filename_tmp, filename, ".tmp", NULL);
572 if((fd = open(filename_tmp,O_RDONLY)) == -1) {
573 fprintf(stderr,"rename_tmp_holding: open of %s failed: %s\n",filename_tmp,strerror(errno));
575 amfree(filename_tmp);
578 buflen = fullread(fd, buffer, SIZEOF(buffer));
581 if(rename(filename_tmp, filename) != 0) {
583 "rename_tmp_holding: could not rename \"%s\" to \"%s\": %s",
584 filename_tmp, filename, strerror(errno));
588 fprintf(stderr,"rename_tmp_holding: %s: empty file?\n", filename);
590 amfree(filename_tmp);
593 parse_file_header(buffer, &file, (size_t)buflen);
595 if((fd = open(filename, O_RDWR)) == -1) {
596 fprintf(stderr, "rename_tmp_holdingX: open of %s failed: %s\n",
597 filename, strerror(errno));
599 amfree(filename_tmp);
604 build_header(buffer, &file, SIZEOF(buffer));
605 fullwrite(fd, buffer, SIZEOF(buffer));
608 filename = newstralloc(filename, file.cont_filename);
611 amfree(filename_tmp);
622 struct dirent *workdir;
624 if((topdir = opendir(diskdir)) == NULL) {
625 if(verbose && errno != ENOENT)
626 printf("Warning: could not open holding dir %s: %s\n",
627 diskdir, strerror(errno));
631 /* find all directories of the right format */
634 printf("Scanning %s...\n", diskdir);
635 if ((chdir(diskdir)) == -1) {
636 log_add(L_INFO, "%s: could not chdir: %s",
637 diskdir, strerror(errno));
639 while((workdir = readdir(topdir)) != NULL) {
640 if(strcmp(workdir->d_name, ".") == 0
641 || strcmp(workdir->d_name, "..") == 0
642 || strcmp(workdir->d_name, "lost+found") == 0)
646 printf(" %s: ", workdir->d_name);
647 if(!is_dir(workdir->d_name)) {
649 puts("skipping cruft file, perhaps you should delete it.");
651 else if(!is_datestr(workdir->d_name)) {
652 if(verbose && (strcmp(workdir->d_name, "lost+found")!=0) )
653 puts("skipping cruft directory, perhaps you should delete it.");
655 else if(rmdir(workdir->d_name) == 0) {
657 puts("deleted empty Amanda directory.");
668 struct stat stat_hdp;
671 if (mkpdir(diskdir, 0770, (uid_t)-1, (gid_t)-1) != 0 && errno != EEXIST) {
672 log_add(L_WARNING, "WARNING: could not create parents of %s: %s",
673 diskdir, strerror(errno));
676 else if (mkdir(diskdir, 0770) != 0 && errno != EEXIST) {
677 log_add(L_WARNING, "WARNING: could not create %s: %s",
678 diskdir, strerror(errno));
681 else if (stat(diskdir, &stat_hdp) == -1) {
682 log_add(L_WARNING, "WARNING: could not stat %s: %s",
683 diskdir, strerror(errno));
687 if (!S_ISDIR((stat_hdp.st_mode))) {
688 log_add(L_WARNING, "WARNING: %s is not a directory",
692 else if (access(diskdir,W_OK) != 0) {
693 log_add(L_WARNING, "WARNING: directory %s is not writable",