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.52 2006/03/09 22:01:21 martinea Exp $
29 * Functions to access holding disk
35 #include "fileheader.h"
38 static sl_t *scan_holdingdisk P((sl_t *holding_list, char *diskdir, int verbose));
45 if(stat(fname, &statbuf) == -1) return 0;
47 return (statbuf.st_mode & S_IFDIR) == S_IFDIR;
50 int is_emptyfile(fname)
55 if(stat(fname, &statbuf) == -1) return 0;
57 return (statbuf.st_mode & S_IFDIR) != S_IFDIR && statbuf.st_size == 0;
62 /* sanity check on datestamp of the form YYYYMMDD or YYYYMMDDhhmmss*/
65 int ch, num, date, year, month, hour, minute, second;
68 /* must be 8 digits */
69 for(cp = fname; (ch = *cp) != '\0'; cp++) {
74 if(ch != '\0' || (cp-fname != 8 && cp-fname != 14)) {
78 /* sanity check year, month, and day */
80 strncpy(ymd, fname, 8);
84 month = (num / 100) % 100;
86 if(year<1990 || year>2100 || month<1 || month>12 || date<1 || date>31)
92 /* sanity check hour, minute, and second */
93 strncpy(hms, fname+8, 6);
97 minute = (num / 100) % 100;
99 if(hour> 23 || minute>59 || second>59)
102 /* yes, we passed all the checks */
112 struct dirent *entry;
115 if((dir = opendir(fname)) == NULL)
119 while(!gotentry && (entry = readdir(dir)) != NULL) {
120 gotentry = !is_dot_or_dotdot(entry->d_name);
128 static sl_t *scan_holdingdisk(holding_list, diskdir, verbose)
134 struct dirent *workdir;
135 char *entryname = NULL;
137 if((topdir = opendir(diskdir)) == NULL) {
138 if(verbose && errno != ENOENT)
139 printf("Warning: could not open holding dir %s: %s\n",
140 diskdir, strerror(errno));
144 /* find all directories of the right format */
147 printf("Scanning %s...\n", diskdir);
148 while((workdir = readdir(topdir)) != NULL) {
149 if(is_dot_or_dotdot(workdir->d_name)) {
152 entryname = newvstralloc(entryname,
153 diskdir, "/", workdir->d_name, NULL);
155 printf(" %s: ", workdir->d_name);
157 if(!is_dir(entryname)) {
159 puts("skipping cruft file, perhaps you should delete it.");
161 } else if(!is_datestr(workdir->d_name)) {
162 if(verbose && (strcmp(workdir->d_name, "lost+found")!=0) ) {
163 puts("skipping cruft directory, perhaps you should delete it.");
166 holding_list = insert_sort_sl(holding_list, workdir->d_name);
168 puts("found Amanda directory.");
178 sl_t *scan_holdingdir(holding_list, holdp, datestamp)
180 holdingdisk_t *holdp;
184 struct dirent *entry;
185 char *dirname = NULL;
186 char *destname = NULL;
190 dirname = vstralloc(holdp->diskdir, "/", datestamp, NULL);
191 if((workdir = opendir(dirname)) == NULL) {
193 log_add(L_INFO, "%s: could not open dir: %s",
194 dirname, strerror(errno));
199 while((entry = readdir(workdir)) != NULL) {
200 if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
203 if(is_emptyfile(entry->d_name))
206 destname = newvstralloc(destname,
207 dirname, "/", entry->d_name,
209 get_dumpfile(destname, &file);
210 if( file.type != F_DUMPFILE) {
211 if( file.type != F_CONT_DUMPFILE )
212 log_add(L_INFO, "%s: ignoring cruft file.", entry->d_name);
216 dp = lookup_disk(file.name, file.disk);
219 log_add(L_INFO, "%s: disk %s:%s not in database, skipping it.",
220 entry->d_name, file.name, file.disk);
224 if(file.dumplevel < 0 || file.dumplevel > 9) {
225 log_add(L_INFO, "%s: ignoring file with bogus dump level %d.",
226 entry->d_name, file.dumplevel);
230 holding_list = append_sl(holding_list, destname);
240 sl_t *get_flush(dateargs, datestamp, amflush, verbose)
242 char *datestamp; /* don't do this date */
243 int amflush, verbose;
248 sle_t *date, *next_date;
249 holdingdisk_t *hdisk;
250 char current_dir[1000];
252 getcwd(current_dir, 999);
254 holding_list = new_sl();
259 date_list = pick_all_datestamp(verbose);
260 for(date = date_list->first; date != NULL;) {
261 next_date = date->next;
263 for(datearg=dateargs->first; datearg != NULL && ok==0;
264 datearg = datearg->next) {
265 ok = match_datestamp(datearg->name, date->name);
267 if(ok == 0) { /* remove dir */
268 remove_sl(date_list, date);
274 date_list = pick_datestamp(verbose);
277 date_list = pick_all_datestamp(verbose);
280 for(date = date_list->first; date !=NULL; date = date->next) {
281 if(!datestamp || strcmp(datestamp,date->name) != 0) {
282 for(hdisk = getconf_holdingdisks(); hdisk != NULL;
283 hdisk = hdisk->next) {
284 holding_list = scan_holdingdir(holding_list, hdisk, date->name);
292 return(holding_list);
296 sl_t *pick_all_datestamp(verbose)
299 sl_t *holding_list = NULL;
300 holdingdisk_t *hdisk;
302 holding_list = new_sl();
303 for(hdisk = getconf_holdingdisks(); hdisk != NULL; hdisk = hdisk->next)
304 holding_list = scan_holdingdisk(holding_list, hdisk->diskdir, verbose);
310 sl_t *pick_datestamp(verbose)
314 sl_t *r_holding_list = NULL;
316 char **directories = NULL;
321 char max_char = '\0', chupper = '\0';
323 holding_list = pick_all_datestamp(verbose);
325 if(holding_list->nb_element == 0) {
328 else if(holding_list->nb_element == 1 || !verbose) {
332 directories = alloc((holding_list->nb_element) * sizeof(char *));
333 for(dir = holding_list->first, i=0; dir != NULL; dir = dir->next,i++) {
334 directories[i] = dir->name;
338 puts("\nMultiple Amanda directories, please pick one by letter:");
339 for(dir = holding_list->first, max_char = 'A';
340 dir != NULL && max_char <= 'Z';
341 dir = dir->next, max_char++) {
342 printf(" %c. %s\n", max_char, dir->name);
345 printf("Select directories to flush [A..%c]: [ALL] ", max_char);
346 fflush(stdout); fflush(stderr);
348 if ((answer = agets(stdin)) == NULL) {
353 while ((ch = *a++) != '\0' && isspace(ch)) {}
354 if(ch == '\0' || strncasecmp(a, "ALL", 3) == 0) {
358 if (isspace(ch) || ch == ',') {
361 chupper = toupper(ch);
362 if (chupper < 'A' || chupper > max_char) {
363 free_sl(r_holding_list);
364 r_holding_list = NULL;
367 r_holding_list = append_sl(r_holding_list,
368 directories[chupper - 'A']);
369 } while ((ch = *a++) != '\0');
370 if (r_holding_list && ch == '\0') {
371 free_sl(holding_list);
372 holding_list = r_holding_list;
383 filetype_t get_amanda_names(fname, hostname, diskname, level)
384 char *fname, **hostname, **diskname;
388 char buffer[DISK_BLOCK_BYTES];
390 *hostname = *diskname = NULL;
392 if((fd = open(fname, O_RDONLY)) == -1)
395 if(fullread(fd, buffer, sizeof(buffer)) != sizeof(buffer)) {
401 parse_file_header(buffer,&file,sizeof(buffer));
402 if(file.type != F_DUMPFILE && file.type != F_CONT_DUMPFILE) {
405 *hostname = stralloc(file.name);
406 *diskname = stralloc(file.disk);
407 *level = file.dumplevel;
413 void get_dumpfile(fname, file)
417 char buffer[DISK_BLOCK_BYTES];
421 file->type = F_UNKNOWN;
422 if((fd = open(fname, O_RDONLY)) == -1)
425 if(fullread(fd, buffer, sizeof(buffer)) != sizeof(buffer)) {
431 parse_file_header(buffer,file,sizeof(buffer));
436 long size_holding_files(holding_file, strip_headers)
442 char buffer[DISK_BLOCK_BYTES];
448 filename = stralloc(holding_file);
449 while(filename != NULL && filename[0] != '\0') {
450 if((fd = open(filename,O_RDONLY)) == -1) {
451 fprintf(stderr,"size_holding_files: open of %s failed: %s\n",filename,strerror(errno));
455 if ((buflen = fullread(fd, buffer, sizeof(buffer))) > 0) {
456 parse_file_header(buffer, &file, buflen);
459 if(stat(filename, &finfo) == -1) {
460 printf("stat %s: %s\n", filename, strerror(errno));
463 size += (finfo.st_size+1023)/1024;
464 if(strip_headers) size -= DISK_BLOCK_BYTES/1024;
466 filename = newstralloc(filename, file.cont_filename);
477 int unlink_holding_files( holding_file )
482 char buffer[DISK_BLOCK_BYTES];
486 filename = stralloc(holding_file);
487 while(filename != NULL && filename[0] != '\0') {
488 if((fd = open(filename,O_RDONLY)) == -1) {
489 fprintf(stderr,"unlink_holding_files: open of %s failed: %s\n",filename,strerror(errno));
493 if ((buflen = fullread(fd, buffer, sizeof(buffer))) > 0) {
494 parse_file_header(buffer, &file, buflen);
499 filename = newstralloc(filename, file.cont_filename);
510 int rename_tmp_holding( holding_file, complete )
516 char buffer[DISK_BLOCK_BYTES];
519 char *filename_tmp = NULL;
521 filename = stralloc(holding_file);
522 while(filename != NULL && filename[0] != '\0') {
523 filename_tmp = newvstralloc(filename_tmp, filename, ".tmp", NULL);
524 if((fd = open(filename_tmp,O_RDONLY)) == -1) {
525 fprintf(stderr,"rename_tmp_holding: open of %s failed: %s\n",filename_tmp,strerror(errno));
527 amfree(filename_tmp);
530 buflen = fullread(fd, buffer, sizeof(buffer));
533 if(rename(filename_tmp, filename) != 0) {
535 "rename_tmp_holding: could not rename \"%s\" to \"%s\": %s",
536 filename_tmp, filename, strerror(errno));
540 fprintf(stderr,"rename_tmp_holding: %s: empty file?\n", filename);
542 amfree(filename_tmp);
545 parse_file_header(buffer, &file, buflen);
547 if((fd = open(filename, O_RDWR)) == -1) {
548 fprintf(stderr, "rename_tmp_holdingX: open of %s failed: %s\n",
549 filename, strerror(errno));
551 amfree(filename_tmp);
556 build_header(buffer, &file, sizeof(buffer));
557 fullwrite(fd, buffer, sizeof(buffer));
560 filename = newstralloc(filename, file.cont_filename);
563 amfree(filename_tmp);
568 void cleanup_holdingdisk(diskdir, verbose)
573 struct dirent *workdir;
575 if((topdir = opendir(diskdir)) == NULL) {
576 if(verbose && errno != ENOENT)
577 printf("Warning: could not open holding dir %s: %s\n",
578 diskdir, strerror(errno));
582 /* find all directories of the right format */
585 printf("Scanning %s...\n", diskdir);
587 while((workdir = readdir(topdir)) != NULL) {
588 if(strcmp(workdir->d_name, ".") == 0
589 || strcmp(workdir->d_name, "..") == 0
590 || strcmp(workdir->d_name, "lost+found") == 0)
594 printf(" %s: ", workdir->d_name);
595 if(!is_dir(workdir->d_name)) {
597 puts("skipping cruft file, perhaps you should delete it.");
599 else if(!is_datestr(workdir->d_name)) {
600 if(verbose && (strcmp(workdir->d_name, "lost+found")!=0) )
601 puts("skipping cruft directory, perhaps you should delete it.");
603 else if(rmdir(workdir->d_name) == 0) {
605 puts("deleted empty Amanda directory.");
612 int mkholdingdir(diskdir)
615 struct stat stat_hdp;
618 if (mkpdir(diskdir, 0770, (uid_t)-1, (gid_t)-1) != 0 && errno != EEXIST) {
619 log_add(L_WARNING, "WARNING: could not create parents of %s: %s",
620 diskdir, strerror(errno));
623 else if (mkdir(diskdir, 0770) != 0 && errno != EEXIST) {
624 log_add(L_WARNING, "WARNING: could not create %s: %s",
625 diskdir, strerror(errno));
628 else if (stat(diskdir, &stat_hdp) == -1) {
629 log_add(L_WARNING, "WARNING: could not stat %s: %s",
630 diskdir, strerror(errno));
634 if (!S_ISDIR((stat_hdp.st_mode))) {
635 log_add(L_WARNING, "WARNING: %s is not a directory",
639 else if (access(diskdir,W_OK) != 0) {
640 log_add(L_WARNING, "WARNING: directory %s is not writable",