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: amadmin.c,v 1.124 2006/07/26 15:17:37 martinea Exp $
30 * controlling process for the Amanda backup system
46 int main(int argc, char **argv);
48 void force(int argc, char **argv);
49 void force_one(disk_t *dp);
50 void unforce(int argc, char **argv);
51 void unforce_one(disk_t *dp);
52 void force_bump(int argc, char **argv);
53 void force_bump_one(disk_t *dp);
54 void force_no_bump(int argc, char **argv);
55 void force_no_bump_one(disk_t *dp);
56 void unforce_bump(int argc, char **argv);
57 void unforce_bump_one(disk_t *dp);
58 void reuse(int argc, char **argv);
59 void noreuse(int argc, char **argv);
60 void info(int argc, char **argv);
61 void info_one(disk_t *dp);
62 void due(int argc, char **argv);
63 void due_one(disk_t *dp);
64 void find(int argc, char **argv);
65 void holding(int argc, char **argv);
66 void delete(int argc, char **argv);
67 void delete_one(disk_t *dp);
68 void balance(int argc, char **argv);
69 void tape(int argc, char **argv);
70 void bumpsize(int argc, char **argv);
71 void diskloop(int argc, char **argv, char *cmdname, void (*func)(disk_t *dp));
72 char *seqdatestr(int seq);
73 static int next_level0(disk_t *dp, info_t *info);
74 int bump_thresh(int level);
75 void export_db(int argc, char **argv);
76 void import_db(int argc, char **argv);
77 void disklist(int argc, char **argv);
78 void disklist_one(disk_t *dp);
79 void show_version(int argc, char **argv);
80 static void show_config(int argc, char **argv);
81 static void check_dumpuser(void);
83 static char *conf_tapelist = NULL;
84 static char *displayunit;
85 static long int unitdivisor;
89 void (*fn)(int, char **);
92 { "version", show_version,
93 "\t\t\t\t\t# Show version info." },
94 { "config", show_config,
95 "\t\t\t\t\t# Show configuration." },
97 " [<hostname> [<disks>]* ]+\t\t# Force level 0 at next run." },
99 " [<hostname> [<disks>]* ]+\t# Clear force command." },
100 { "force-bump", force_bump,
101 " [<hostname> [<disks>]* ]+\t# Force bump at next run." },
102 { "force-no-bump", force_no_bump,
103 " [<hostname> [<disks>]* ]+\t# Force no-bump at next run." },
104 { "unforce-bump", unforce_bump,
105 " [<hostname> [<disks>]* ]+\t# Clear bump command." },
106 { "disklist", disklist,
107 " [<hostname> [<disks>]* ]*\t# Debug disklist entries." },
109 " <tapelabel> ...\t\t # re-use this tape." },
110 { "no-reuse", noreuse,
111 " <tapelabel> ...\t # never re-use this tape." },
113 " [<hostname> [<disks>]* ]*\t # Show which tapes these dumps are on." },
114 { "holding", holding,
115 " {list [ -l ] |delete} [ <hostname> [ <disk> [ <datestamp> [ .. ] ] ] ]+\t # Show or delete holding disk contents." },
117 " [<hostname> [<disks>]* ]+ # Delete from database." },
119 " [<hostname> [<disks>]* ]*\t # Show current info records." },
121 " [<hostname> [<disks>]* ]*\t # Show due date." },
122 { "balance", balance,
123 " [-days <num>]\t\t # Show nightly dump size balance." },
125 " [-days <num>]\t\t # Show which tape is due next." },
126 { "bumpsize", bumpsize,
127 "\t\t\t # Show current bump thresholds." },
128 { "export", export_db,
129 " [<hostname> [<disks>]* ]* # Export curinfo database to stdout." },
130 { "import", import_db,
131 "\t\t\t\t # Import curinfo database from stdin." },
133 #define NCMDS (int)(sizeof(cmdtab) / sizeof(cmdtab[0]))
135 static char *conffile;
145 unsigned long malloc_hist_1, malloc_size_1;
146 unsigned long malloc_hist_2, malloc_size_2;
153 set_pname("amadmin");
155 dbopen(DBG_SUBDIR_SERVER);
157 /* Don't die when child closes pipe */
158 signal(SIGPIPE, SIG_IGN);
160 malloc_size_1 = malloc_inuse(&malloc_hist_1);
162 erroutput_type = ERR_INTERACTIVE;
164 parse_conf(argc, argv, &new_argc, &new_argv);
166 if(new_argc < 3) usage();
168 if(strcmp(new_argv[2],"version") == 0) {
169 show_version(new_argc, new_argv);
173 config_name = new_argv[1];
175 config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
176 conffile = stralloc2(config_dir, CONFFILE_NAME);
178 if(read_conffile(conffile)) {
179 error("errors processing config file \"%s\"", conffile);
183 dbrename(config_name, DBG_SUBDIR_SERVER);
185 report_bad_conf_arg();
189 conf_diskfile = getconf_str(CNF_DISKFILE);
190 if (*conf_diskfile == '/') {
191 conf_diskfile = stralloc(conf_diskfile);
193 conf_diskfile = stralloc2(config_dir, conf_diskfile);
195 if (read_diskfile(conf_diskfile, &diskq) < 0) {
196 error("could not load disklist \"%s\"", conf_diskfile);
199 amfree(conf_diskfile);
201 conf_tapelist = getconf_str(CNF_TAPELIST);
202 if (*conf_tapelist == '/') {
203 conf_tapelist = stralloc(conf_tapelist);
205 conf_tapelist = stralloc2(config_dir, conf_tapelist);
207 if(read_tapelist(conf_tapelist)) {
208 error("could not load tapelist \"%s\"", conf_tapelist);
211 conf_infofile = getconf_str(CNF_INFOFILE);
212 if (*conf_infofile == '/') {
213 conf_infofile = stralloc(conf_infofile);
215 conf_infofile = stralloc2(config_dir, conf_infofile);
217 if(open_infofile(conf_infofile)) {
218 error("could not open info db \"%s\"", conf_infofile);
221 amfree(conf_infofile);
223 displayunit = getconf_str(CNF_DISPLAYUNIT);
224 unitdivisor = getconf_unit_divisor();
226 for (i = 0; i < NCMDS; i++)
227 if (strcmp(new_argv[2], cmdtab[i].name) == 0) {
228 (*cmdtab[i].fn)(new_argc, new_argv);
232 fprintf(stderr, "%s: unknown command \"%s\"\n", new_argv[0], new_argv[2]);
236 free_new_argv(new_argc, new_argv);
240 amfree(conf_tapelist);
245 malloc_size_2 = malloc_inuse(&malloc_hist_2);
247 if(malloc_size_1 != malloc_size_2) {
248 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
252 free_disklist(&diskq);
253 free_server_config();
264 fprintf(stderr, "\nUsage: %s%s <conf> <command> {<args>} [-o configoption]* ...\n",
265 get_pname(), versionsuffix());
266 fprintf(stderr, " Valid <command>s are:\n");
267 for (i = 0; i < NCMDS; i++)
268 fprintf(stderr, "\t%s%s\n", cmdtab[i].name, cmdtab[i].usage);
273 /* ----------------------------------------------- */
275 #define SECS_PER_DAY (24*60*60)
283 static char *dow[7] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
284 time_t t = today + seq*SECS_PER_DAY;
290 snprintf(str, SIZEOF(str),
291 "%2d/%02d %3s", tm->tm_mon+1, tm->tm_mday, dow[tm->tm_wday]);
293 strcpy(str, "BAD DATE");
299 #define days_diff(a, b) (int)(((b) - (a) + SECS_PER_DAY) / SECS_PER_DAY)
301 /* when is next level 0 due? 0 = tonight, 1 = tommorrow, etc*/
307 if(dp->strategy == DS_NOFULL)
308 return 1; /* fake it */
309 if(info->inf[0].date < (time_t)0)
310 return 0; /* new disk */
312 return dp->dumpcycle - days_diff(info->inf[0].date, today);
318 static int been_here = 0;
328 uid_dumpuser = uid_me;
329 dumpuser = getconf_str(CNF_DUMPUSER);
331 if ((pw = getpwnam(dumpuser)) == NULL) {
332 error("cannot look up dump user \"%s\"", dumpuser);
335 uid_dumpuser = pw->pw_uid;
336 if ((pw = getpwuid(uid_me)) == NULL) {
337 error("cannot look up my own uid %ld", (long)uid_me);
340 if (uid_me != uid_dumpuser) {
341 error("ERROR: running as user \"%s\" instead of \"%s\"",
342 pw->pw_name, dumpuser);
349 /* ----------------------------------------------- */
356 void (*func)(disk_t *dp))
363 fprintf(stderr,"%s: expecting \"%s [<hostname> [<disks>]* ]+\"\n",
364 get_pname(), cmdname);
368 errstr = match_disklist(&diskq, argc-3, argv+3);
370 printf("%s", errstr);
374 for(dp = diskq.head; dp != NULL; dp = dp->next) {
381 fprintf(stderr,"%s: no disk matched\n",get_pname());
385 /* ----------------------------------------------- */
392 char *hostname = dp->host->hostname;
393 char *diskname = dp->name;
399 get_info(hostname, diskname, &info);
400 SET(info.command, FORCE_FULL);
401 if (ISSET(info.command, FORCE_BUMP)) {
402 CLR(info.command, FORCE_BUMP);
403 printf("%s: WARNING: %s:%s FORCE_BUMP command was cleared.\n",
404 get_pname(), hostname, diskname);
406 if(put_info(hostname, diskname, &info) == 0) {
407 printf("%s: %s:%s is set to a forced level 0 at next run.\n",
408 get_pname(), hostname, diskname);
410 fprintf(stderr, "%s: %s:%s could not be forced.\n",
411 get_pname(), hostname, diskname);
421 diskloop(argc, argv, "force", force_one);
425 /* ----------------------------------------------- */
432 char *hostname = dp->host->hostname;
433 char *diskname = dp->name;
436 get_info(hostname, diskname, &info);
437 if (ISSET(info.command, FORCE_FULL)) {
441 CLR(info.command, FORCE_FULL);
442 if(put_info(hostname, diskname, &info) == 0){
443 printf("%s: force command for %s:%s cleared.\n",
444 get_pname(), hostname, diskname);
447 "%s: force command for %s:%s could not be cleared.\n",
448 get_pname(), hostname, diskname);
452 printf("%s: no force command outstanding for %s:%s, unchanged.\n",
453 get_pname(), hostname, diskname);
462 diskloop(argc, argv, "unforce", unforce_one);
466 /* ----------------------------------------------- */
473 char *hostname = dp->host->hostname;
474 char *diskname = dp->name;
480 get_info(hostname, diskname, &info);
481 SET(info.command, FORCE_BUMP);
482 if (ISSET(info.command, FORCE_NO_BUMP)) {
483 CLR(info.command, FORCE_NO_BUMP);
484 printf("%s: WARNING: %s:%s FORCE_NO_BUMP command was cleared.\n",
485 get_pname(), hostname, diskname);
487 if (ISSET(info.command, FORCE_FULL)) {
488 CLR(info.command, FORCE_FULL);
489 printf("%s: WARNING: %s:%s FORCE_FULL command was cleared.\n",
490 get_pname(), hostname, diskname);
492 if(put_info(hostname, diskname, &info) == 0) {
493 printf("%s: %s:%s is set to bump at next run.\n",
494 get_pname(), hostname, diskname);
496 fprintf(stderr, "%s: %s:%s could not be forced to bump.\n",
497 get_pname(), hostname, diskname);
507 diskloop(argc, argv, "force-bump", force_bump_one);
511 /* ----------------------------------------------- */
518 char *hostname = dp->host->hostname;
519 char *diskname = dp->name;
525 get_info(hostname, diskname, &info);
526 SET(info.command, FORCE_NO_BUMP);
527 if (ISSET(info.command, FORCE_BUMP)) {
528 CLR(info.command, FORCE_BUMP);
529 printf("%s: WARNING: %s:%s FORCE_BUMP command was cleared.\n",
530 get_pname(), hostname, diskname);
532 if(put_info(hostname, diskname, &info) == 0) {
533 printf("%s: %s:%s is set to not bump at next run.\n",
534 get_pname(), hostname, diskname);
536 fprintf(stderr, "%s: %s:%s could not be force to not bump.\n",
537 get_pname(), hostname, diskname);
547 diskloop(argc, argv, "force-no-bump", force_no_bump_one);
551 /* ----------------------------------------------- */
558 char *hostname = dp->host->hostname;
559 char *diskname = dp->name;
562 get_info(hostname, diskname, &info);
563 if (ISSET(info.command, FORCE_BUMP|FORCE_NO_BUMP)) {
567 CLR(info.command, FORCE_BUMP|FORCE_NO_BUMP);
568 if(put_info(hostname, diskname, &info) == 0) {
569 printf("%s: bump command for %s:%s cleared.\n",
570 get_pname(), hostname, diskname);
572 fprintf(stderr, "%s: %s:%s bump command could not be cleared.\n",
573 get_pname(), hostname, diskname);
577 printf("%s: no bump command outstanding for %s:%s, unchanged.\n",
578 get_pname(), hostname, diskname);
588 diskloop(argc, argv, "unforce-bump", unforce_bump_one);
592 /* ----------------------------------------------- */
603 fprintf(stderr,"%s: expecting \"reuse <tapelabel> ...\"\n",
609 for(count=3; count< argc; count++) {
610 tp = lookup_tapelabel(argv[count]);
612 fprintf(stderr, "reuse: tape label %s not found in tapelist.\n",
616 if( tp->reuse == 0 ) {
618 printf("%s: marking tape %s as reusable.\n",
619 get_pname(), argv[count]);
621 fprintf(stderr, "%s: tape %s already reusable.\n",
622 get_pname(), argv[count]);
626 if(write_tapelist(conf_tapelist)) {
627 error("could not write tapelist \"%s\"", conf_tapelist);
641 fprintf(stderr,"%s: expecting \"no-reuse <tapelabel> ...\"\n",
647 for(count=3; count< argc; count++) {
648 tp = lookup_tapelabel(argv[count]);
650 fprintf(stderr, "no-reuse: tape label %s not found in tapelist.\n",
654 if( tp->reuse == 1 ) {
656 printf("%s: marking tape %s as not reusable.\n",
657 get_pname(), argv[count]);
659 fprintf(stderr, "%s: tape %s already not reusable.\n",
660 get_pname(), argv[count]);
664 if(write_tapelist(conf_tapelist)) {
665 error("could not write tapelist \"%s\"", conf_tapelist);
671 /* ----------------------------------------------- */
679 char *hostname = dp->host->hostname;
680 char *diskname = dp->name;
683 if(get_info(hostname, diskname, &info)) {
684 printf("%s: %s:%s NOT currently in database.\n",
685 get_pname(), hostname, diskname);
690 if(del_info(hostname, diskname)) {
691 error("couldn't delete %s:%s from database: %s",
692 hostname, diskname, strerror(errno));
695 printf("%s: %s:%s deleted from curinfo database.\n",
696 get_pname(), hostname, diskname);
706 diskloop(argc, argv, "delete", delete_one);
710 "%s: NOTE: you'll have to remove these from the disklist yourself.\n",
714 /* ----------------------------------------------- */
725 get_info(dp->host->hostname, dp->name, &info);
727 printf("\nCurrent info for %s %s:\n", dp->host->hostname, dp->name);
728 if (ISSET(info.command, FORCE_FULL))
729 printf(" (Forcing to level 0 dump at next run)\n");
730 if (ISSET(info.command, FORCE_BUMP))
731 printf(" (Forcing bump at next run)\n");
732 if (ISSET(info.command, FORCE_NO_BUMP))
733 printf(" (Forcing no-bump at next run)\n");
734 printf(" Stats: dump rates (kps), Full: %5.1lf, %5.1lf, %5.1lf\n",
735 info.full.rate[0], info.full.rate[1], info.full.rate[2]);
736 printf(" Incremental: %5.1lf, %5.1lf, %5.1lf\n",
737 info.incr.rate[0], info.incr.rate[1], info.incr.rate[2]);
738 printf(" compressed size, Full: %5.1lf%%,%5.1lf%%,%5.1lf%%\n",
739 info.full.comp[0]*100, info.full.comp[1]*100, info.full.comp[2]*100);
740 printf(" Incremental: %5.1lf%%,%5.1lf%%,%5.1lf%%\n",
741 info.incr.comp[0]*100, info.incr.comp[1]*100, info.incr.comp[2]*100);
743 printf(" Dumps: lev datestmp tape file origK compK secs\n");
744 for(lev = 0, sp = &info.inf[0]; lev < 9; lev++, sp++) {
745 if(sp->date < (time_t)0 && sp->label[0] == '\0') continue;
746 tm = localtime(&sp->date);
748 printf(" %d %04d%02d%02d %-15s "
749 OFF_T_FMT " " OFF_T_FMT " " OFF_T_FMT " " TIME_T_FMT "\n",
750 lev, tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
752 (OFF_T_FMT_TYPE)sp->filenum,
753 (OFF_T_FMT_TYPE)sp->size,
754 (OFF_T_FMT_TYPE)sp->csize,
755 (TIME_T_FMT_TYPE)sp->secs);
757 printf(" %d BAD-DATE %-15s "
758 OFF_T_FMT " " OFF_T_FMT " " OFF_T_FMT " " TIME_T_FMT "\n",
761 (OFF_T_FMT_TYPE)sp->filenum,
762 (OFF_T_FMT_TYPE)sp->size,
763 (OFF_T_FMT_TYPE)sp->csize,
764 (TIME_T_FMT_TYPE)sp->secs);
778 diskloop(argc, argv, "info", info_one);
780 for(dp = diskq.head; dp != NULL; dp = dp->next)
784 /* ----------------------------------------------- */
795 if(get_info(hp->hostname, dp->name, &info)) {
796 printf("new disk %s:%s ignored.\n", hp->hostname, dp->name);
799 days = next_level0(dp, &info);
801 printf("Overdue %2d day%s %s:%s\n",
802 -days, (-days == 1) ? ": " : "s:",
803 hp->hostname, dp->name);
806 printf("Due today: %s:%s\n", hp->hostname, dp->name);
809 printf("Due in %2d day%s %s:%s\n", days,
810 (days == 1) ? ": " : "s:",
811 hp->hostname, dp->name);
825 diskloop(argc, argv, "due", due_one);
827 for(dp = diskq.head; dp != NULL; dp = dp->next)
831 /* ----------------------------------------------- */
842 if(argc > 4 && strcmp(argv[3],"--days") == 0) {
843 nb_days = atoi(argv[4]);
845 printf("days must be an integer bigger than 0\n");
852 runtapes = getconf_int(CNF_RUNTAPES);
853 tp = lookup_last_reusable_tape(0);
855 for ( j=0 ; j < nb_days ; j++ ) {
856 for ( i=0 ; i < runtapes ; i++ ) {
858 printf("The next Amanda run should go onto ");
862 printf("tape %s or a new tape.\n", tp->label);
864 if (runtapes - i == 1)
865 printf("1 new tape.\n");
867 printf("%d new tapes.\n", runtapes - i);
871 tp = lookup_last_reusable_tape(i + 1);
874 lasttp = lookup_tapepos(lookup_nb_tape());
876 if(lasttp && i > 0 && strcmp(lasttp->datestamp,"0") == 0) {
878 while(lasttp && i > 0 && strcmp(lasttp->datestamp,"0") == 0) {
880 lasttp = lasttp->prev;
883 lasttp = lookup_tapepos(lookup_nb_tape());
886 printf("The next new tape already labelled is: %s.\n",
890 printf("The next %d new tapes already labelled are: %s", c,
892 lasttp = lasttp->prev;
894 while(lasttp && c > 0 && strcmp(lasttp->datestamp,"0") == 0) {
895 printf(", %s", lasttp->label);
896 lasttp = lasttp->prev;
904 /* ----------------------------------------------- */
912 struct balance_stats {
914 off_t origsize, outsize;
916 int conf_runspercycle, conf_dumpcycle;
917 int seq, runs_per_cycle, overdue, max_overdue;
918 int later, total, balance, distinct;
919 double fseq, disk_dumpcycle;
921 off_t total_balanced, balanced;
925 conf_dumpcycle = getconf_int(CNF_DUMPCYCLE);
926 conf_runspercycle = getconf_int(CNF_RUNSPERCYCLE);
927 later = conf_dumpcycle;
931 if(argc > 4 && strcmp(argv[3],"--days") == 0) {
932 later = atoi(argv[4]);
933 if(later < 0) later = conf_dumpcycle;
935 if(later > 10000) later = 10000;
937 if(conf_runspercycle == 0) {
938 runs_per_cycle = conf_dumpcycle;
939 } else if(conf_runspercycle == -1 ) {
940 runs_per_cycle = guess_runs_from_tapelist();
942 runs_per_cycle = conf_runspercycle;
944 if (runs_per_cycle <= 0) {
950 distinct = later + 3;
952 sp = (struct balance_stats *)
953 alloc(SIZEOF(struct balance_stats) * (distinct+1));
955 for(seq=0; seq <= distinct; seq++) {
957 sp[seq].origsize = sp[seq].outsize = (off_t)0;
960 for(dp = diskq.head; dp != NULL; dp = dp->next) {
961 if(get_info(dp->host->hostname, dp->name, &info)) {
962 printf("new disk %s:%s ignored.\n", dp->host->hostname, dp->name);
965 if (dp->strategy == DS_NOFULL) {
968 sp[distinct].disks++;
969 sp[distinct].origsize += info.inf[0].size/(off_t)unitdivisor;
970 sp[distinct].outsize += info.inf[0].csize/(off_t)unitdivisor;
973 if(dp->dumpcycle == 0) {
974 sp[balance].origsize += (info.inf[0].size/(off_t)unitdivisor) * (off_t)runs_per_cycle;
975 sp[balance].outsize += (info.inf[0].csize/(off_t)unitdivisor) * (off_t)runs_per_cycle;
978 sp[balance].origsize += (info.inf[0].size/(off_t)unitdivisor) *
979 (off_t)(conf_dumpcycle / dp->dumpcycle);
980 sp[balance].outsize += (info.inf[0].csize/(off_t)unitdivisor) *
981 (off_t)(conf_dumpcycle / dp->dumpcycle);
984 disk_dumpcycle = (double)dp->dumpcycle;
985 if(dp->dumpcycle <= 0)
986 disk_dumpcycle = ((double)conf_dumpcycle) / ((double)runs_per_cycle);
988 seq = next_level0(dp, &info);
993 if (-seq > max_overdue)
1003 sp[seq].origsize += info.inf[0].size/(off_t)unitdivisor;
1004 sp[seq].outsize += info.inf[0].csize/(off_t)unitdivisor;
1008 sp[total].origsize += info.inf[0].size/(off_t)unitdivisor;
1009 sp[total].outsize += info.inf[0].csize/(off_t)unitdivisor;
1012 /* See, if there's another run in this dumpcycle */
1013 fseq += disk_dumpcycle;
1015 } while (seq < later);
1018 if(sp[total].outsize == (off_t)0 && sp[later].outsize == (off_t)0) {
1019 printf("\nNo data to report on yet.\n");
1024 balanced = sp[balance].outsize / (off_t)runs_per_cycle;
1025 if(conf_dumpcycle == later) {
1026 total_balanced = sp[total].outsize / (off_t)runs_per_cycle;
1029 total_balanced = (((sp[total].outsize/(off_t)1024) * (off_t)conf_dumpcycle)
1030 / (off_t)(runs_per_cycle * later)) * (off_t)1024;
1034 printf("\n due-date #fs orig %cB out %cB balance\n",
1035 displayunit[0], displayunit[0]);
1036 printf("----------------------------------------------\n");
1037 for(seq = 0; seq < later; seq++) {
1038 if(sp[seq].disks == 0 &&
1039 ((seq > 0 && sp[seq-1].disks == 0) ||
1040 ((seq < later-1) && sp[seq+1].disks == 0))) {
1048 printf("%-9.9s %3d " OFF_T_FMT " " OFF_T_FMT " ",
1049 seqdatestr(seq), sp[seq].disks,
1050 (OFF_T_FMT_TYPE)sp[seq].origsize,
1051 (OFF_T_FMT_TYPE)sp[seq].outsize);
1052 if(!sp[seq].outsize) printf(" --- \n");
1053 else printf("%+8.1lf%%\n",
1054 (((double)sp[seq].outsize - (double)balanced) * 100.0 /
1059 if(sp[later].disks != 0) {
1060 printf("later %3d " OFF_T_FMT " " OFF_T_FMT " ",
1062 (OFF_T_FMT_TYPE)sp[later].origsize,
1063 (OFF_T_FMT_TYPE)sp[later].outsize);
1064 if(!sp[later].outsize) printf(" --- \n");
1065 else printf("%+8.1lf%%\n",
1066 (((double)sp[later].outsize - (double)balanced) * 100.0 /
1069 printf("----------------------------------------------\n");
1070 printf("TOTAL %3d " OFF_T_FMT " " OFF_T_FMT " " OFF_T_FMT "\n",
1072 (OFF_T_FMT_TYPE)sp[total].origsize,
1073 (OFF_T_FMT_TYPE)sp[total].outsize,
1074 (OFF_T_FMT_TYPE)total_balanced);
1075 if (sp[balance].origsize != sp[total].origsize ||
1076 sp[balance].outsize != sp[total].outsize ||
1077 balanced != total_balanced) {
1078 printf("BALANCED " OFF_T_FMT " " OFF_T_FMT " " OFF_T_FMT "\n",
1079 (OFF_T_FMT_TYPE)sp[balance].origsize,
1080 (OFF_T_FMT_TYPE)sp[balance].outsize,
1081 (OFF_T_FMT_TYPE)balanced);
1083 if (sp[distinct].disks != sp[total].disks) {
1084 printf("DISTINCT %3d " OFF_T_FMT " " OFF_T_FMT "\n",
1086 (OFF_T_FMT_TYPE)sp[distinct].origsize,
1087 (OFF_T_FMT_TYPE)sp[distinct].outsize);
1089 printf(" (estimated %d run%s per dumpcycle)\n",
1090 runs_per_cycle, (runs_per_cycle == 1) ? "" : "s");
1092 printf(" (%d filesystem%s overdue, the most being overdue %d day%s)\n",
1093 overdue, (overdue == 1) ? "" : "s",
1094 max_overdue, (max_overdue == 1) ? "" : "s");
1100 /* ----------------------------------------------- */
1108 char *sort_order = NULL;
1109 find_result_t *output_find;
1114 "%s: expecting \"find [--sort <hkdlpb>] [hostname [<disk>]]*\"\n",
1120 sort_order = newstralloc(sort_order, DEFAULT_SORT_ORDER);
1121 if(argc > 4 && strcmp(argv[3],"--sort") == 0) {
1122 size_t i, valid_sort=1;
1124 for(i = strlen(argv[4]); i > 0; i--) {
1125 switch (argv[4][i - 1]) {
1139 default: valid_sort=0;
1143 sort_order = newstralloc(sort_order, argv[4]);
1145 printf("Invalid sort order: %s\n", argv[4]);
1146 printf("Use default sort order: %s\n", sort_order);
1152 errstr = match_disklist(&diskq, argc-(start_argc-1), argv+(start_argc-1));
1154 printf("%s", errstr);
1158 output_find = find_dump(1, &diskq);
1159 if(argc-(start_argc-1) > 0) {
1160 free_find_result(&output_find);
1161 errstr = match_disklist(&diskq, argc-(start_argc-1),
1162 argv+(start_argc-1));
1164 printf("%s", errstr);
1167 output_find = find_dump(0, NULL);
1170 sort_find_result(sort_order, &output_find);
1171 print_find_result(output_find);
1172 free_find_result(&output_find);
1178 /* ------------------------ */
1186 sl_t * file_list = NULL;
1187 dumpspec_list_t * dumplist;
1190 dumplist = cmdline_parse_dumpspecs(argc, argv);
1192 fprintf(stderr, _("Could not get dump list\n"));
1196 file_list = cmdline_match_holding(dumplist);
1197 dumpspec_free_list(dumplist);
1198 } else if (allow_empty) {
1199 /* just list all of them */
1200 file_list = holding_get_files(NULL, NULL, 1);
1207 remove_holding_file_from_catalog(
1210 static int warnings_printed; /* only print once per invocation */
1216 int matching_hist_idx = -1;
1217 history_t matching_hist; /* will be a copy */
1221 if (!holding_file_read_header(filename, &host, &disk, &level, &datestamp)) {
1222 printf(_("Could not read holding file %s\n"), filename);
1226 if (get_info(host, disk, &info) == -1) {
1227 printf(_("WARNING: No curinfo record for %s:%s\n"), host, disk);
1228 return 1; /* not an error */
1231 /* Begin by trying to find the history element matching this dump.
1232 * The datestamp on the dump is for the entire run of amdump, while the
1233 * 'date' in the history element of 'info' is the time the dump itself
1234 * began. A matching history element, then, is the earliest element
1235 * with a 'date' equal to or later than the date of the dumpfile.
1237 * We compare using formatted datestamps; even using seconds since epoch,
1238 * we would still face timezone issues, and have to do a reverse (timezone
1239 * to gmt) translation.
1242 /* get to the end of the history list and search backward */
1243 for (nhist = 0; info.history[nhist].level > -1; nhist++) /* empty loop */;
1244 for (i = nhist-1; i > -1; i--) {
1245 char *info_datestamp = construct_timestamp(&info.history[i].date);
1246 int order = strcmp(datestamp, info_datestamp);
1247 amfree(info_datestamp);
1250 /* only a match if the levels are equal */
1251 if (info.history[i].level == level) {
1252 matching_hist_idx = i;
1253 matching_hist = info.history[matching_hist_idx];
1259 if (matching_hist_idx == -1) {
1260 printf(_("WARNING: No dump matching %s found in curinfo.\n"), filename);
1261 return 1; /* not an error */
1264 /* Remove the history element itself before doing the stats */
1265 for (i = matching_hist_idx; i <= NB_HISTORY; i++) {
1266 info.history[i] = info.history[i+1];
1268 info.history[NB_HISTORY].level = -1;
1270 /* Remove stats for that history element, if necessary. Doing so
1271 * will result in an inconsistent set of backups, so we warn the
1272 * user and adjust last_level to make the next dump get us a
1273 * consistent picture. */
1274 if (matching_hist.date == info.inf[matching_hist.level].date) {
1275 /* search for an earlier dump at this level */
1276 for (i = matching_hist_idx; info.history[i].level > -1; i++) {
1277 if (info.history[i].level == matching_hist.level)
1281 if (info.history[i].level < 0) {
1282 /* not found => zero it out */
1283 info.inf[matching_hist.level].date = (time_t)-1; /* flag as not set */
1284 info.inf[matching_hist.level].label[0] = '\0';
1286 /* found => reconstruct stats as best we can */
1287 info.inf[matching_hist.level].size = info.history[i].size;
1288 info.inf[matching_hist.level].csize = info.history[i].csize;
1289 info.inf[matching_hist.level].secs = info.history[i].secs;
1290 info.inf[matching_hist.level].date = info.history[i].date;
1291 info.inf[matching_hist.level].filenum = 0; /* we don't know */
1292 info.inf[matching_hist.level].label[0] = '\0'; /* we don't know */
1295 /* set last_level to the level we just deleted, and set command
1296 * appropriately to make sure planner does a new dump at this level
1298 info.last_level = matching_hist.level;
1299 if (info.last_level == 0) {
1300 printf(_("WARNING: Deleting the most recent full dump; forcing a full dump at next run.\n"));
1301 SET(info.command, FORCE_FULL);
1303 printf(_("WARNING: Deleting the most recent level %d dump; forcing a level %d dump or \nWARNING: lower at next run.\n"),
1304 info.last_level, info.last_level);
1305 SET(info.command, FORCE_NO_BUMP);
1308 /* Search for and display any subsequent runs that depended on this one */
1309 warnings_printed = 0;
1310 for (i = matching_hist_idx-1; i >= 0; i--) {
1312 if (info.history[i].level <= matching_hist.level) break;
1314 datestamp = construct_timestamp(&info.history[i].date);
1315 printf(_("WARNING: Level %d dump made %s can no longer be accurately restored.\n"),
1316 info.history[i].level, datestamp);
1319 warnings_printed = 1;
1321 if (warnings_printed)
1322 printf(_("WARNING: (note, dates shown above are for dumps, and may be later than the\nWARNING: corresponding run date)\n"));
1325 /* recalculate consecutive_runs based on the history: find the first run
1326 * at this level, and then count the consecutive runs at that level. This
1327 * number may be zero (if we just deleted the last run at this level) */
1328 info.consecutive_runs = 0;
1329 for (i = 0; info.history[i].level >= 0; i++) {
1330 if (info.history[i].level == info.last_level) break;
1332 while (info.history[i+info.consecutive_runs].level == info.last_level)
1333 info.consecutive_runs++;
1335 /* this function doesn't touch the performance stats */
1337 /* write out the changes */
1338 if (put_info(host, disk, &info) == -1) {
1339 printf(_("Could not write curinfo record for %s:%s\n"), host, disk);
1352 enum { HOLDING_USAGE, HOLDING_LIST, HOLDING_DELETE } action = HOLDING_USAGE;
1360 action = HOLDING_USAGE;
1361 else if (strcmp(argv[3], "list") == 0 && argc >= 4)
1362 action = HOLDING_LIST;
1363 else if (strcmp(argv[3], "delete") == 0 && argc > 4)
1364 action = HOLDING_DELETE;
1366 holding_set_verbosity(1);
1371 _("%s: expecting \"holding list [-l]\" or \"holding delete <host> [ .. ]\"\n"),
1377 argc -= 4; argv += 4;
1378 if (argc && strcmp(argv[0], "-l") == 0) {
1383 file_list = get_file_list(argc, argv, 1);
1385 printf("%-10s %-2s %s\n", "size (kB)", "lv", "dump specification");
1387 for (h = file_list->first; h != NULL; h = h->next) {
1389 if (!holding_file_read_header(h->name, &host, &disk, &level, &datestamp)) {
1390 fprintf(stderr, _("Error reading %s\n"), h->name);
1394 dumpstr = cmdline_format_dumpspec_components(host, disk, datestamp);
1396 printf("%-10"OFF_T_RFMT" %-2d %s\n",
1397 (OFF_T_FMT_TYPE)holding_file_size(h->name, 0), level, dumpstr);
1399 printf("%s\n", dumpstr);
1406 case HOLDING_DELETE:
1407 argc -= 4; argv += 4;
1409 file_list = get_file_list(argc, argv, 0);
1410 for (h = file_list->first; h != NULL; h = h->next) {
1411 fprintf(stderr, _("Deleting '%s'\n"), h->name);
1412 /* remove it from the catalog */
1413 if (!remove_holding_file_from_catalog(h->name))
1417 if (!holding_file_unlink(h->name)) {
1418 /* holding_file_unlink printed an error message */
1428 /* ------------------------ */
1431 /* shared code with planner.c */
1437 int bump = getconf_int(CNF_BUMPSIZE);
1438 double mult = getconf_real(CNF_BUMPMULT);
1441 bump = (int)((double)bump * mult);
1451 int conf_bumppercent = getconf_int(CNF_BUMPPERCENT);
1452 double conf_bumpmult = getconf_real(CNF_BUMPMULT);
1454 (void)argc; /* Quiet unused parameter warning */
1455 (void)argv; /* Quiet unused parameter warning */
1457 printf("Current bump parameters:\n");
1458 if(conf_bumppercent == 0) {
1459 printf(" bumpsize %5d KB\t- minimum savings (threshold) to bump level 1 -> 2\n",
1460 getconf_int(CNF_BUMPSIZE));
1461 printf(" bumpdays %5d\t- minimum days at each level\n",
1462 getconf_int(CNF_BUMPDAYS));
1463 printf(" bumpmult %5.5lg\t- threshold = bumpsize * bumpmult**(level-1)\n\n",
1466 printf(" Bump -> To Threshold\n");
1467 for(l = 1; l < 9; l++)
1468 printf("\t%d -> %d %9d KB\n", l, l+1, bump_thresh(l));
1472 double bumppercent = (double)conf_bumppercent;
1474 printf(" bumppercent %3d %%\t- minimum savings (threshold) to bump level 1 -> 2\n",
1476 printf(" bumpdays %5d\t- minimum days at each level\n",
1477 getconf_int(CNF_BUMPDAYS));
1478 printf(" bumpmult %5.5lg\t- threshold = disk_size * bumppercent * bumpmult**(level-1)\n\n",
1480 printf(" Bump -> To Threshold\n");
1481 for(l = 1; l < 9; l++) {
1482 printf("\t%d -> %d %7.2lf %%\n", l, l+1, bumppercent);
1483 bumppercent *= conf_bumpmult;
1484 if(bumppercent >= 100.000) { bumppercent = 100.0;}
1490 /* ----------------------------------------------- */
1492 void export_one(disk_t *dp);
1501 char hostname[MAX_HOSTNAME_LENGTH+1];
1504 printf("CURINFO Version %s CONF %s\n", version(), getconf_str(CNF_ORG));
1507 if(gethostname(hostname, SIZEOF(hostname)-1) == -1) {
1508 error("could not determine host name: %s\n", strerror(errno));
1511 hostname[SIZEOF(hostname)-1] = '\0';
1512 printf("# Generated by:\n# host: %s\n# date: %s",
1513 hostname, ctime(&curtime));
1515 printf("# command:");
1516 for(i = 0; i < argc; i++)
1517 printf(" %s", argv[i]);
1519 printf("\n# This file can be merged back in with \"amadmin import\".\n");
1520 printf("# Edit only with care.\n");
1523 diskloop(argc, argv, "export", export_one);
1524 else for(dp = diskq.head; dp != NULL; dp = dp->next)
1535 if(get_info(dp->host->hostname, dp->name, &info)) {
1536 fprintf(stderr, "Warning: no curinfo record for %s:%s\n",
1537 dp->host->hostname, dp->name);
1540 printf("host: %s\ndisk: %s\n", dp->host->hostname, dp->name);
1541 printf("command: %u\n", info.command);
1542 printf("last_level: %d\n",info.last_level);
1543 printf("consecutive_runs: %d\n",info.consecutive_runs);
1544 printf("full-rate:");
1545 for(i=0;i<AVG_COUNT;i++) printf(" %lf", info.full.rate[i]);
1546 printf("\nfull-comp:");
1547 for(i=0;i<AVG_COUNT;i++) printf(" %lf", info.full.comp[i]);
1549 printf("\nincr-rate:");
1550 for(i=0;i<AVG_COUNT;i++) printf(" %lf", info.incr.rate[i]);
1551 printf("\nincr-comp:");
1552 for(i=0;i<AVG_COUNT;i++) printf(" %lf", info.incr.comp[i]);
1554 for(l=0;l<DUMP_LEVELS;l++) {
1555 if(info.inf[l].date < (time_t)0 && info.inf[l].label[0] == '\0') continue;
1556 printf("stats: %d " OFF_T_FMT " " OFF_T_FMT " " TIME_T_FMT " " TIME_T_FMT " " OFF_T_FMT " %s\n", l,
1557 (OFF_T_FMT_TYPE)info.inf[l].size,
1558 (OFF_T_FMT_TYPE)info.inf[l].csize,
1559 (TIME_T_FMT_TYPE)info.inf[l].secs,
1560 (TIME_T_FMT_TYPE)info.inf[l].date,
1561 (OFF_T_FMT_TYPE)info.inf[l].filenum,
1564 for(l=0;info.history[l].level > -1;l++) {
1565 printf("history: %d " OFF_T_FMT " " OFF_T_FMT " " TIME_T_FMT "\n",
1566 info.history[l].level,
1567 (OFF_T_FMT_TYPE)info.history[l].size,
1568 (OFF_T_FMT_TYPE)info.history[l].csize,
1569 (TIME_T_FMT_TYPE)info.history[l].date);
1574 /* ----------------------------------------------- */
1576 int import_one(void);
1577 char *impget_line(void);
1595 (void)argc; /* Quiet unused parameter warning */
1596 (void)argv; /* Quiet unused parameter warning */
1598 /* process header line */
1600 if((line = agets(stdin)) == NULL) {
1601 fprintf(stderr, "%s: empty input.\n", get_pname());
1609 if(strncmp_const_skip(s - 1, "CURINFO Version", s, ch) != 0) {
1613 skip_whitespace(s, ch);
1615 || sscanf(s - 1, "%d.%d.%d", &vers_maj, &vers_min, &vers_patch) != 3) {
1619 skip_integer(s, ch); /* skip over major */
1624 skip_integer(s, ch); /* skip over minor */
1629 skip_integer(s, ch); /* skip over patch */
1635 skip_non_whitespace(s, ch);
1639 skip_whitespace(s, ch); /* find the org keyword */
1640 if(ch == '\0' || strncmp_const_skip(s - 1, "CONF", s, ch) != 0) {
1646 skip_whitespace(s, ch); /* find the org string */
1653 newer = (vers_maj != VERSION_MAJOR)? vers_maj > VERSION_MAJOR :
1654 (vers_min != VERSION_MINOR)? vers_min > VERSION_MINOR :
1655 vers_patch > VERSION_PATCH;
1658 "%s: WARNING: input is from newer Amanda version: %d.%d.%d.\n",
1659 get_pname(), vers_maj, vers_min, vers_patch);
1662 if(strcmp(org, getconf_str(CNF_ORG)) != 0) {
1663 fprintf(stderr, "%s: WARNING: input is from different org: %s\n",
1676 /*@i@*/ amfree(line);
1677 fprintf(stderr, "%s: bad CURINFO header line in input: %s.\n",
1679 fprintf(stderr, " Was the input in \"amadmin export\" format?\n");
1691 time_t *onedate_p = &onedate;
1696 char *hostname = NULL;
1697 char *diskname = NULL;
1704 memset(&info, 0, SIZEOF(info_t));
1706 for(level = 0; level < DUMP_LEVELS; level++) {
1707 info.inf[level].date = (time_t)-1;
1710 /* get host: disk: command: lines */
1712 hostname = diskname = NULL;
1714 if((line = impget_line()) == NULL) return 0; /* nothing there */
1718 skip_whitespace(s, ch);
1719 if(ch == '\0' || strncmp_const_skip(s - 1, "host:", s, ch) != 0) goto parse_err;
1720 skip_whitespace(s, ch);
1721 if(ch == '\0') goto parse_err;
1723 skip_non_whitespace(s, ch);
1725 hostname = stralloc(fp);
1728 skip_whitespace(s, ch);
1731 if((line = impget_line()) == NULL) goto shortfile_err;
1734 skip_whitespace(s, ch);
1736 if(strncmp_const_skip(s - 1, "disk:", s, ch) != 0) goto parse_err;
1737 skip_whitespace(s, ch);
1738 if(ch == '\0') goto parse_err;
1740 skip_non_whitespace(s, ch);
1742 diskname = stralloc(fp);
1746 if((line = impget_line()) == NULL) goto shortfile_err;
1747 if(sscanf(line, "command: %u", &info.command) != 1) goto parse_err;
1749 /* get last_level and consecutive_runs */
1752 if((line = impget_line()) == NULL) goto shortfile_err;
1753 rc = sscanf(line, "last_level: %d", &info.last_level);
1756 if((line = impget_line()) == NULL) goto shortfile_err;
1757 if(sscanf(line, "consecutive_runs: %d", &info.consecutive_runs) != 1) goto parse_err;
1759 if((line = impget_line()) == NULL) goto shortfile_err;
1762 /* get rate: and comp: lines for full dumps */
1764 rc = sscanf(line, "full-rate: %lf %lf %lf",
1765 &info.full.rate[0], &info.full.rate[1], &info.full.rate[2]);
1766 if(rc != 3) goto parse_err;
1769 if((line = impget_line()) == NULL) goto shortfile_err;
1770 rc = sscanf(line, "full-comp: %lf %lf %lf",
1771 &info.full.comp[0], &info.full.comp[1], &info.full.comp[2]);
1772 if(rc != 3) goto parse_err;
1774 /* get rate: and comp: lines for incr dumps */
1777 if((line = impget_line()) == NULL) goto shortfile_err;
1778 rc = sscanf(line, "incr-rate: %lf %lf %lf",
1779 &info.incr.rate[0], &info.incr.rate[1], &info.incr.rate[2]);
1780 if(rc != 3) goto parse_err;
1783 if((line = impget_line()) == NULL) goto shortfile_err;
1784 rc = sscanf(line, "incr-comp: %lf %lf %lf",
1785 &info.incr.comp[0], &info.incr.comp[1], &info.incr.comp[2]);
1786 if(rc != 3) goto parse_err;
1788 /* get stats for dump levels */
1792 if((line = impget_line()) == NULL) goto shortfile_err;
1793 if(strncmp_const(line, "//") == 0) {
1797 if(strncmp_const(line, "history:") == 0) {
1801 memset(&onestat, 0, SIZEOF(onestat));
1806 skip_whitespace(s, ch);
1807 if(ch == '\0' || strncmp_const_skip(s - 1, "stats:", s, ch) != 0) {
1811 skip_whitespace(s, ch);
1812 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
1815 skip_integer(s, ch);
1817 skip_whitespace(s, ch);
1818 if(ch == '\0' || sscanf(s - 1, OFF_T_FMT,
1819 (OFF_T_FMT_TYPE *)&onestat.size) != 1) {
1822 skip_integer(s, ch);
1824 skip_whitespace(s, ch);
1825 if(ch == '\0' || sscanf(s - 1, OFF_T_FMT,
1826 (OFF_T_FMT_TYPE *)&onestat.csize) != 1) {
1829 skip_integer(s, ch);
1831 skip_whitespace(s, ch);
1832 secs_p = &onestat.secs;
1833 if(ch == '\0' || sscanf(s - 1, TIME_T_FMT,
1834 (TIME_T_FMT_TYPE *)secs_p) != 1) {
1837 skip_integer(s, ch);
1839 skip_whitespace(s, ch);
1840 if(ch == '\0' || sscanf(s - 1, TIME_T_FMT,
1841 (TIME_T_FMT_TYPE *)onedate_p) != 1) {
1844 skip_integer(s, ch);
1846 skip_whitespace(s, ch);
1848 if(sscanf(s - 1, OFF_T_FMT, (OFF_T_FMT_TYPE *)&onestat.filenum) != 1) {
1851 skip_integer(s, ch);
1853 skip_whitespace(s, ch);
1855 if (onestat.filenum != 0)
1857 onestat.label[0] = '\0';
1859 strncpy(onestat.label, s - 1, SIZEOF(onestat.label)-1);
1860 onestat.label[SIZEOF(onestat.label)-1] = '\0';
1864 /* time_t not guarranteed to be long */
1865 /*@i1@*/ onestat.date = onedate;
1866 if(level < 0 || level > 9) goto parse_err;
1868 info.inf[level] = onestat;
1871 for(i=0;i<=NB_HISTORY;i++) {
1872 info.history[i].level = -2;
1875 history_t onehistory;
1877 time_t *date_p = &date;
1879 if(line[0] == '/' && line[1] == '/') {
1880 info.history[nb_history].level = -2;
1884 memset(&onehistory, 0, SIZEOF(onehistory));
1887 if(strncmp_const_skip(line, "history:", s, ch) != 0) {
1891 skip_whitespace(s, ch);
1892 if(ch == '\0' || sscanf((s - 1), "%d", &onehistory.level) != 1) {
1895 skip_integer(s, ch);
1897 skip_whitespace(s, ch);
1898 if(ch == '\0' || sscanf((s - 1), OFF_T_FMT,
1899 (OFF_T_FMT_TYPE *)&onehistory.size) != 1) {
1902 skip_integer(s, ch);
1904 skip_whitespace(s, ch);
1905 if(ch == '\0' || sscanf((s - 1), OFF_T_FMT,
1906 (OFF_T_FMT_TYPE *)&onehistory.csize) != 1) {
1909 skip_integer(s, ch);
1911 skip_whitespace(s, ch);
1912 if((ch == '\0') || (sscanf((s - 1), TIME_T_FMT,
1913 (TIME_T_FMT_TYPE *)date_p) != 1)) {
1916 skip_integer(s, ch);
1917 /*@i1@*/onehistory.date = date; /* time_t not guarranteed to be long */
1919 info.history[nb_history++] = onehistory;
1921 if((line = impget_line()) == NULL) goto shortfile_err;
1923 /*@i@*/ amfree(line);
1925 /* got a full record, now write it out to the database */
1927 if(put_info(hostname, diskname, &info)) {
1928 fprintf(stderr, "%s: error writing record for %s:%s\n",
1929 get_pname(), hostname, diskname);
1936 /*@i@*/ amfree(line);
1939 fprintf(stderr, "%s: parse error reading import record.\n", get_pname());
1943 /*@i@*/ amfree(line);
1946 fprintf(stderr, "%s: short file reading import record.\n", get_pname());
1957 for(; (line = agets(stdin)) != NULL; free(line)) {
1961 skip_whitespace(s, ch);
1963 /* ignore comment lines */
1966 /* found non-blank, return line */
1969 /* otherwise, a blank line, so keep going */
1972 fprintf(stderr, "%s: reading stdin: %s\n",
1973 get_pname(), strerror(errno));
1978 /* ----------------------------------------------- */
1991 printf("line %d:\n", dp->line);
1993 printf(" host %s:\n", hp->hostname);
1994 printf(" interface %s\n",
1995 ip->name[0] ? ip->name : "default");
1996 printf(" disk %s:\n", dp->name);
1997 if(dp->device) printf(" device %s\n", dp->device);
1999 printf(" program \"%s\"\n", dp->program);
2000 if(dp->exclude_file != NULL && dp->exclude_file->nb_element > 0) {
2001 printf(" exclude file");
2002 for(excl = dp->exclude_file->first; excl != NULL; excl = excl->next) {
2003 printf(" \"%s\"", excl->name);
2007 if(dp->exclude_list != NULL && dp->exclude_list->nb_element > 0) {
2008 printf(" exclude list");
2009 if(dp->exclude_optional) printf(" optional");
2010 for(excl = dp->exclude_list->first; excl != NULL; excl = excl->next) {
2011 printf(" \"%s\"", excl->name);
2015 if(dp->include_file != NULL && dp->include_file->nb_element > 0) {
2016 printf(" include file");
2017 for(excl = dp->include_file->first; excl != NULL; excl = excl->next) {
2018 printf(" \"%s\"", excl->name);
2022 if(dp->include_list != NULL && dp->include_list->nb_element > 0) {
2023 printf(" include list");
2024 if(dp->include_optional) printf(" optional");
2025 for(excl = dp->include_list->first; excl != NULL; excl = excl->next) {
2026 printf(" \"%s\"", excl->name);
2030 printf(" priority %d\n", dp->priority);
2031 printf(" dumpcycle %d\n", dp->dumpcycle);
2032 printf(" maxdumps %d\n", dp->maxdumps);
2033 printf(" maxpromoteday %d\n", dp->maxpromoteday);
2034 if(dp->bumppercent > 0) {
2035 printf(" bumppercent %d\n", dp->bumppercent);
2038 printf(" bumpsize " OFF_T_FMT "\n",
2039 (OFF_T_FMT_TYPE)dp->bumpsize);
2041 printf(" bumpdays %d\n", dp->bumpdays);
2042 printf(" bumpmult %lf\n", dp->bumpmult);
2044 printf(" strategy ");
2045 switch(dp->strategy) {
2050 printf("STANDARD\n");
2062 printf("INCRONLY\n");
2065 printf(" ignore %s\n", (dp->ignore? "YES" : "NO"));
2066 printf(" estimate ");
2067 switch(dp->estimate) {
2075 printf("CALCSIZE\n");
2079 printf(" compress ");
2080 switch(dp->compress) {
2085 printf("CLIENT FAST\n");
2088 printf("CLIENT BEST\n");
2090 case COMP_SERVER_FAST:
2091 printf("SERVER FAST\n");
2093 case COMP_SERVER_BEST:
2094 printf("SERVER BEST\n");
2097 if(dp->compress != COMP_NONE) {
2098 printf(" comprate %.2lf %.2lf\n",
2099 dp->comprate[0], dp->comprate[1]);
2102 printf(" encrypt ");
2103 switch(dp->encrypt) {
2110 case ENCRYPT_SERV_CUST:
2115 printf(" auth %s\n", dp->security_driver);
2116 printf(" kencrypt %s\n", (dp->kencrypt? "YES" : "NO"));
2117 printf(" amandad_path %s\n", dp->amandad_path);
2118 printf(" client_username %s\n", dp->client_username);
2119 printf(" ssh_keys %s\n", dp->ssh_keys);
2121 printf(" holdingdisk ");
2122 switch(dp->to_holdingdisk) {
2130 printf("REQUIRED\n");
2134 printf(" record %s\n", (dp->record? "YES" : "NO"));
2135 printf(" index %s\n", (dp->index? "YES" : "NO"));
2136 printf(" starttime %04d\n", (int)dp->starttime);
2137 if(dp->tape_splitsize > (off_t)0) {
2138 printf(" tape_splitsize " OFF_T_FMT "\n",
2139 (OFF_T_FMT_TYPE)dp->tape_splitsize);
2141 if(dp->split_diskbuffer) {
2142 printf(" split_diskbuffer %s\n", dp->split_diskbuffer);
2144 if(dp->fallback_splitsize > (off_t)0) {
2145 printf(" fallback_splitsize " OFF_T_FMT "Mb\n",
2146 (OFF_T_FMT_TYPE)(dp->fallback_splitsize / (off_t)1024));
2148 printf(" skip-incr %s\n", (dp->skip_incr? "YES" : "NO"));
2149 printf(" skip-full %s\n", (dp->skip_full? "YES" : "NO"));
2150 printf(" spindle %d\n", dp->spindle);
2163 diskloop(argc, argv, "disklist", disklist_one);
2165 for(dp = diskq.head; dp != NULL; dp = dp->next)
2176 (void)argc; /* Quiet unused parameter warning */
2177 (void)argv; /* Quiet unused parameter warning */
2179 for(i = 0; version_info[i] != NULL; i++)
2180 printf("%s", version_info[i]);
2190 dump_configuration(conffile);