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 * Author: James da Silva, Systems Design and Analysis Group
24 * Computer Science Department
25 * University of Maryland at College Park
28 * $Id: diskfile.c,v 1.27.4.6.4.3.2.15 2003/12/16 22:36:45 martinea Exp $
38 static disklist_t lst;
40 static char *diskfname = NULL;
41 static host_t *hostlist;
42 static int line_num, got_parserror;
45 static char *upcase P((char *st));
46 static int read_diskline P((void));
47 static void parserror P((char *format, ...))
48 __attribute__ ((format (printf, 1, 2)));
51 disklist_t *read_diskfile(filename)
59 lst.head = lst.tail = NULL;
60 diskfname = newstralloc(diskfname, filename);
61 malloc_mark(diskfname);
62 line_num = got_parserror = 0;
64 if((diskf = fopen(filename, "r")) == NULL)
65 error("could not open disklist file \"%s\": %s",
66 filename, strerror(errno));
68 while(read_diskline());
71 if(got_parserror) return NULL;
75 host_t *lookup_host(hostname)
80 for(p = hostlist; p != NULL; p = p->next) {
81 if(strcasecmp(p->hostname, hostname) == 0) return p;
86 disk_t *lookup_disk(hostname, diskname)
87 char *hostname, *diskname;
92 host = lookup_host(hostname);
93 if(host == NULL) return NULL;
95 for(disk = host->disks; disk != NULL; disk = disk->hostnext) {
96 if(strcmp(disk->name, diskname) == 0) return disk;
101 void enqueue_disk(list, disk) /* put disk on end of queue */
105 if(list->tail == NULL) list->head = disk;
106 else list->tail->next = disk;
107 disk->prev = list->tail;
113 void headqueue_disk(list, disk) /* put disk on head of queue */
117 if(list->head == NULL) list->tail = disk;
118 else list->head->prev = disk;
119 disk->next = list->head;
125 void insert_disk(list, disk, cmp) /* insert in sorted order */
128 int (*cmp) P((disk_t *a, disk_t *b));
136 if(cmp(disk, ptr) < 0) break;
143 if(prev == NULL) list->head = disk;
144 else prev->next = disk;
145 if(ptr == NULL) list->tail = disk;
146 else ptr->prev = disk;
149 disk_t *add_disk(hostname, diskname)
156 disk = alloc(sizeof(disk_t));
158 disk->name = stralloc(diskname);
159 disk->device = stralloc(diskname);
162 disk->compress = COMP_NONE;
166 host = lookup_host(hostname);
168 host = alloc(sizeof(host_t));
169 host->next = hostlist;
172 host->hostname = stralloc(hostname);
174 host->inprogress = 0;
179 host->features = NULL;
181 enqueue_disk(&lst, disk);
184 disk->hostnext = host->disks;
190 int find_disk(list, disk)
193 /* check if disk is present in list. Return true if so, false otherwise. */
197 for( t = list->head; t && t != disk; t = t->next );
202 void sort_disk(in, out, cmp) /* sort a whole queue */
205 int (*cmp) P((disk_t *a, disk_t *b));
210 tmp = in; /* just in case in == out */
212 out->head = (disk_t *)0;
213 out->tail = (disk_t *)0;
215 while((disk = dequeue_disk(tmp)))
216 insert_disk(out, disk, cmp);
219 disk_t *dequeue_disk(list) /* remove disk from front of queue */
224 if(list->head == NULL) return NULL;
227 list->head = disk->next;
229 if(list->head == NULL) list->tail = NULL;
230 else list->head->prev = NULL;
232 disk->prev = disk->next = NULL; /* for debugging */
236 void remove_disk(list, disk)
240 if(disk->prev == NULL) list->head = disk->next;
241 else disk->prev->next = disk->next;
243 if(disk->next == NULL) list->tail = disk->prev;
244 else disk->next->prev = disk->prev;
246 disk->prev = disk->next = NULL;
249 static char *upcase(st)
255 if(islower((int)*s)) *s = toupper(*s);
262 static int read_diskline()
267 interface_t *netif = 0;
268 char *hostname = NULL;
269 char *diskname, *diskdevice;
270 static char *line = NULL;
272 int ch = '\0', dup = 0;
276 for(; (line = agets(diskf)) != NULL; free(line)) {
281 skip_whitespace(s, ch);
282 if(ch != '\0' && ch != '#') break;
284 if(line == NULL) return 0;
287 skip_non_whitespace(s, ch);
289 host = lookup_host(fp);
291 hostname = stralloc(fp);
292 malloc_mark(hostname);
294 hostname = host->hostname;
297 skip_whitespace(s, ch);
298 if(ch == '\0' || ch == '#') {
299 parserror("disk device name expected");
303 skip_non_whitespace(s, ch);
305 diskname = stralloc(fp);
307 skip_whitespace(s, ch);
308 if(ch == '\0' || ch == '#') {
309 parserror("disk dumptype expected");
310 if(host == NULL) amfree(hostname);
315 skip_non_whitespace(s, ch);
320 if(fp[0] != '{' && (dtype = lookup_dumptype(upcase(fp))) == NULL) {
322 skip_whitespace(s, ch);
323 if(ch == '\0' || ch == '#') {
324 parserror("disk dumptype expected");
325 if(host == NULL) amfree(hostname);
331 skip_non_whitespace(s, ch);
339 /* check for duplicate disk */
340 if(host && (disk = lookup_disk(hostname, diskname)) != NULL) {
341 parserror("duplicate disk record, previous on line %d", disk->line);
344 disk = alloc(sizeof(disk_t));
346 disk->line = line_num;
347 disk->name = diskname;
348 disk->device = diskdevice;
349 malloc_mark(disk->name);
352 disk->inprogress = 0;
358 skip_whitespace(s, ch);
359 if (ch != '\0' && ch != '#') {
360 parserror("expected line break after `{\', ignoring rest of line");
363 if (strchr(s-1, '}') &&
364 (strchr(s-1, '#') == NULL ||
365 strchr(s-1, '}') < strchr(s-1, '#'))) {
366 if(host == NULL) amfree(hostname);
375 dtype = read_dumptype(vstralloc("custom(", hostname,
376 ":", disk->name, ")", 0),
377 diskf, diskfname, &line_num);
380 /* line_num += 1; */ /* read_dumptype did it already */
382 if (dtype == NULL || dup) {
383 if(host == NULL) amfree(hostname);
395 } else if((dtype = lookup_dumptype(upcase(fp))) == NULL) {
396 parserror("undefined dumptype `%s'", fp);
397 if(host == NULL) amfree(hostname);
406 if(host == NULL) amfree(hostname);
410 disk->dtype_name = dtype->name;
411 disk->program = dtype->program;
412 disk->exclude_file = duplicate_sl(dtype->exclude_file);
413 disk->exclude_list = duplicate_sl(dtype->exclude_list);
414 disk->include_file = duplicate_sl(dtype->include_file);
415 disk->include_list = duplicate_sl(dtype->include_list);
416 disk->exclude_optional = dtype->exclude_optional;
417 disk->include_optional = dtype->include_optional;
418 disk->priority = dtype->priority;
419 disk->dumpcycle = dtype->dumpcycle;
420 disk->frequency = dtype->frequency;
421 disk->auth = dtype->auth;
422 disk->maxdumps = dtype->maxdumps;
423 disk->maxpromoteday = dtype->maxpromoteday;
424 disk->start_t = dtype->start_t;
425 disk->strategy = dtype->strategy;
426 disk->compress = dtype->compress;
427 disk->comprate[0] = dtype->comprate[0];
428 disk->comprate[1] = dtype->comprate[1];
429 disk->record = dtype->record;
430 disk->skip_incr = dtype->skip_incr;
431 disk->skip_full = dtype->skip_full;
432 disk->no_hold = dtype->no_hold;
433 disk->kencrypt = dtype->kencrypt;
434 disk->index = dtype->index;
437 skip_whitespace(s, ch);
439 if(ch && ch != '#') { /* get optional spindle number */
440 disk->spindle = atoi(fp);
444 skip_whitespace(s, ch);
446 if(ch && ch != '#') { /* get optional network interface */
447 skip_non_whitespace(s, ch);
449 if((netif = lookup_interface(upcase(fp))) == NULL) {
450 parserror("undefined network interface `%s'", fp);
451 if(host == NULL) amfree(hostname);
457 netif = lookup_interface("");
460 skip_whitespace(s, ch);
461 if(ch && ch != '#') { /* now we have garbage, ignore it */
462 parserror("end of line expected");
465 if(dtype->ignore || dtype->strategy == DS_SKIP) {
467 free_sl(disk->exclude_file);
468 free_sl(disk->exclude_list);
469 free_sl(disk->include_file);
470 free_sl(disk->include_list);
475 /* success, add disk to lists */
477 if(host == NULL) { /* new host */
478 host = alloc(sizeof(host_t));
480 host->next = hostlist;
483 host->hostname = hostname;
486 host->inprogress = 0;
487 host->maxdumps = 1; /* will be overwritten */
491 host->features = NULL;
496 enqueue_disk(&lst, disk);
499 disk->hostnext = host->disks;
501 host->maxdumps = disk->maxdumps;
507 printf_arglist_function(static void parserror, char *, format)
511 /* print error message */
513 fprintf(stderr, "\"%s\", line %d: ", diskfname, line_num);
514 arglist_start(argp, format);
515 vfprintf(stderr, format, argp);
523 void dump_queue(st, q, npr, f)
526 int npr; /* we print first npr disks on queue, plus last two */
533 fprintf(f, "%s QUEUE: empty\n", st);
536 fprintf(f, "%s QUEUE:\n", st);
537 for(pos = 0, d = q.head, p = NULL; d != NULL; p = d, d = d->next, pos++) {
538 if(pos < npr) fprintf(f, "%3d: %-10s %-4s\n",
539 pos, d->host->hostname, d->name);
542 if(pos > npr+2) fprintf(f, " ...\n");
545 fprintf(f, "%3d: %-10s %-4s\n", pos-2, d->host->hostname, d->name);
548 fprintf(f, "%3d: %-10s %-4s\n", pos-1, d->host->hostname, d->name);
552 char *optionstr(dp, their_features, fdout)
554 am_feature_t * their_features;
557 char *auth_opt = NULL;
558 char *kencrypt_opt = "";
559 char *compress_opt = "";
560 char *record_opt = "";
561 char *index_opt = "";
562 char *exclude_file = NULL;
563 char *exclude_list = NULL;
564 char *include_file = NULL;
565 char *include_list = NULL;
574 /* modification by BIS@BBN 4/25/2003:
575 * The first "if" statement has a number of problems, so I removed the
576 * am_has_feature(dp->host->features, fe_options_auth)
577 * condition and caused the first case to always fail.
578 * 1) If dp->host is a NULL pointer, subsequent tests which look
579 * at dp->host->features or dp->host->hostname will cause a dump.
580 * It appears that there should be an assertion that dp->host
582 * 2) The code which checks for the kencrypt feature is only executed
583 * in the case where dp->auth == AUTH_KRB4. If we enable Kerberos IV
584 * in the first case, then the code checking for kencrypt will never
586 * 3) The option processing code in server-src/dumper.c and
587 * client-src/sendbackup.c do not yet handle the "auth=krb4"
588 * option style of specifying Kerberos IV.
589 * Getting rid of the whole first case seems to take care of problems
590 * 2 and 3, but not problem 1.
593 /* && am_has_feature(dp->host->features, fe_options_auth)) */ {
594 auth_opt = stralloc("auth=");
595 if(dp->auth == AUTH_BSD) {
596 strappend(auth_opt, "bsd");
597 } else if(dp->auth == AUTH_KRB4) {
598 strappend(auth_opt, "krb4");
600 strappend(auth_opt, "unknown");
602 strappend(auth_opt, ";");
603 } else if(dp->auth == AUTH_BSD) {
604 if(am_has_feature(dp->host->features, fe_options_bsd_auth)) {
605 auth_opt = stralloc("bsd-auth;");
608 fprintf(fdout, "WARNING: %s:%s does not support bsd-auth\n",
609 dp->host->hostname, dp->name);
611 } else if(dp->auth == AUTH_KRB4) {
612 if(am_has_feature(dp->host->features, fe_options_krb4_auth)) {
613 auth_opt = stralloc("krb4-auth;");
616 fprintf(fdout, "WARNING: %s:%s does not support krb4-auth\n",
617 dp->host->hostname, dp->name);
620 if(am_has_feature(dp->host->features, fe_options_kencrypt)) {
621 kencrypt_opt = "kencrypt;";
625 "WARNING: %s:%s does not support kencrypt\n",
626 dp->host->hostname, dp->name);
631 switch(dp->compress) {
633 if(am_has_feature(their_features, fe_options_compress_fast)) {
634 compress_opt = "compress-fast;";
638 "WARNING: %s:%s does not support fast compression\n",
639 dp->host->hostname, dp->name);
643 if(am_has_feature(their_features, fe_options_compress_best)) {
644 compress_opt = "compress-best;";
648 "WARNING: %s:%s does not support best compression\n",
649 dp->host->hostname, dp->name);
653 if(am_has_feature(their_features, fe_options_srvcomp_fast)) {
654 compress_opt = "srvcomp-fast;";
658 if(am_has_feature(their_features, fe_options_srvcomp_best)) {
659 compress_opt = "srvcomp-best;";
665 if(am_has_feature(their_features, fe_options_no_record)) {
666 record_opt = "no-record;";
669 fprintf(fdout, "WARNING: %s:%s does not support no record\n",
670 dp->host->hostname, dp->name);
675 if(am_has_feature(their_features, fe_options_index)) {
676 index_opt = "index;";
679 fprintf(fdout, "WARNING: %s:%s does not support index\n",
680 dp->host->hostname, dp->name);
684 exclude_file = stralloc("");
686 if(dp->exclude_file != NULL && dp->exclude_file->nb_element > 0) {
687 nb_exclude_file = dp->exclude_file->nb_element;
688 if(am_has_feature(their_features, fe_options_exclude_file)) {
689 if(am_has_feature(their_features, fe_options_multiple_exclude) ||
690 dp->exclude_file->nb_element == 1) {
691 for(excl = dp->exclude_file->first; excl != NULL;
693 exc = newvstralloc( exc, "exclude-file=", excl->name,
695 strappend(exclude_file, exc);
698 exc = newvstralloc(exc, "exclude-file=",
699 dp->exclude_file->last->name, ";", NULL);
700 strappend(exclude_file, exc);
703 "WARNING: %s:%s does not support multiple exclude\n",
704 dp->host->hostname, dp->name);
708 fprintf(fdout, "WARNING: %s:%s does not support exclude file\n",
709 dp->host->hostname, dp->name);
712 exclude_list = stralloc("");
713 if(dp->exclude_list != NULL && dp->exclude_list->nb_element > 0) {
714 if(am_has_feature(their_features, fe_options_exclude_list)) {
715 if(am_has_feature(their_features, fe_options_multiple_exclude) ||
716 (dp->exclude_list->nb_element == 1 && nb_exclude_file == 0)) {
717 for(excl = dp->exclude_list->first; excl != NULL;
719 exc = newvstralloc( exc, "exclude-list=", excl->name,
721 strappend(exclude_list, exc);
724 exc = newvstralloc(exc, "exclude-list=",
725 dp->exclude_list->last->name, ";", NULL);
726 strappend(exclude_list, exc);
729 "WARNING: %s:%s does not support multiple exclude\n",
730 dp->host->hostname, dp->name);
734 fprintf(fdout, "WARNING: %s:%s does not support exclude list\n",
735 dp->host->hostname, dp->name);
739 include_file = stralloc("");
741 if(dp->include_file != NULL && dp->include_file->nb_element > 0) {
742 nb_include_file = dp->include_file->nb_element;
743 if(am_has_feature(their_features, fe_options_include_file)) {
744 if(am_has_feature(their_features, fe_options_multiple_include) ||
745 dp->include_file->nb_element == 1) {
746 for(excl = dp->include_file->first; excl != NULL;
748 exc = newvstralloc( exc, "include-file=", excl->name,
750 strappend(include_file, exc);
753 exc = newvstralloc(exc, "include-file=",
754 dp->include_file->last->name, ";", NULL);
755 strappend(include_file, exc);
758 "WARNING: %s:%s does not support multiple include\n",
759 dp->host->hostname, dp->name);
763 fprintf(fdout, "WARNING: %s:%s does not support include file\n",
764 dp->host->hostname, dp->name);
767 include_list = stralloc("");
768 if(dp->include_list != NULL && dp->include_list->nb_element > 0) {
769 if(am_has_feature(their_features, fe_options_include_list)) {
770 if(am_has_feature(their_features, fe_options_multiple_include) ||
771 (dp->include_list->nb_element == 1 && nb_include_file == 0)) {
772 for(excl = dp->include_list->first; excl != NULL;
774 exc = newvstralloc( exc, "include-list=", excl->name,
776 strappend(include_list, exc);
779 exc = newvstralloc(exc, "include-list=",
780 dp->include_list->last->name, ";", NULL);
781 strappend(include_list, exc);
784 "WARNING: %s:%s does not support multiple include\n",
785 dp->host->hostname, dp->name);
789 fprintf(fdout, "WARNING: %s:%s does not support include list\n",
790 dp->host->hostname, dp->name);
794 if(dp->exclude_optional) {
795 if(am_has_feature(their_features, fe_options_optional_exclude)) {
796 excl_opt = "exclude-optional;";
800 "WARNING: %s:%s does not support optional exclude\n",
801 dp->host->hostname, dp->name);
804 if(dp->include_optional) {
805 if(am_has_feature(their_features, fe_options_optional_include)) {
806 incl_opt = "include-optional;";
810 "WARNING: %s:%s does not support optional include\n",
811 dp->host->hostname, dp->name);
815 result = vstralloc(";",
829 amfree(exclude_file);
830 amfree(exclude_list);
831 amfree(include_file);
832 amfree(include_list);
839 void match_disklist(disklist_t *origqp, int sargc, char **sargv)
841 char *prevhost = NULL;
851 for(dp = origqp->head; dp != NULL; dp = dp->next) {
857 for(i=0;i<sargc;i++) {
859 for(dp = origqp->head; dp != NULL; dp = dp->next) {
860 if(match_host(sargv[i], dp->host->hostname))
864 for(dp = origqp->head; dp != NULL; dp = dp->next) {
865 if(prevhost != NULL &&
866 match_host(prevhost, dp->host->hostname) &&
867 (match_disk(sargv[i], dp->name) ||
868 (dp->device && match_disk(sargv[i], dp->device)))) {
870 error("Argument %s match a host and a disk",sargv[i]);
882 if(match_a_host == 1) {
883 if(prev_match == 1) { /* all disk of the previous host */
884 for(dp = origqp->head; dp != NULL; dp = dp->next) {
885 if(match_host(prevhost,dp->host->hostname))
895 /*error("%s match nothing",sargv[i]);*/
900 if(prev_match == 1) { /* all disk of the previous host */
901 for(dp = origqp->head; dp != NULL; dp = dp->next) {
902 if(match_host(prevhost,dp->host->hostname))
908 for(dp = origqp->head; dp != NULL; dp = dp->next) {
921 printf(" DISK %s (HOST %s, LINE %d) TYPE %s NAME %s SPINDLE %d\n",
922 dp->name, dp->host->hostname, dp->line, dp->dtype_name,
923 dp->name == NULL? "(null)": dp->name,
933 if(hostlist == NULL) {
934 printf("DISKLIST not read in\n");
938 printf("DISKLIST BY HOSTNAME:\n");
940 for(hp = hostlist; hp != NULL; hp = hp->next) {
941 printf("HOST %s INTERFACE %s\n",
943 (hp->netif == NULL||hp->netif->name == NULL) ? "(null)"
945 for(dp = hp->disks; dp != NULL; dp = dp->hostnext)
951 printf("DISKLIST IN FILE ORDER:\n");
954 for(dp = lst.head; dp != NULL; prev = dp, dp = dp->next) {
957 if(dp->prev != prev) printf("*** prev pointer mismatch!\n");
958 if(dp->next == NULL && lst.tail != dp) printf("tail mismatch!\n");
971 unsigned long malloc_hist_1, malloc_size_1;
972 unsigned long malloc_hist_2, malloc_size_2;
974 for(fd = 3; fd < FD_SETSIZE; fd++) {
976 * Make sure nobody spoofs us with a lot of extra open files
977 * that would cause an open we do to get a very high file
978 * descriptor, which in turn might be used as an index into
979 * an array (e.g. an fd_set).
984 set_pname("diskfile");
986 malloc_size_1 = malloc_inuse(&malloc_hist_1);
989 config_name = argv[1];
990 if (strchr(config_name, '/') != NULL) {
991 config_dir = stralloc2(argv[1], "/");
992 config_name = strrchr(config_name, '/') + 1;
994 config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
997 config_dir = stralloc("");
999 conffile = stralloc2(config_dir, CONFFILE_NAME);
1000 if((result = read_conffile(conffile)) == 0) {
1001 conf_diskfile = getconf_str(CNF_DISKFILE);
1002 if (*conf_diskfile == '/') {
1003 conf_diskfile = stralloc(conf_diskfile);
1005 conf_diskfile = stralloc2(config_dir, conf_diskfile);
1007 if((result = (read_diskfile(conf_diskfile) == NULL)) == 0) {
1010 amfree(conf_diskfile);
1015 malloc_size_2 = malloc_inuse(&malloc_hist_2);
1017 if(malloc_size_1 != malloc_size_2) {
1018 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);