Imported Upstream version 2.6.1
[debian/amanda] / server-src / driver.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * All Rights Reserved.
5  *
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.
15  *
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.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /*
27  * $Id: driver.c 6512 2007-05-24 17:00:24Z ian $
28  *
29  * controlling process for the Amanda backup system
30  */
31
32 /*
33  * XXX possibly modify tape queue to be cognizant of how much room is left on
34  *     tape.  Probably not effective though, should do this in planner.
35  */
36
37 #include "amanda.h"
38 #include "clock.h"
39 #include "conffile.h"
40 #include "diskfile.h"
41 #include "event.h"
42 #include "holding.h"
43 #include "infofile.h"
44 #include "logfile.h"
45 #include "fsusage.h"
46 #include "version.h"
47 #include "driverio.h"
48 #include "server_util.h"
49 #include "timestamp.h"
50
51 #define driver_debug(i, ...) do {       \
52         if ((i) <= debug_driver) {      \
53             dbprintf(__VA_ARGS__);      \
54         }                               \
55 } while (0)
56
57 #define hold_debug(i, ...) do {         \
58         if ((i) <= debug_holding) {     \
59             dbprintf(__VA_ARGS__);      \
60         }                               \
61 } while (0)
62
63 static disklist_t waitq;        // dle waiting estimate result
64 static disklist_t runq;         // dle waiting to be dumped to holding disk
65 static disklist_t directq;      // dle waiting to be dumped directly to tape
66 static disklist_t tapeq;        // dle on holding disk waiting to be written
67                                 //   to tape
68 static disklist_t roomq;        // dle waiting for more space on holding disk
69 static int pending_aborts;
70 static disk_t *taper_disk;
71 static int degraded_mode;
72 static off_t reserved_space;
73 static off_t total_disksize;
74 static char *dumper_program;
75 static char *chunker_program;
76 static int  inparallel;
77 static int nodump = 0;
78 static off_t tape_length = (off_t)0;
79 static off_t tape_left = (off_t)0;
80 static int current_tape = 0;
81 static int conf_taperalgo;
82 static int conf_runtapes;
83 static time_t sleep_time;
84 static int idle_reason;
85 static char *driver_timestamp;
86 static char *hd_driver_timestamp;
87 static am_host_t *flushhost = NULL;
88 static int need_degraded=0;
89 static holdalloc_t *holdalloc;
90 static int num_holdalloc;
91 static event_handle_t *dumpers_ev_time = NULL;
92 static event_handle_t *schedule_ev_read = NULL;
93 static int   conf_flush_threshold_dumped;
94 static int   conf_flush_threshold_scheduled;
95 static int   conf_taperflush;
96 static off_t flush_threshold_dumped;
97 static off_t flush_threshold_scheduled;
98 static off_t taperflush;
99 static int   schedule_done;                     // 1 if we don't wait for a
100                                                 //   schedule from the planner
101 static int   force_flush;                       // All dump are terminated, we
102                                                 // must now respect taper_flush
103
104 static int wait_children(int count);
105 static void wait_for_children(void);
106 static void allocate_bandwidth(netif_t *ip, unsigned long kps);
107 static int assign_holdingdisk(assignedhd_t **holdp, disk_t *diskp);
108 static void adjust_diskspace(disk_t *diskp, cmd_t cmd);
109 static void delete_diskspace(disk_t *diskp);
110 static assignedhd_t **build_diskspace(char *destname);
111 static int client_constrained(disk_t *dp);
112 static void deallocate_bandwidth(netif_t *ip, unsigned long kps);
113 static void dump_schedule(disklist_t *qp, char *str);
114 static void dump_to_tape(disk_t *dp);
115 static assignedhd_t **find_diskspace(off_t size, int *cur_idle,
116                                         assignedhd_t *preferred);
117 static unsigned long free_kps(netif_t *ip);
118 static off_t free_space(void);
119 static void dumper_chunker_result(disk_t *dp);
120 static void dumper_taper_result(disk_t *dp);
121 static void file_taper_result(disk_t *dp);
122 static void handle_dumper_result(void *);
123 static void handle_chunker_result(void *);
124 static void handle_dumpers_time(void *);
125 static void handle_taper_result(void *);
126
127 static void holdingdisk_state(char *time_str);
128 static dumper_t *idle_dumper(void);
129 static void interface_state(char *time_str);
130 static int queue_length(disklist_t q);
131 static disklist_t read_flush(void);
132 static void read_schedule(void *cookie);
133 static void short_dump_state(void);
134 static void startaflush(void);
135 static void start_degraded_mode(disklist_t *queuep);
136 static void start_some_dumps(disklist_t *rq);
137 static void continue_port_dumps(void);
138 static void update_failed_dump_to_tape(disk_t *);
139
140 typedef enum {
141     TAPE_ACTION_NO_ACTION     = 0,
142     TAPE_ACTION_NEW_TAPE      = (1 << 0),
143     TAPE_ACTION_NO_NEW_TAPE   = (1 << 1),
144     TAPE_ACTION_START_A_FLUSH = (1 << 2)
145 } TapeAction;
146
147 static TapeAction tape_action(char **why_no_new_tape);
148
149 static const char *idle_strings[] = {
150 #define NOT_IDLE                0
151     T_("not-idle"),
152 #define IDLE_NO_DUMPERS         1
153     T_("no-dumpers"),
154 #define IDLE_START_WAIT         2
155     T_("start-wait"),
156 #define IDLE_NO_HOLD            3
157     T_("no-hold"),
158 #define IDLE_CLIENT_CONSTRAINED 4
159     T_("client-constrained"),
160 #define IDLE_NO_BANDWIDTH       5
161     T_("no-bandwidth"),
162 #define IDLE_NO_DISKSPACE       6
163     T_("no-diskspace")
164 };
165
166 int
167 main(
168     int         argc,
169     char **     argv)
170 {
171     disklist_t origq;
172     disk_t *diskp;
173     int dsk;
174     dumper_t *dumper;
175     char *newdir = NULL;
176     struct fs_usage fsusage;
177     holdingdisk_t *hdp;
178     unsigned long reserve = 100;
179     char *conf_diskfile;
180     cmd_t cmd;
181     int result_argc;
182     char **result_argv = NULL;
183     char *taper_program;
184     char *conf_tapetype;
185     tapetype_t *tape;
186     char *line;
187     char hostname[1025];
188     intmax_t kb_avail;
189     config_overwrites_t *cfg_ovr = NULL;
190     char *cfg_opt = NULL;
191     holdalloc_t *ha, *ha_last;
192
193     /*
194      * Configure program for internationalization:
195      *   1) Only set the message locale for now.
196      *   2) Set textdomain for all amanda related programs to "amanda"
197      *      We don't want to be forced to support dozens of message catalogs.
198      */  
199     setlocale(LC_MESSAGES, "C");
200     textdomain("amanda");
201
202     safe_fd(-1, 0);
203
204     setvbuf(stdout, (char *)NULL, (int)_IOLBF, 0);
205     setvbuf(stderr, (char *)NULL, (int)_IOLBF, 0);
206
207     set_pname("driver");
208
209     dbopen(DBG_SUBDIR_SERVER);
210
211     atexit(wait_for_children);
212
213     /* Don't die when child closes pipe */
214     signal(SIGPIPE, SIG_IGN);
215
216     erroutput_type = (ERR_AMANDALOG|ERR_INTERACTIVE);
217     set_logerror(logerror);
218
219     startclock();
220
221     cfg_ovr = extract_commandline_config_overwrites(&argc, &argv);
222
223     if (argc > 1)
224         cfg_opt = argv[1];
225     config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt);
226     apply_config_overwrites(cfg_ovr);
227
228     conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE));
229     read_diskfile(conf_diskfile, &origq);
230     amfree(conf_diskfile);
231
232     if (config_errors(NULL) >= CFGERR_WARNINGS) {
233         config_print_errors();
234         if (config_errors(NULL) >= CFGERR_ERRORS) {
235             g_critical(_("errors processing config file"));
236         }
237     }
238
239     log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
240     g_printf(_("%s: pid %ld executable %s version %s\n"),
241            get_pname(), (long) getpid(), argv[0], version());
242
243     if(argc > 2) {
244         if(strncmp(argv[2], "nodump", 6) == 0) {
245             nodump = 1;
246         }
247     }
248
249     safe_cd(); /* do this *after* config_init */
250
251     check_running_as(RUNNING_AS_DUMPUSER);
252
253     dbrename(get_config_name(), DBG_SUBDIR_SERVER);
254
255     amfree(driver_timestamp);
256     /* read timestamp from stdin */
257     while ((line = agets(stdin)) != NULL) {
258         if (line[0] != '\0')
259             break;
260         amfree(line);
261     }
262     if ( line == NULL ) {
263       error(_("Did not get DATE line from planner"));
264       /*NOTREACHED*/
265     }
266     driver_timestamp = alloc(15);
267     strncpy(driver_timestamp, &line[5], 14);
268     driver_timestamp[14] = '\0';
269     amfree(line);
270     log_add(L_START,_("date %s"), driver_timestamp);
271
272     gethostname(hostname, SIZEOF(hostname));
273     log_add(L_STATS,_("hostname %s"), hostname);
274
275     /* check that we don't do many dump in a day and usetimestamps is off */
276     if(strlen(driver_timestamp) == 8) {
277         if (!nodump) {
278             char *conf_logdir = getconf_str(CNF_LOGDIR);
279             char *logfile    = vstralloc(conf_logdir, "/log.",
280                                          driver_timestamp, ".0", NULL);
281             char *oldlogfile = vstralloc(conf_logdir, "/oldlog/log.",
282                                          driver_timestamp, ".0", NULL);
283             if(access(logfile, F_OK) == 0 || access(oldlogfile, F_OK) == 0) {
284                 log_add(L_WARNING, _("WARNING: This is not the first amdump run today. Enable the usetimestamps option in the configuration file if you want to run amdump more than once per calendar day."));
285             }
286             amfree(oldlogfile);
287             amfree(logfile);
288         }
289         hd_driver_timestamp = get_timestamp_from_time(0);
290     }
291     else {
292         hd_driver_timestamp = stralloc(driver_timestamp);
293     }
294
295     taper_program = vstralloc(amlibexecdir, "/", "taper", versionsuffix(), NULL);
296     dumper_program = vstralloc(amlibexecdir, "/", "dumper", versionsuffix(),
297                                NULL);
298     chunker_program = vstralloc(amlibexecdir, "/", "chunker", versionsuffix(),
299                                NULL);
300
301     conf_taperalgo = getconf_taperalgo(CNF_TAPERALGO);
302     conf_tapetype = getconf_str(CNF_TAPETYPE);
303     conf_runtapes = getconf_int(CNF_RUNTAPES);
304     tape = lookup_tapetype(conf_tapetype);
305     tape_length = tapetype_get_length(tape);
306     g_printf("driver: tape size %lld\n", (long long)tape_length);
307     conf_flush_threshold_dumped = getconf_int(CNF_FLUSH_THRESHOLD_DUMPED);
308     conf_flush_threshold_scheduled = getconf_int(CNF_FLUSH_THRESHOLD_SCHEDULED);
309     conf_taperflush = getconf_int(CNF_TAPERFLUSH);
310
311     flush_threshold_dumped = (conf_flush_threshold_dumped * tape_length) / 100;
312     flush_threshold_scheduled = (conf_flush_threshold_scheduled * tape_length) / 100;
313     taperflush = (conf_taperflush *tape_length) / 100;
314
315     driver_debug(1, _("flush_threshold_dumped: %lld\n"), (long long)flush_threshold_dumped);
316     driver_debug(1, _("flush_threshold_scheduled: %lld\n"), (long long)flush_threshold_scheduled);
317     driver_debug(1, _("taperflush: %lld\n"), (long long)taperflush);
318
319     /* set up any configuration-dependent variables */
320
321     inparallel  = getconf_int(CNF_INPARALLEL);
322
323     reserve = (unsigned long)getconf_int(CNF_RESERVE);
324
325     total_disksize = (off_t)0;
326     ha_last = NULL;
327     num_holdalloc = 0;
328     for(hdp = getconf_holdingdisks(), dsk = 0; hdp != NULL; hdp = holdingdisk_next(hdp), dsk++) {
329         ha = alloc(SIZEOF(holdalloc_t));
330         num_holdalloc++;
331
332         /* link the list in the same order as getconf_holdingdisks's results */
333         ha->next = NULL;
334         if (ha_last == NULL)
335             holdalloc = ha;
336         else
337             ha_last->next = ha;
338         ha_last = ha;
339
340         ha->hdisk = hdp;
341         ha->allocated_dumpers = 0;
342         ha->allocated_space = (off_t)0;
343         ha->disksize = holdingdisk_get_disksize(hdp);
344
345         /* get disk size */
346         if(get_fs_usage(holdingdisk_get_diskdir(hdp), NULL, &fsusage) == -1
347            || access(holdingdisk_get_diskdir(hdp), W_OK) == -1) {
348             log_add(L_WARNING, _("WARNING: ignoring holding disk %s: %s\n"),
349                     holdingdisk_get_diskdir(hdp), strerror(errno));
350             ha->disksize = 0L;
351             continue;
352         }
353
354         /* do the division first to avoid potential integer overflow */
355         if (fsusage.fsu_bavail_top_bit_set)
356             kb_avail = 0;
357         else
358             kb_avail = fsusage.fsu_bavail / 1024 * fsusage.fsu_blocksize;
359
360         if(ha->disksize > (off_t)0) {
361             if(ha->disksize > kb_avail) {
362                 log_add(L_WARNING,
363                         _("WARNING: %s: %lld KB requested, "
364                         "but only %lld KB available."),
365                         holdingdisk_get_diskdir(hdp),
366                         (long long)ha->disksize,
367                         (long long)kb_avail);
368                         ha->disksize = kb_avail;
369             }
370         }
371         /* ha->disksize is negative; use all but that amount */
372         else if(kb_avail < -ha->disksize) {
373             log_add(L_WARNING,
374                     _("WARNING: %s: not %lld KB free."),
375                     holdingdisk_get_diskdir(hdp),
376                     (long long)-ha->disksize);
377             ha->disksize = (off_t)0;
378             continue;
379         }
380         else
381             ha->disksize += kb_avail;
382
383         g_printf(_("driver: adding holding disk %d dir %s size %lld chunksize %lld\n"),
384                dsk, holdingdisk_get_diskdir(hdp),
385                (long long)ha->disksize,
386                (long long)(holdingdisk_get_chunksize(hdp)));
387
388         newdir = newvstralloc(newdir,
389                               holdingdisk_get_diskdir(hdp), "/", hd_driver_timestamp,
390                               NULL);
391         if(!mkholdingdir(newdir)) {
392             ha->disksize = (off_t)0;
393         }
394         total_disksize += ha->disksize;
395     }
396
397     reserved_space = total_disksize * (off_t)(reserve / 100);
398
399     g_printf(_("reserving %lld out of %lld for degraded-mode dumps\n"),
400            (long long)reserved_space, (long long)free_space());
401
402     amfree(newdir);
403
404     if(inparallel > MAX_DUMPERS) inparallel = MAX_DUMPERS;
405
406     /* taper takes a while to get going, so start it up right away */
407
408     init_driverio();
409     if(conf_runtapes > 0) {
410         startup_tape_process(taper_program);
411         taper_cmd(START_TAPER, driver_timestamp, NULL, 0, NULL);
412     }
413
414     /* fire up the dumpers now while we are waiting */
415     if(!nodump) startup_dump_processes(dumper_program, inparallel, driver_timestamp);
416
417     /*
418      * Read schedule from stdin.  Usually, this is a pipe from planner,
419      * so the effect is that we wait here for the planner to
420      * finish, but meanwhile the taper is rewinding the tape, reading
421      * the label, checking it, writing a new label and all that jazz
422      * in parallel with the planner.
423      */
424
425     runq.head = NULL;
426     runq.tail = NULL;
427     directq.head = NULL;
428     directq.tail = NULL;
429     waitq = origq;
430     taper_state = TAPER_STATE_DEFAULT;
431     tapeq = read_flush();
432
433     roomq.head = roomq.tail = NULL;
434
435     log_add(L_STATS, _("startup time %s"), walltime_str(curclock()));
436
437     g_printf(_("driver: start time %s inparallel %d bandwidth %lu diskspace %lld "), walltime_str(curclock()), inparallel,
438            free_kps(NULL), (long long)free_space());
439     g_printf(_(" dir %s datestamp %s driver: drain-ends tapeq %s big-dumpers %s\n"),
440            "OBSOLETE", driver_timestamp, taperalgo2str(conf_taperalgo),
441            getconf_str(CNF_DUMPORDER));
442     fflush(stdout);
443
444     /* ok, planner is done, now lets see if the tape is ready */
445
446     if (conf_runtapes > 0) {
447         cmd = getresult(taper, 1, &result_argc, &result_argv);
448         if (cmd != TAPER_OK) {
449             /* no tape, go into degraded mode: dump to holding disk */
450             need_degraded = 1;
451         }
452     } else {
453         need_degraded = 1;
454     }
455
456     tape_left = tape_length;
457     taper_busy = 0;
458     amfree(taper_input_error);
459     amfree(taper_tape_error);
460     taper_disk = NULL;
461     taper_ev_read = NULL;
462
463     schedule_done = nodump;
464     force_flush = 0;
465
466     if(!need_degraded) startaflush();
467
468     if(!nodump)
469         schedule_ev_read = event_register((event_id_t)0, EV_READFD, read_schedule, NULL);
470
471     short_dump_state();
472     event_loop(0);
473
474     force_flush = 1;
475
476     /* mv runq to directq */
477     while (!empty(runq)) {
478         diskp = dequeue_disk(&runq);
479         headqueue_disk(&directq, diskp);
480     }
481
482     /* handle any remaining dumps by dumping directly to tape, if possible */
483     while(!empty(directq) && taper > 0) {
484         time_t  sleep_time  = 100000000;
485         disk_t *sleep_diskp = NULL;
486         time_t  now         = time(0);
487
488         /* Find one we can do immediately or the sonner */
489         for (diskp = directq.head; diskp != NULL; diskp = diskp->next) {
490             if (diskp->to_holdingdisk == HOLD_REQUIRED ||
491                 degraded_mode) {
492                 sleep_time = 0;
493                 sleep_diskp = diskp;
494             } else if (diskp->host->start_t - now < sleep_time &&
495                        diskp->start_t -now < sleep_time) {
496                 if (diskp->host->start_t > diskp->start_t)
497                     sleep_time = diskp->host->start_t - now;
498                 else
499                     sleep_time = diskp->start_t - now;
500                 sleep_diskp = diskp;
501             }
502         }
503         diskp = sleep_diskp;
504         if (sleep_time > 0)
505             sleep(sleep_time);
506         remove_disk(&directq, diskp);
507
508         if (diskp->to_holdingdisk == HOLD_REQUIRED) {
509             char *qname = quote_string(diskp->name);
510             log_add(L_FAIL, "%s %s %s %d [%s]",
511                 diskp->host->hostname, qname, sched(diskp)->datestamp,
512                 sched(diskp)->level,
513                 _("can't dump required holdingdisk"));
514             amfree(qname);
515         }
516         else if (!degraded_mode) {
517             taper_state |= TAPER_STATE_DUMP_TO_TAPE;
518             dump_to_tape(diskp);
519             event_loop(0);
520             taper_state &= ~TAPER_STATE_DUMP_TO_TAPE;
521         }
522         else {
523             char *qname = quote_string(diskp->name);
524             log_add(L_FAIL, "%s %s %s %d [%s]",
525                 diskp->host->hostname, qname, sched(diskp)->datestamp,
526                 sched(diskp)->level,
527                 num_holdalloc == 0 ?
528                     _("can't do degraded dump without holding disk") :
529                 diskp->to_holdingdisk != HOLD_NEVER ?
530                     _("out of holding space in degraded mode") :
531                     _("can't dump 'holdingdisk never' dle in degraded mode"));
532             amfree(qname);
533         }
534     }
535
536     /* fill up the tape or start new one for taperflush */
537     startaflush();
538     event_loop(0);
539
540     short_dump_state();                         /* for amstatus */
541
542     g_printf(_("driver: QUITTING time %s telling children to quit\n"),
543            walltime_str(curclock()));
544     fflush(stdout);
545
546     if(!nodump) {
547         for(dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
548             if(dumper->fd >= 0)
549                 dumper_cmd(dumper, QUIT, NULL, NULL);
550         }
551     }
552
553     if(taper >= 0) {
554         taper_cmd(QUIT, NULL, NULL, 0, NULL);
555     }
556
557     /* wait for all to die */
558     wait_children(600);
559
560     /* cleanup */
561     holding_cleanup(NULL, NULL);
562
563     amfree(newdir);
564
565     check_unfree_serial();
566     g_printf(_("driver: FINISHED time %s\n"), walltime_str(curclock()));
567     fflush(stdout);
568     log_add(L_FINISH,_("date %s time %s"), driver_timestamp, walltime_str(curclock()));
569     log_add(L_INFO, "pid-done %ld", (long)getpid());
570     amfree(driver_timestamp);
571
572     amfree(dumper_program);
573     amfree(taper_program);
574     if (result_argv)
575         g_strfreev(result_argv);
576
577     dbclose();
578
579     return 0;
580 }
581
582 /* sleep up to count seconds, and wait for terminating child process */
583 /* if sleep is negative, this function will not timeout              */
584 /* exit once all child process are finished or the timout expired    */
585 /* return 0 if no more children to wait                              */
586 /* return 1 if some children are still alive                         */
587 static int
588 wait_children(int count)
589 {
590     pid_t     pid;
591     amwait_t  retstat;
592     char     *who;
593     char     *what;
594     int       code=0;
595     dumper_t *dumper;
596     int       wait_errno;
597
598     do {
599         do {
600             pid = waitpid((pid_t)-1, &retstat, WNOHANG);
601             wait_errno = errno;
602             if (pid > 0) {
603                 what = NULL;
604                 if (! WIFEXITED(retstat)) {
605                     what = _("signal");
606                     code = WTERMSIG(retstat);
607                 } else if (WEXITSTATUS(retstat) != 0) {
608                     what = _("code");
609                     code = WEXITSTATUS(retstat);
610                 }
611                 who = NULL;
612                 for (dumper = dmptable; dumper < dmptable + inparallel;
613                      dumper++) {
614                     if (pid == dumper->pid) {
615                         who = stralloc(dumper->name);
616                         dumper->pid = -1;
617                         break;
618                     }
619                     if (dumper->chunker && pid == dumper->chunker->pid) {
620                         who = stralloc(dumper->chunker->name);
621                         dumper->chunker->pid = -1;
622                         break;
623                     }
624                 }
625                 if (who == NULL && pid == taper_pid) {
626                     who = stralloc("taper");
627                     taper_pid = -1;
628                 }
629                 if(what != NULL && who == NULL) {
630                     who = stralloc("unknown");
631                 }
632                 if(who && what) {
633                     log_add(L_WARNING, _("%s pid %u exited with %s %d\n"), who, 
634                             (unsigned)pid, what, code);
635                     g_printf(_("driver: %s pid %u exited with %s %d\n"), who,
636                            (unsigned)pid, what, code);
637                 }
638                 amfree(who);
639             }
640         } while (pid > 0 || wait_errno == EINTR);
641         if (errno != ECHILD)
642             sleep(1);
643         if (count > 0)
644             count--;
645     } while ((errno != ECHILD) && (count != 0));
646     return (errno != ECHILD);
647 }
648
649 static void
650 kill_children(int signal)
651 {
652     dumper_t *dumper;
653
654     if(!nodump) {
655         for(dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
656             if (!dumper->down && dumper->pid > 1) {
657                 g_printf(_("driver: sending signal %d to %s pid %u\n"), signal,
658                        dumper->name, (unsigned)dumper->pid);
659                 if (kill(dumper->pid, signal) == -1 && errno == ESRCH) {
660                     if (dumper->chunker)
661                         dumper->chunker->pid = 0;
662                 }
663                 if (dumper->chunker && dumper->chunker->pid > 1) {
664                     g_printf(_("driver: sending signal %d to %s pid %u\n"), signal,
665                            dumper->chunker->name,
666                            (unsigned)dumper->chunker->pid);
667                     if (kill(dumper->chunker->pid, signal) == -1 &&
668                         errno == ESRCH)
669                         dumper->chunker->pid = 0;
670                 }
671             }
672         }
673     }
674
675     if(taper_pid > 1) {
676         g_printf(_("driver: sending signal %d to %s pid %u\n"), signal,
677                "taper", (unsigned)taper_pid);
678         if (kill(taper_pid, signal) == -1 && errno == ESRCH)
679             taper_pid = 0;
680     }
681 }
682
683 static void
684 wait_for_children(void)
685 {
686     dumper_t *dumper;
687
688     if(!nodump) {
689         for(dumper = dmptable; dumper < dmptable + inparallel; dumper++) {
690             if (dumper->pid > 1 && dumper->fd >= 0) {
691                 dumper_cmd(dumper, QUIT, NULL, NULL);
692                 if (dumper->chunker && dumper->chunker->pid > 1 &&
693                     dumper->chunker->fd >= 0)
694                     chunker_cmd(dumper->chunker, QUIT, NULL, NULL);
695             }
696         }
697     }
698
699     if(taper_pid > 1 && taper > 0) {
700         taper_cmd(QUIT, NULL, NULL, 0, NULL);
701     }
702
703     if(wait_children(60) == 0)
704         return;
705
706     kill_children(SIGHUP);
707     if(wait_children(60) == 0)
708         return;
709
710     kill_children(SIGKILL);
711     if(wait_children(-1) == 0)
712         return;
713
714 }
715
716 static void
717 startaflush(void)
718 {
719     disk_t *dp = NULL;
720     disk_t *fit = NULL;
721     char *datestamp;
722     int extra_tapes = 0;
723     char *qname;
724     TapeAction result_tape_action;
725     char *why_no_new_tape;
726
727     result_tape_action = tape_action(&why_no_new_tape);
728
729     if (result_tape_action & TAPE_ACTION_NEW_TAPE) {
730         taper_state &= ~TAPER_STATE_WAIT_FOR_TAPE;
731         taper_cmd(NEW_TAPE, NULL, NULL, 0, NULL);
732     } else if (result_tape_action & TAPE_ACTION_NO_NEW_TAPE) {
733         taper_state &= ~TAPER_STATE_WAIT_FOR_TAPE;
734         taper_cmd(NO_NEW_TAPE, why_no_new_tape, NULL, 0, NULL);
735         start_degraded_mode(&runq);
736     }
737
738     if (!degraded_mode && !taper_busy && !empty(tapeq) &&
739         (result_tape_action & TAPE_ACTION_START_A_FLUSH)) {
740         
741         datestamp = sched(tapeq.head)->datestamp;
742         switch(conf_taperalgo) {
743         case ALGO_FIRST:
744                 dp = dequeue_disk(&tapeq);
745                 break;
746         case ALGO_FIRSTFIT:
747                 fit = tapeq.head;
748                 while (fit != NULL) {
749                     extra_tapes = (fit->tape_splitsize > (off_t)0) ? 
750                                         conf_runtapes - current_tape : 0;
751                     if(sched(fit)->act_size <= (tape_left +
752                              tape_length * (off_t)extra_tapes) &&
753                              strcmp(sched(fit)->datestamp, datestamp) <= 0) {
754                         dp = fit;
755                         fit = NULL;
756                     }
757                     else {
758                         fit = fit->next;
759                     }
760                 }
761                 if(dp) remove_disk(&tapeq, dp);
762                 break;
763         case ALGO_LARGEST:
764                 fit = dp = tapeq.head;
765                 while (fit != NULL) {
766                     if(sched(fit)->act_size > sched(dp)->act_size &&
767                        strcmp(sched(fit)->datestamp, datestamp) <= 0) {
768                         dp = fit;
769                     }
770                     fit = fit->next;
771                 }
772                 if(dp) remove_disk(&tapeq, dp);
773                 break;
774         case ALGO_LARGESTFIT:
775                 fit = tapeq.head;
776                 while (fit != NULL) {
777                     extra_tapes = (fit->tape_splitsize > (off_t)0) ? 
778                                         conf_runtapes - current_tape : 0;
779                     if(sched(fit)->act_size <=
780                        (tape_left + tape_length * (off_t)extra_tapes) &&
781                        (!dp || sched(fit)->act_size > sched(dp)->act_size) &&
782                        strcmp(sched(fit)->datestamp, datestamp) <= 0) {
783                         dp = fit;
784                     }
785                     fit = fit->next;
786                 }
787                 if(dp) remove_disk(&tapeq, dp);
788                 break;
789         case ALGO_SMALLEST:
790                 break;
791         case ALGO_LAST:
792                 dp = tapeq.tail;
793                 remove_disk(&tapeq, dp);
794                 break;
795         }
796         if(!dp) { /* ALGO_SMALLEST, or default if nothing fit. */
797             if(conf_taperalgo != ALGO_SMALLEST)  {
798                 g_fprintf(stderr,
799                    _("driver: startaflush: Using SMALLEST because nothing fit\n"));
800             }
801             fit = dp = tapeq.head;
802             while (fit != NULL) {
803                 if(sched(fit)->act_size < sched(dp)->act_size &&
804                    strcmp(sched(fit)->datestamp, datestamp) <= 0) {
805                     dp = fit;
806                 }
807                 fit = fit->next;
808             }
809             if(dp) remove_disk(&tapeq, dp);
810         }
811         if(taper_ev_read == NULL) {
812             taper_ev_read = event_register((event_id_t)taper, EV_READFD,
813                                            handle_taper_result, NULL);
814         }
815         if (dp) {
816             taper_disk = dp;
817             taper_busy = 1;
818             amfree(taper_input_error);
819             amfree(taper_tape_error);
820             taper_result = LAST_TOK;
821             taper_sendresult = 0;
822             taper_first_label = NULL;
823             taper_written = 0;
824             taper_state &= ~TAPER_STATE_DUMP_TO_TAPE;
825             taper_dumper = NULL;
826             qname = quote_string(dp->name);
827             taper_cmd(FILE_WRITE, dp, sched(dp)->destname, sched(dp)->level,
828                       sched(dp)->datestamp);
829             g_fprintf(stderr,_("driver: startaflush: %s %s %s %lld %lld\n"),
830                     taperalgo2str(conf_taperalgo), dp->host->hostname, qname,
831                     (long long)sched(taper_disk)->act_size,
832                     (long long)tape_left);
833             if(sched(dp)->act_size <= tape_left)
834                 tape_left -= sched(dp)->act_size;
835             else
836                 tape_left = (off_t)0;
837             amfree(qname);
838         } else {
839             error(_("FATAL: Taper marked busy and no work found."));
840             /*NOTREACHED*/
841         }
842         short_dump_state();
843     } else if(!taper_busy && taper_ev_read != NULL) {
844         event_release(taper_ev_read);
845         taper_ev_read = NULL;
846     }
847 }
848
849 static int
850 client_constrained(
851     disk_t *    dp)
852 {
853     disk_t *dp2;
854
855     /* first, check if host is too busy */
856
857     if(dp->host->inprogress >= dp->host->maxdumps) {
858         return 1;
859     }
860
861     /* next, check conflict with other dumps on same spindle */
862
863     if(dp->spindle == -1) {     /* but spindle -1 never conflicts by def. */
864         return 0;
865     }
866
867     for(dp2 = dp->host->disks; dp2 != NULL; dp2 = dp2->hostnext)
868         if(dp2->inprogress && dp2->spindle == dp->spindle) {
869             return 1;
870         }
871
872     return 0;
873 }
874
875 static void
876 start_some_dumps(
877     disklist_t *        rq)
878 {
879     int cur_idle;
880     disk_t *diskp, *delayed_diskp, *diskp_accept;
881     disk_t *dp;
882     assignedhd_t **holdp=NULL, **holdp_accept;
883     const time_t now = time(NULL);
884     cmd_t cmd;
885     int result_argc;
886     char **result_argv;
887     chunker_t *chunker;
888     dumper_t *dumper;
889     char dumptype;
890     char *dumporder;
891     int  busy_dumpers = 0;
892
893     idle_reason = IDLE_NO_DUMPERS;
894     sleep_time = 0;
895
896     if(dumpers_ev_time != NULL) {
897         event_release(dumpers_ev_time);
898         dumpers_ev_time = NULL;
899     }
900
901     for(dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
902         if( dumper->busy ) {
903             busy_dumpers++;
904         }
905     }
906
907     for (dumper = dmptable; dumper < dmptable+inparallel; dumper++) {
908
909         if( dumper->busy || dumper->down) {
910             continue;
911         }
912
913         if (dumper->ev_read != NULL) {
914             event_release(dumper->ev_read);
915             dumper->ev_read = NULL;
916         }
917
918         /*
919          * A potential problem with starting from the bottom of the dump time
920          * distribution is that a slave host will have both one of the shortest
921          * and one of the longest disks, so starting its shortest disk first will
922          * tie up the host and eliminate its longest disk from consideration the
923          * first pass through.  This could cause a big delay in starting that long
924          * disk, which could drag out the whole night's dumps.
925          *
926          * While starting from the top of the dump time distribution solves the
927          * above problem, this turns out to be a bad idea, because the big dumps
928          * will almost certainly pack the holding disk completely, leaving no
929          * room for even one small dump to start.  This ends up shutting out the
930          * small-end dumpers completely (they stay idle).
931          *
932          * The introduction of multiple simultaneous dumps to one host alleviates
933          * the biggest&smallest dumps problem: both can be started at the
934          * beginning.
935          */
936
937         diskp_accept = NULL;
938         holdp_accept = NULL;
939         delayed_diskp = NULL;
940
941         cur_idle = NOT_IDLE;
942
943         dumporder = getconf_str(CNF_DUMPORDER);
944         if(strlen(dumporder) > (size_t)(dumper-dmptable)) {
945             dumptype = dumporder[dumper-dmptable];
946         }
947         else {
948             if(dumper-dmptable < 3)
949                 dumptype = 't';
950             else
951                 dumptype = 'T';
952         }
953
954         for(diskp = rq->head; diskp != NULL; diskp = diskp->next) {
955             assert(diskp->host != NULL && sched(diskp) != NULL);
956
957             if (diskp->host->start_t > now) {
958                 cur_idle = max(cur_idle, IDLE_START_WAIT);
959                 if (delayed_diskp == NULL || sleep_time > diskp->host->start_t) {
960                     delayed_diskp = diskp;
961                     sleep_time = diskp->host->start_t;
962                 }
963             } else if(diskp->start_t > now) {
964                 cur_idle = max(cur_idle, IDLE_START_WAIT);
965                 if (delayed_diskp == NULL || sleep_time > diskp->start_t) {
966                     delayed_diskp = diskp;
967                     sleep_time = diskp->start_t;
968                 }
969             } else if (diskp->host->netif->curusage > 0 &&
970                        sched(diskp)->est_kps > free_kps(diskp->host->netif)) {
971                 cur_idle = max(cur_idle, IDLE_NO_BANDWIDTH);
972             } else if(sched(diskp)->no_space) {
973                 cur_idle = max(cur_idle, IDLE_NO_DISKSPACE);
974             } else if (diskp->to_holdingdisk == HOLD_NEVER) {
975                 cur_idle = max(cur_idle, IDLE_NO_HOLD);
976             } else if ((holdp =
977                 find_diskspace(sched(diskp)->est_size, &cur_idle, NULL)) == NULL) {
978                 cur_idle = max(cur_idle, IDLE_NO_DISKSPACE);
979                 if (empty(tapeq) && busy_dumpers == 0) {
980                     remove_disk(rq, diskp);
981                     enqueue_disk(&directq, diskp);
982                 }
983             } else if (client_constrained(diskp)) {
984                 free_assignedhd(holdp);
985                 cur_idle = max(cur_idle, IDLE_CLIENT_CONSTRAINED);
986             } else {
987
988                 /* disk fits, dump it */
989                 int accept = !diskp_accept;
990                 if(!accept) {
991                     switch(dumptype) {
992                       case 's': accept = (sched(diskp)->est_size < sched(diskp_accept)->est_size);
993                                 break;
994                       case 'S': accept = (sched(diskp)->est_size > sched(diskp_accept)->est_size);
995                                 break;
996                       case 't': accept = (sched(diskp)->est_time < sched(diskp_accept)->est_time);
997                                 break;
998                       case 'T': accept = (sched(diskp)->est_time > sched(diskp_accept)->est_time);
999                                 break;
1000                       case 'b': accept = (sched(diskp)->est_kps < sched(diskp_accept)->est_kps);
1001                                 break;
1002                       case 'B': accept = (sched(diskp)->est_kps > sched(diskp_accept)->est_kps);
1003                                 break;
1004                       default:  log_add(L_WARNING, _("Unknown dumporder character \'%c\', using 's'.\n"),
1005                                         dumptype);
1006                                 accept = (sched(diskp)->est_size < sched(diskp_accept)->est_size);
1007                                 break;
1008                     }
1009                 }
1010                 if(accept) {
1011                     if( !diskp_accept || !degraded_mode || diskp->priority >= diskp_accept->priority) {
1012                         if(holdp_accept) free_assignedhd(holdp_accept);
1013                         diskp_accept = diskp;
1014                         holdp_accept = holdp;
1015                     }
1016                     else {
1017                         free_assignedhd(holdp);
1018                     }
1019                 }
1020                 else {
1021                     free_assignedhd(holdp);
1022                 }
1023             }
1024         }
1025
1026         diskp = diskp_accept;
1027         holdp = holdp_accept;
1028
1029         idle_reason = max(idle_reason, cur_idle);
1030
1031         /*
1032          * If we have no disk at this point, and there are disks that
1033          * are delayed, then schedule a time event to call this dumper
1034          * with the disk with the shortest delay.
1035          */
1036         if (diskp == NULL && delayed_diskp != NULL) {
1037             assert(sleep_time > now);
1038             sleep_time -= now;
1039             dumpers_ev_time = event_register((event_id_t)sleep_time, EV_TIME,
1040                 handle_dumpers_time, &runq);
1041             return;
1042         } else if (diskp != NULL) {
1043             sched(diskp)->act_size = (off_t)0;
1044             allocate_bandwidth(diskp->host->netif, sched(diskp)->est_kps);
1045             sched(diskp)->activehd = assign_holdingdisk(holdp, diskp);
1046             amfree(holdp);
1047             sched(diskp)->destname = newstralloc(sched(diskp)->destname,
1048                                                  sched(diskp)->holdp[0]->destname);
1049             diskp->host->inprogress++;  /* host is now busy */
1050             diskp->inprogress = 1;
1051             sched(diskp)->dumper = dumper;
1052             sched(diskp)->timestamp = now;
1053
1054             dumper->busy = 1;           /* dumper is now busy */
1055             dumper->dp = diskp;         /* link disk to dumper */
1056             remove_disk(rq, diskp);             /* take it off the run queue */
1057
1058             sched(diskp)->origsize = (off_t)-1;
1059             sched(diskp)->dumpsize = (off_t)-1;
1060             sched(diskp)->dumptime = (time_t)0;
1061             sched(diskp)->tapetime = (time_t)0;
1062             chunker = dumper->chunker;
1063             chunker->result = LAST_TOK;
1064             dumper->result = LAST_TOK;
1065             startup_chunk_process(chunker,chunker_program);
1066             chunker_cmd(chunker, START, NULL, driver_timestamp);
1067             chunker->dumper = dumper;
1068             chunker_cmd(chunker, PORT_WRITE, diskp, NULL);
1069             cmd = getresult(chunker->fd, 1, &result_argc, &result_argv);
1070             if(cmd != PORT) {
1071                 assignedhd_t **h=NULL;
1072                 int activehd;
1073                 char *qname = quote_string(diskp->name);
1074
1075                 g_printf(_("driver: did not get PORT from %s for %s:%s\n"),
1076                        chunker->name, diskp->host->hostname, qname);
1077                 amfree(qname);
1078                 fflush(stdout);
1079
1080                 deallocate_bandwidth(diskp->host->netif, sched(diskp)->est_kps);
1081                 h = sched(diskp)->holdp;
1082                 activehd = sched(diskp)->activehd;
1083                 h[activehd]->used = 0;
1084                 h[activehd]->disk->allocated_dumpers--;
1085                 adjust_diskspace(diskp, DONE);
1086                 delete_diskspace(diskp);
1087                 diskp->host->inprogress--;
1088                 diskp->inprogress = 0;
1089                 sched(diskp)->dumper = NULL;
1090                 dumper->busy = 0;
1091                 dumper->dp = NULL;
1092                 sched(diskp)->dump_attempted++;
1093                 free_serial_dp(diskp);
1094                 if(sched(diskp)->dump_attempted < 2)
1095                     enqueue_disk(rq, diskp);
1096             }
1097             else {
1098                 dumper->ev_read = event_register((event_id_t)dumper->fd, EV_READFD,
1099                                                  handle_dumper_result, dumper);
1100                 chunker->ev_read = event_register((event_id_t)chunker->fd, EV_READFD,
1101                                                    handle_chunker_result, chunker);
1102                 dumper->output_port = atoi(result_argv[1]);
1103
1104                 if (diskp->host->pre_script == 0) {
1105                     for (dp=diskp->host->disks; dp != NULL; dp = dp->hostnext) {
1106                         run_server_scripts(EXECUTE_ON_PRE_HOST_BACKUP,
1107                                            get_config_name(), dp, -1);
1108                     }
1109                     diskp->host->pre_script = 1;
1110                 }
1111                 run_server_scripts(EXECUTE_ON_PRE_DLE_BACKUP,
1112                                    get_config_name(), diskp,
1113                                    sched(diskp)->level);
1114                 dumper_cmd(dumper, PORT_DUMP, diskp, NULL);
1115             }
1116             diskp->host->start_t = now + 15;
1117
1118             if (result_argv)
1119                 g_strfreev(result_argv);
1120             short_dump_state();
1121         }
1122     }
1123 }
1124
1125 /*
1126  * This gets called when a dumper is delayed for some reason.  It may
1127  * be because a disk has a delayed start, or amanda is constrained
1128  * by network or disk limits.
1129  */
1130
1131 static void
1132 handle_dumpers_time(
1133     void *      cookie)
1134 {
1135     disklist_t *runq = cookie;
1136     event_release(dumpers_ev_time);
1137     dumpers_ev_time = NULL; 
1138     start_some_dumps(runq);
1139 }
1140
1141 static void
1142 dump_schedule(
1143     disklist_t *qp,
1144     char *      str)
1145 {
1146     disk_t *dp;
1147     char *qname;
1148
1149     g_printf(_("dump of driver schedule %s:\n--------\n"), str);
1150
1151     for(dp = qp->head; dp != NULL; dp = dp->next) {
1152         qname = quote_string(dp->name);
1153         g_printf("  %-20s %-25s lv %d t %5lu s %lld p %d\n",
1154                dp->host->hostname, qname, sched(dp)->level,
1155                sched(dp)->est_time,
1156                (long long)sched(dp)->est_size, sched(dp)->priority);
1157         amfree(qname);
1158     }
1159     g_printf("--------\n");
1160 }
1161
1162 static void
1163 start_degraded_mode(
1164     /*@keep@*/ disklist_t *queuep)
1165 {
1166     disk_t *dp;
1167     disklist_t newq;
1168     off_t est_full_size;
1169     char *qname;
1170
1171     newq.head = newq.tail = 0;
1172
1173     dump_schedule(queuep, _("before start degraded mode"));
1174
1175     est_full_size = (off_t)0;
1176     while(!empty(*queuep)) {
1177         dp = dequeue_disk(queuep);
1178
1179         qname = quote_string(dp->name);
1180         if(sched(dp)->level != 0)
1181             /* go ahead and do the disk as-is */
1182             enqueue_disk(&newq, dp);
1183         else {
1184             if (reserved_space + est_full_size + sched(dp)->est_size
1185                 <= total_disksize) {
1186                 enqueue_disk(&newq, dp);
1187                 est_full_size += sched(dp)->est_size;
1188             }
1189             else if(sched(dp)->degr_level != -1) {
1190                 sched(dp)->level = sched(dp)->degr_level;
1191                 sched(dp)->dumpdate = sched(dp)->degr_dumpdate;
1192                 sched(dp)->est_nsize = sched(dp)->degr_nsize;
1193                 sched(dp)->est_csize = sched(dp)->degr_csize;
1194                 sched(dp)->est_time = sched(dp)->degr_time;
1195                 sched(dp)->est_kps  = sched(dp)->degr_kps;
1196                 enqueue_disk(&newq, dp);
1197             }
1198             else {
1199                 log_add(L_FAIL, "%s %s %s %d [%s]",
1200                         dp->host->hostname, qname, sched(dp)->datestamp,
1201                         sched(dp)->level, sched(dp)->degr_mesg);
1202             }
1203         }
1204         amfree(qname);
1205     }
1206
1207     /*@i@*/ *queuep = newq;
1208     degraded_mode = 1;
1209
1210     dump_schedule(queuep, _("after start degraded mode"));
1211 }
1212
1213
1214 static void
1215 continue_port_dumps(void)
1216 {
1217     disk_t *dp, *ndp;
1218     assignedhd_t **h;
1219     int active_dumpers=0, busy_dumpers=0, i;
1220     dumper_t *dumper;
1221
1222     /* First we try to grant diskspace to some dumps waiting for it. */
1223     for( dp = roomq.head; dp; dp = ndp ) {
1224         ndp = dp->next;
1225         /* find last holdingdisk used by this dump */
1226         for( i = 0, h = sched(dp)->holdp; h[i+1]; i++ ) {
1227             (void)h; /* Quiet lint */
1228         }
1229         /* find more space */
1230         h = find_diskspace( sched(dp)->est_size - sched(dp)->act_size,
1231                             &active_dumpers, h[i] );
1232         if( h ) {
1233             for(dumper = dmptable; dumper < dmptable + inparallel &&
1234                                    dumper->dp != dp; dumper++) {
1235                 (void)dp; /* Quiet lint */
1236             }
1237             assert( dumper < dmptable + inparallel );
1238             sched(dp)->activehd = assign_holdingdisk( h, dp );
1239             chunker_cmd( dumper->chunker, CONTINUE, dp, NULL );
1240             amfree(h);
1241             remove_disk( &roomq, dp );
1242         }
1243     }
1244
1245     /* So for some disks there is less holding diskspace available than
1246      * was asked for. Possible reasons are
1247      * a) diskspace has been allocated for other dumps which are
1248      *    still running or already being written to tape
1249      * b) all other dumps have been suspended due to lack of diskspace
1250      * c) this dump doesn't fit on all the holding disks
1251      * Case a) is not a problem. We just wait for the diskspace to
1252      * be freed by moving the current disk to a queue.
1253      * If case b) occurs, we have a deadlock situation. We select
1254      * a dump from the queue to be aborted and abort it. It will
1255      * be retried later dumping to disk.
1256      * If case c) is detected, the dump is aborted. Next time
1257      * it will be dumped directly to tape. Actually, case c is a special
1258      * manifestation of case b) where only one dumper is busy.
1259      */
1260     for(dp=NULL, dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
1261         if( dumper->busy ) {
1262             busy_dumpers++;
1263             if( !find_disk(&roomq, dumper->dp) ) {
1264                 active_dumpers++;
1265             } else if( !dp || 
1266                        sched(dp)->est_size > sched(dumper->dp)->est_size ) {
1267                 dp = dumper->dp;
1268             }
1269         }
1270     }
1271     if((dp != NULL) && (active_dumpers == 0) && (busy_dumpers > 0) && 
1272         ((!taper_busy && empty(tapeq)) || degraded_mode) &&
1273         pending_aborts == 0 ) { /* not case a */
1274         if( busy_dumpers == 1 ) { /* case c */
1275             sched(dp)->no_space = 1;
1276         }
1277         /* case b */
1278         /* At this time, dp points to the dump with the smallest est_size.
1279          * We abort that dump, hopefully not wasting too much time retrying it.
1280          */
1281         remove_disk( &roomq, dp );
1282         chunker_cmd(sched(dp)->dumper->chunker, ABORT, NULL, _("Not enough holding disk space"));
1283         dumper_cmd( sched(dp)->dumper, ABORT, NULL, _("Not enough holding disk space"));
1284         pending_aborts++;
1285     }
1286 }
1287
1288
1289 static void
1290 handle_taper_result(
1291         void *cookie G_GNUC_UNUSED)
1292 {
1293     disk_t *dp;
1294     cmd_t cmd;
1295     int result_argc;
1296     char **result_argv;
1297     char *qname, *q;
1298     char *s;
1299
1300     assert(cookie == NULL);
1301     amfree(taper_input_error);
1302     amfree(taper_tape_error);
1303     
1304     do {
1305         
1306         short_dump_state();
1307         
1308         cmd = getresult(taper, 1, &result_argc, &result_argv);
1309         
1310         switch(cmd) {
1311             
1312         case FAILED:    /* FAILED <handle> INPUT-* TAPE-* <input err mesg> <tape err mesg> */
1313             if(result_argc != 6) {
1314                 error(_("error: [taper FAILED result_argc != 6: %d"), result_argc);
1315                 /*NOTREACHED*/
1316             }
1317             
1318             dp = serial2disk(result_argv[1]);
1319             assert(dp == taper_disk);
1320             if (!taper_dumper)
1321                 free_serial(result_argv[1]);
1322             
1323             qname = quote_string(dp->name);
1324             g_printf(_("driver: finished-cmd time %s taper wrote %s:%s\n"),
1325                    walltime_str(curclock()), dp->host->hostname, qname);
1326             fflush(stdout);
1327
1328             if (strcmp(result_argv[2], "INPUT-ERROR") == 0) {
1329                 taper_input_error = newstralloc(taper_input_error, result_argv[4]);
1330             } else if (strcmp(result_argv[2], "INPUT-GOOD") != 0) {
1331                 taper_tape_error = newstralloc(taper_tape_error,
1332                                                _("Taper protocol error"));
1333                 taper_result = FAILED;
1334                 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1335                         dp->host->hostname, qname, sched(dp)->datestamp,
1336                         sched(dp)->level, taper_tape_error);
1337                 amfree(qname);
1338                 break;
1339             }
1340             if (strcmp(result_argv[3], "TAPE-ERROR") == 0) {
1341                 taper_tape_error = newstralloc(taper_tape_error, result_argv[5]);
1342             } else if (strcmp(result_argv[3], "TAPE-GOOD") != 0) {
1343                 taper_tape_error = newstralloc(taper_tape_error,
1344                                                _("Taper protocol error"));
1345                 taper_result = FAILED;
1346                 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1347                         dp->host->hostname, qname, sched(dp)->datestamp,
1348                         sched(dp)->level, taper_tape_error);
1349                 amfree(qname);
1350                 break;
1351             }
1352
1353             amfree(qname);
1354             taper_result = cmd;
1355
1356             break;
1357             
1358         case PARTIAL:   /* PARTIAL <handle> INPUT-* TAPE-* <stat mess> <input err mesg> <tape err mesg>*/
1359         case DONE:      /* DONE <handle> INPUT-GOOD TAPE-GOOD <stat mess> <input err mesg> <tape err mesg> */
1360             if(result_argc != 7) {
1361                 error(_("error: [taper PARTIAL result_argc != 7: %d"), result_argc);
1362                 /*NOTREACHED*/
1363             }
1364             
1365             dp = serial2disk(result_argv[1]);
1366             assert(dp == taper_disk);
1367             if (!taper_dumper)
1368                 free_serial(result_argv[1]);
1369
1370             qname = quote_string(dp->name);
1371             g_printf(_("driver: finished-cmd time %s taper wrote %s:%s\n"),
1372                    walltime_str(curclock()), dp->host->hostname, qname);
1373             fflush(stdout);
1374
1375             if (strcmp(result_argv[2], "INPUT-ERROR") == 0) {
1376                 taper_input_error = newstralloc(taper_input_error, result_argv[5]);
1377             } else if (strcmp(result_argv[2], "INPUT-GOOD") != 0) {
1378                 taper_tape_error = newstralloc(taper_tape_error,
1379                                                _("Taper protocol error"));
1380                 taper_result = FAILED;
1381                 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1382                         dp->host->hostname, qname, sched(dp)->datestamp,
1383                         sched(dp)->level, taper_tape_error);
1384                 amfree(qname);
1385                 break;
1386             }
1387             if (strcmp(result_argv[3], "TAPE-ERROR") == 0) {
1388                 taper_tape_error = newstralloc(taper_tape_error, result_argv[6]);
1389             } else if (strcmp(result_argv[3], "TAPE-GOOD") != 0) {
1390                 taper_tape_error = newstralloc(taper_tape_error,
1391                                                _("Taper protocol error"));
1392                 taper_result = FAILED;
1393                 log_add(L_FAIL, _("%s %s %s %d [%s]"),
1394                         dp->host->hostname, qname, sched(dp)->datestamp,
1395                         sched(dp)->level, taper_tape_error);
1396                 amfree(qname);
1397                 break;
1398             }
1399
1400             s = strstr(result_argv[4], " kb ");
1401             if (s) {
1402                 s += 4;
1403                 sched(dp)->dumpsize = atol(s);
1404             }
1405
1406             taper_result = cmd;
1407             amfree(qname);
1408
1409             break;
1410             
1411         case PARTDONE:  /* PARTDONE <handle> <label> <fileno> <kbytes> <stat> */
1412             dp = serial2disk(result_argv[1]);
1413             assert(dp == taper_disk);
1414             if (result_argc != 6) {
1415                 error(_("error [taper PARTDONE result_argc != 6: %d]"),
1416                       result_argc);
1417                 /*NOTREACHED*/
1418             }
1419             if (!taper_first_label) {
1420                 taper_first_label = stralloc(result_argv[2]);
1421                 taper_first_fileno = OFF_T_ATOI(result_argv[3]);
1422             }
1423             taper_written = OFF_T_ATOI(result_argv[4]);
1424             if (taper_written > sched(taper_disk)->act_size)
1425                 sched(taper_disk)->act_size = taper_written;
1426             
1427             break;
1428
1429         case REQUEST_NEW_TAPE:  /* REQUEST-NEW-TAPE <handle> */
1430             if (result_argc != 2) {
1431                 error(_("error [taper REQUEST_NEW_TAPE result_argc != 2: %d]"),
1432                       result_argc);
1433                 /*NOTREACHED*/
1434             }
1435             taper_state &= ~TAPER_STATE_TAPE_STARTED;
1436
1437             if (current_tape >= conf_runtapes) {
1438                 taper_cmd(NO_NEW_TAPE, "runtapes volumes already written", NULL, 0, NULL);
1439                 log_add(L_WARNING,
1440                         _("Out of tapes; going into degraded mode."));
1441                 start_degraded_mode(&runq);
1442             } else {
1443                 TapeAction result_tape_action;
1444                 char *why_no_new_tape;
1445
1446                 taper_state |= TAPER_STATE_WAIT_FOR_TAPE;
1447                 result_tape_action = tape_action(&why_no_new_tape);
1448                 if (result_tape_action & TAPE_ACTION_NEW_TAPE) {
1449                     taper_cmd(NEW_TAPE, NULL, NULL, 0, NULL);
1450                     taper_state &= ~TAPER_STATE_WAIT_FOR_TAPE;
1451                 } else if (result_tape_action & TAPE_ACTION_NO_NEW_TAPE) {
1452                     taper_cmd(NO_NEW_TAPE, why_no_new_tape, NULL, 0, NULL);
1453                     taper_state &= ~TAPER_STATE_WAIT_FOR_TAPE;
1454                     start_degraded_mode(&runq);
1455                 }
1456             }
1457             break;
1458
1459         case NEW_TAPE: /* NEW-TAPE <handle> <label> */
1460             if (result_argc != 3) {
1461                 error(_("error [taper NEW_TAPE result_argc != 3: %d]"),
1462                       result_argc);
1463                 /*NOTREACHED*/
1464             }
1465
1466             /* Update our tape counter and reset tape_left */
1467             current_tape++;
1468             tape_left = tape_length;
1469             taper_state |= TAPER_STATE_TAPE_STARTED;
1470             break;
1471
1472         case NO_NEW_TAPE:  /* NO-NEW-TAPE <handle> */
1473             if (result_argc != 2) {
1474                 error(_("error [taper NO_NEW_TAPE result_argc != 2: %d]"),
1475                       result_argc);
1476                 /*NOTREACHED*/
1477             }
1478             start_degraded_mode(&runq);
1479             break;
1480
1481         case DUMPER_STATUS:  /* DUMPER-STATUS <handle> */
1482             if (result_argc != 2) {
1483                 error(_("error [taper NO_NEW_TAPE result_argc != 2: %d]"),
1484                       result_argc);
1485                 /*NOTREACHED*/
1486             }
1487             if (taper_dumper->result == LAST_TOK) {
1488                 taper_sendresult = 1;
1489             } else {
1490                 if( taper_dumper->result == DONE) {
1491                     taper_cmd(DONE, NULL, NULL, 0, NULL);
1492                 } else {
1493                     taper_cmd(FAILED, NULL, NULL, 0, NULL);
1494                 }
1495             }
1496             break;
1497
1498         case TAPE_ERROR: /* TAPE-ERROR <handle> <err mess> */
1499             dp = serial2disk(result_argv[1]);
1500             if (!taper_dumper)
1501                 free_serial(result_argv[1]);
1502             qname = quote_string(dp->name);
1503             g_printf(_("driver: finished-cmd time %s taper wrote %s:%s\n"),
1504                    walltime_str(curclock()), dp->host->hostname, qname);
1505             amfree(qname);
1506             fflush(stdout);
1507             q = quote_string(result_argv[2]);
1508             log_add(L_WARNING, _("Taper error: %s"), q);
1509             amfree(q);
1510             taper_tape_error = newstralloc(taper_tape_error, result_argv[2]);
1511             /*FALLTHROUGH*/
1512
1513         case BOGUS:
1514             if (cmd == BOGUS) {
1515                 log_add(L_WARNING, _("Taper protocol error"));
1516                 taper_tape_error = newstralloc(taper_tape_error, "BOGUS");
1517             }
1518             /*
1519              * Since we received a taper error, we can't send anything more
1520              * to the taper.  Go into degraded mode to try to get everthing
1521              * onto disk.  Later, these dumps can be flushed to a new tape.
1522              * The tape queue is zapped so that it appears empty in future
1523              * checks. If there are dumps waiting for diskspace to be freed,
1524              * cancel one.
1525              */
1526             if(!nodump) {
1527                 log_add(L_WARNING,
1528                         _("going into degraded mode because of taper component error."));
1529                 start_degraded_mode(&runq);
1530             }
1531             tapeq.head = tapeq.tail = NULL;
1532             taper_busy = 0;
1533             if(taper_ev_read != NULL) {
1534                 event_release(taper_ev_read);
1535                 taper_ev_read = NULL;
1536             }
1537             if(cmd != TAPE_ERROR) aclose(taper);
1538             taper_result = cmd;
1539
1540             break;
1541
1542         default:
1543             error(_("driver received unexpected token (%s) from taper"),
1544                   cmdstr[cmd]);
1545             /*NOTREACHED*/
1546         }
1547
1548         g_strfreev(result_argv);
1549
1550         if (taper_result != LAST_TOK) {
1551             if(taper_dumper) {
1552                 if (taper_dumper->result != LAST_TOK) {
1553                     // Dumper already returned it's result
1554                     dumper_taper_result(taper_disk);
1555                 }
1556             } else {
1557                 file_taper_result(taper_disk);
1558             }
1559         }
1560         
1561     } while(areads_dataready(taper));
1562 }
1563
1564
1565 static void
1566 file_taper_result(
1567     disk_t *dp)
1568 {
1569     char *qname = quote_string(dp->name);
1570
1571     if (taper_result == DONE) {
1572         update_info_taper(dp, taper_first_label, taper_first_fileno,
1573                           sched(dp)->level);
1574     }
1575
1576     sched(dp)->taper_attempted += 1;
1577
1578     if (taper_input_error) {
1579         g_printf("driver: taper failed %s %s: %s\n",
1580                    dp->host->hostname, qname, taper_input_error);
1581         if (strcmp(sched(dp)->datestamp, driver_timestamp) == 0) {
1582             if(sched(dp)->taper_attempted >= 2) {
1583                 log_add(L_FAIL, _("%s %s %s %d [too many taper retries after holding disk error: %s]"),
1584                     dp->host->hostname, qname, sched(dp)->datestamp,
1585                     sched(dp)->level, taper_input_error);
1586                 g_printf("driver: taper failed %s %s, too many taper retry after holding disk error\n",
1587                    dp->host->hostname, qname);
1588                 amfree(sched(dp)->destname);
1589                 amfree(sched(dp)->dumpdate);
1590                 amfree(sched(dp)->degr_dumpdate);
1591                 amfree(sched(dp)->degr_mesg);
1592                 amfree(sched(dp)->datestamp);
1593                 amfree(dp->up);
1594             } else {
1595                 log_add(L_INFO, _("%s %s %s %d [Will retry dump because of holding disk error: %s]"),
1596                         dp->host->hostname, qname, sched(dp)->datestamp,
1597                         sched(dp)->level, taper_input_error);
1598                 g_printf("driver: taper will retry %s %s because of holding disk error\n",
1599                         dp->host->hostname, qname);
1600                 if (dp->to_holdingdisk != HOLD_REQUIRED) {
1601                     dp->to_holdingdisk = HOLD_NEVER;
1602                     sched(dp)->dump_attempted -= 1;
1603                     headqueue_disk(&directq, dp);
1604                 } else {
1605                     amfree(sched(dp)->destname);
1606                     amfree(sched(dp)->dumpdate);
1607                     amfree(sched(dp)->degr_dumpdate);
1608                     amfree(sched(dp)->degr_mesg);
1609                     amfree(sched(dp)->datestamp);
1610                     amfree(dp->up);
1611                 }
1612             }
1613         } else {
1614             amfree(sched(dp)->destname);
1615             amfree(sched(dp)->dumpdate);
1616             amfree(sched(dp)->degr_dumpdate);
1617             amfree(sched(dp)->degr_mesg);
1618             amfree(sched(dp)->datestamp);
1619             amfree(dp->up);
1620         }
1621     } else if (taper_tape_error) {
1622         g_printf("driver: taper failed %s %s with tape error: %s\n",
1623                    dp->host->hostname, qname, taper_tape_error);
1624         if(sched(dp)->taper_attempted >= 2) {
1625             log_add(L_FAIL, _("%s %s %s %d [too many taper retries]"),
1626                     dp->host->hostname, qname, sched(dp)->datestamp,
1627                     sched(dp)->level);
1628             g_printf("driver: taper failed %s %s, too many taper retry\n",
1629                    dp->host->hostname, qname);
1630             amfree(sched(dp)->destname);
1631             amfree(sched(dp)->dumpdate);
1632             amfree(sched(dp)->degr_dumpdate);
1633             amfree(sched(dp)->degr_mesg);
1634             amfree(sched(dp)->datestamp);
1635             amfree(dp->up);
1636         } else {
1637             g_printf("driver: taper will retry %s %s\n",
1638                    dp->host->hostname, qname);
1639             /* Re-insert into taper queue. */
1640             headqueue_disk(&tapeq, dp);
1641         }
1642     } else if (taper_result != DONE) {
1643         g_printf("driver: taper failed %s %s without error\n",
1644                    dp->host->hostname, qname);
1645     } else {
1646         delete_diskspace(dp);
1647         amfree(sched(dp)->destname);
1648         amfree(sched(dp)->dumpdate);
1649         amfree(sched(dp)->degr_dumpdate);
1650         amfree(sched(dp)->degr_mesg);
1651         amfree(sched(dp)->datestamp);
1652         amfree(dp->up);
1653     }
1654
1655     amfree(qname);
1656
1657     taper_busy = 0;
1658     amfree(taper_input_error);
1659     amfree(taper_tape_error);
1660     taper_disk = NULL;
1661             
1662     /* continue with those dumps waiting for diskspace */
1663     continue_port_dumps();
1664     start_some_dumps(&runq);
1665     startaflush();
1666 }
1667
1668 static void
1669 dumper_taper_result(
1670     disk_t *dp)
1671 {
1672     dumper_t *dumper;
1673     int is_partial;
1674     char *qname;
1675
1676     dumper = sched(dp)->dumper;
1677
1678     free_serial_dp(dp);
1679     if(dumper->result == DONE && taper_result == DONE) {
1680         update_info_dumper(dp, sched(dp)->origsize,
1681                            sched(dp)->dumpsize, sched(dp)->dumptime);
1682         update_info_taper(dp, taper_first_label, taper_first_fileno,
1683                           sched(dp)->level);
1684         qname = quote_string(dp->name); /*quote to take care of spaces*/
1685
1686         log_add(L_STATS, _("estimate %s %s %s %d [sec %ld nkb %lld ckb %lld kps %lu]"),
1687                 dp->host->hostname, qname, sched(dp)->datestamp,
1688                 sched(dp)->level,
1689                 sched(dp)->est_time, (long long)sched(dp)->est_nsize,
1690                 (long long)sched(dp)->est_csize,
1691                 sched(dp)->est_kps);
1692         amfree(qname);
1693     } else {
1694         update_failed_dump_to_tape(dp);
1695     }
1696
1697     is_partial = dumper->result != DONE || taper_result != DONE;
1698
1699     sched(dp)->dump_attempted += 1;
1700     sched(dp)->taper_attempted += 1;
1701
1702     if((dumper->result != DONE || taper_result != DONE) &&
1703         sched(dp)->dump_attempted <= 1 &&
1704         sched(dp)->taper_attempted <= 1) {
1705         enqueue_disk(&directq, dp);
1706     }
1707
1708     if(dumper->ev_read != NULL) {
1709         event_release(dumper->ev_read);
1710         dumper->ev_read = NULL;
1711     }
1712     if(taper_ev_read != NULL) {
1713         event_release(taper_ev_read);
1714         taper_ev_read = NULL;
1715     }
1716     taper_busy = 0;
1717     amfree(taper_input_error);
1718     amfree(taper_tape_error);
1719     dumper->busy = 0;
1720     dp->host->inprogress -= 1;
1721     dp->inprogress = 0;
1722     deallocate_bandwidth(dp->host->netif, sched(dp)->est_kps);
1723 }
1724
1725
1726 static dumper_t *
1727 idle_dumper(void)
1728 {
1729     dumper_t *dumper;
1730
1731     for(dumper = dmptable; dumper < dmptable+inparallel; dumper++)
1732         if(!dumper->busy && !dumper->down) return dumper;
1733
1734     return NULL;
1735 }
1736
1737 static void
1738 dumper_chunker_result(
1739     disk_t *    dp)
1740 {
1741     dumper_t *dumper;
1742     chunker_t *chunker;
1743     assignedhd_t **h=NULL;
1744     int activehd, i;
1745     off_t dummy;
1746     off_t size;
1747     int is_partial;
1748     char *qname;
1749
1750     dumper = sched(dp)->dumper;
1751     chunker = dumper->chunker;
1752
1753     free_serial_dp(dp);
1754
1755     h = sched(dp)->holdp;
1756     activehd = sched(dp)->activehd;
1757
1758     if(dumper->result == DONE && chunker->result == DONE) {
1759         update_info_dumper(dp, sched(dp)->origsize,
1760                            sched(dp)->dumpsize, sched(dp)->dumptime);
1761         qname = quote_string(dp->name);/*quote to take care of spaces*/
1762
1763         log_add(L_STATS, _("estimate %s %s %s %d [sec %ld nkb %lld ckb %lld kps %lu]"),
1764                 dp->host->hostname, qname, sched(dp)->datestamp,
1765                 sched(dp)->level,
1766                 sched(dp)->est_time, (long long)sched(dp)->est_nsize, 
1767                 (long long)sched(dp)->est_csize,
1768                 sched(dp)->est_kps);
1769         amfree(qname);
1770     }
1771
1772     deallocate_bandwidth(dp->host->netif, sched(dp)->est_kps);
1773
1774     is_partial = dumper->result != DONE || chunker->result != DONE;
1775     rename_tmp_holding(sched(dp)->destname, !is_partial);
1776
1777     dummy = (off_t)0;
1778     for( i = 0, h = sched(dp)->holdp; i < activehd; i++ ) {
1779         dummy += h[i]->used;
1780     }
1781
1782     size = holding_file_size(sched(dp)->destname, 0);
1783     h[activehd]->used = size - dummy;
1784     h[activehd]->disk->allocated_dumpers--;
1785     adjust_diskspace(dp, DONE);
1786
1787     sched(dp)->dump_attempted += 1;
1788
1789     if((dumper->result != DONE || chunker->result != DONE) &&
1790        sched(dp)->dump_attempted <= 1) {
1791         delete_diskspace(dp);
1792         if (sched(dp)->no_space) {
1793             enqueue_disk(&directq, dp);
1794         } else {
1795             enqueue_disk(&runq, dp);
1796         }
1797     }
1798     else if(size > (off_t)DISK_BLOCK_KB) {
1799         enqueue_disk(&tapeq, dp);
1800     }
1801     else {
1802         delete_diskspace(dp);
1803     }
1804
1805     dumper->busy = 0;
1806     dp->host->inprogress -= 1;
1807     dp->inprogress = 0;
1808
1809     waitpid(chunker->pid, NULL, 0 );
1810     aclose(chunker->fd);
1811     chunker->fd = -1;
1812     chunker->down = 1;
1813     
1814     dp = NULL;
1815     if (chunker->result == ABORT_FINISHED)
1816         pending_aborts--;
1817     continue_port_dumps();
1818     /*
1819      * Wakeup any dumpers that are sleeping because of network
1820      * or disk constraints.
1821      */
1822     start_some_dumps(&runq);
1823     startaflush();
1824 }
1825
1826
1827 static void
1828 handle_dumper_result(
1829         void * cookie)
1830 {
1831     /* uses global pending_aborts */
1832     dumper_t *dumper = cookie;
1833     disk_t *dp, *sdp, *dp1;
1834     cmd_t cmd;
1835     int result_argc;
1836     char *qname;
1837     char **result_argv;
1838
1839     assert(dumper != NULL);
1840     dp = dumper->dp;
1841     assert(dp != NULL);
1842     assert(sched(dp) != NULL);
1843     do {
1844
1845         short_dump_state();
1846
1847         cmd = getresult(dumper->fd, 1, &result_argc, &result_argv);
1848
1849         if(cmd != BOGUS) {
1850             /* result_argv[1] always contains the serial number */
1851             sdp = serial2disk(result_argv[1]);
1852             if (sdp != dp) {
1853                 error(_("Invalid serial number %s"), result_argv[1]);
1854                 g_assert_not_reached();
1855             }
1856         }
1857
1858         qname = quote_string(dp->name);
1859         switch(cmd) {
1860
1861         case DONE: /* DONE <handle> <origsize> <dumpsize> <dumptime> <errstr> */
1862             if(result_argc != 6) {
1863                 error(_("error [dumper DONE result_argc != 6: %d]"), result_argc);
1864                 /*NOTREACHED*/
1865             }
1866
1867             sched(dp)->origsize = OFF_T_ATOI(result_argv[2]);
1868             sched(dp)->dumptime = TIME_T_ATOI(result_argv[4]);
1869
1870             g_printf(_("driver: finished-cmd time %s %s dumped %s:%s\n"),
1871                    walltime_str(curclock()), dumper->name,
1872                    dp->host->hostname, qname);
1873             fflush(stdout);
1874
1875             dumper->result = cmd;
1876
1877             break;
1878
1879         case TRYAGAIN: /* TRY-AGAIN <handle> <errstr> */
1880             /*
1881              * Requeue this disk, and fall through to the FAILED
1882              * case for cleanup.
1883              */
1884             if(sched(dp)->dump_attempted) {
1885                 char *qname = quote_string(dp->name);
1886                 char *qerr = quote_string(result_argv[2]);
1887                 log_add(L_FAIL, _("%s %s %s %d [too many dumper retry: %s]"),
1888                     dp->host->hostname, qname, sched(dp)->datestamp,
1889                     sched(dp)->level, qerr);
1890                 g_printf(_("driver: dump failed %s %s %s, too many dumper retry: %s\n"),
1891                         result_argv[1], dp->host->hostname, qname, qerr);
1892                 amfree(qname);
1893                 amfree(qerr);
1894             }
1895             /* FALLTHROUGH */
1896         case FAILED: /* FAILED <handle> <errstr> */
1897             /*free_serial(result_argv[1]);*/
1898             dumper->result = cmd;
1899             break;
1900
1901         case ABORT_FINISHED: /* ABORT-FINISHED <handle> */
1902             /*
1903              * We sent an ABORT from the NO-ROOM case because this dump
1904              * wasn't going to fit onto the holding disk.  We now need to
1905              * clean up the remains of this image, and try to finish
1906              * other dumps that are waiting on disk space.
1907              */
1908             assert(pending_aborts);
1909             /*free_serial(result_argv[1]);*/
1910             dumper->result = cmd;
1911             break;
1912
1913         case BOGUS:
1914             /* either EOF or garbage from dumper.  Turn it off */
1915             log_add(L_WARNING, _("%s pid %ld is messed up, ignoring it.\n"),
1916                     dumper->name, (long)dumper->pid);
1917             if (dumper->ev_read) {
1918                 event_release(dumper->ev_read);
1919                 dumper->ev_read = NULL;
1920             }
1921             aclose(dumper->fd);
1922             dumper->busy = 0;
1923             dumper->down = 1;   /* mark it down so it isn't used again */
1924
1925             /* if it was dumping something, zap it and try again */
1926             if(sched(dp)->dump_attempted) {
1927                 log_add(L_FAIL, _("%s %s %s %d [%s died]"),
1928                         dp->host->hostname, qname, sched(dp)->datestamp,
1929                         sched(dp)->level, dumper->name);
1930             } else {
1931                 log_add(L_WARNING, _("%s died while dumping %s:%s lev %d."),
1932                         dumper->name, dp->host->hostname, qname,
1933                         sched(dp)->level);
1934             }
1935             dumper->result = cmd;
1936             break;
1937
1938         default:
1939             assert(0);
1940         }
1941         amfree(qname);
1942         g_strfreev(result_argv);
1943
1944         if (cmd != BOGUS) {
1945             int last_dump = 1;
1946             run_server_scripts(EXECUTE_ON_POST_DLE_BACKUP,
1947                                get_config_name(), dp, sched(dp)->level);
1948             for (dp1=runq.head; dp1 != NULL; dp1 = dp1->next) {
1949                 if (dp1 != dp) last_dump = 0;
1950             }
1951             if (last_dump && dp->host->post_script == 0) {
1952                 if (dp->host->post_script == 0) {
1953                     for (dp1=dp->host->disks; dp1 != NULL; dp1 = dp1->hostnext) {
1954                         run_server_scripts(EXECUTE_ON_POST_HOST_BACKUP,
1955                                            get_config_name(), dp1, -1);
1956                     }
1957                     dp->host->post_script = 1;
1958                 }
1959             }
1960         }
1961
1962         /* send the dumper result to the chunker */
1963         if (dumper->chunker) {
1964             if (dumper->chunker->down == 0 && dumper->chunker->fd != -1 &&
1965                 dumper->chunker->result == LAST_TOK) {
1966                 if (cmd == DONE) {
1967                     chunker_cmd(dumper->chunker, DONE, dp, NULL);
1968                 }
1969                 else {
1970                     chunker_cmd(dumper->chunker, FAILED, dp, NULL);
1971                 }
1972             }
1973             if( dumper->result != LAST_TOK &&
1974                 dumper->chunker->result != LAST_TOK)
1975                 dumper_chunker_result(dp);
1976         } else { /* send the dumper result to the taper */
1977             if (taper_sendresult) {
1978                 if (cmd == DONE) {
1979                     taper_cmd(DONE, driver_timestamp, NULL, 0, NULL);
1980                 } else {
1981                     taper_cmd(FAILED, driver_timestamp, NULL, 0, NULL);
1982                 }
1983                 taper_sendresult = 0;
1984             }
1985         }
1986         if (taper_dumper && taper_result != LAST_TOK) {
1987             dumper_taper_result(dp);
1988         }
1989     } while(areads_dataready(dumper->fd));
1990 }
1991
1992
1993 static void
1994 handle_chunker_result(
1995     void *      cookie)
1996 {
1997     chunker_t *chunker = cookie;
1998     assignedhd_t **h=NULL;
1999     dumper_t *dumper;
2000     disk_t *dp, *sdp;
2001     cmd_t cmd;
2002     int result_argc;
2003     char **result_argv;
2004     int dummy;
2005     int activehd = -1;
2006     char *qname;
2007
2008     assert(chunker != NULL);
2009     dumper = chunker->dumper;
2010     assert(dumper != NULL);
2011     dp = dumper->dp;
2012     assert(dp != NULL);
2013     assert(sched(dp) != NULL);
2014     assert(sched(dp)->destname != NULL);
2015     assert(dp != NULL && sched(dp) != NULL && sched(dp)->destname);
2016
2017     if(sched(dp)->holdp) {
2018         h = sched(dp)->holdp;
2019         activehd = sched(dp)->activehd;
2020     }
2021
2022     do {
2023         short_dump_state();
2024
2025         cmd = getresult(chunker->fd, 1, &result_argc, &result_argv);
2026
2027         if(cmd != BOGUS) {
2028             /* result_argv[1] always contains the serial number */
2029             sdp = serial2disk(result_argv[1]);
2030             if (sdp != dp) {
2031                 error(_("Invalid serial number %s"), result_argv[1]);
2032                 g_assert_not_reached();
2033             }
2034         }
2035
2036         switch(cmd) {
2037
2038         case PARTIAL: /* PARTIAL <handle> <dumpsize> <errstr> */
2039         case DONE: /* DONE <handle> <dumpsize> <errstr> */
2040             if(result_argc != 4) {
2041                 error(_("error [chunker %s result_argc != 4: %d]"), cmdstr[cmd],
2042                       result_argc);
2043                 /*NOTREACHED*/
2044             }
2045             /*free_serial(result_argv[1]);*/
2046
2047             sched(dp)->dumpsize = (off_t)atof(result_argv[2]);
2048
2049             qname = quote_string(dp->name);
2050             g_printf(_("driver: finished-cmd time %s %s chunked %s:%s\n"),
2051                    walltime_str(curclock()), chunker->name,
2052                    dp->host->hostname, qname);
2053             fflush(stdout);
2054             amfree(qname);
2055
2056             event_release(chunker->ev_read);
2057
2058             chunker->result = cmd;
2059
2060             break;
2061
2062         case TRYAGAIN: /* TRY-AGAIN <handle> <errstr> */
2063             event_release(chunker->ev_read);
2064
2065             chunker->result = cmd;
2066
2067             break;
2068         case FAILED: /* FAILED <handle> <errstr> */
2069             /*free_serial(result_argv[1]);*/
2070
2071             event_release(chunker->ev_read);
2072
2073             chunker->result = cmd;
2074
2075             break;
2076
2077         case NO_ROOM: /* NO-ROOM <handle> <missing_size> */
2078             if (!h || activehd < 0) { /* should never happen */
2079                 error(_("!h || activehd < 0"));
2080                 /*NOTREACHED*/
2081             }
2082             h[activehd]->used -= OFF_T_ATOI(result_argv[2]);
2083             h[activehd]->reserved -= OFF_T_ATOI(result_argv[2]);
2084             h[activehd]->disk->allocated_space -= OFF_T_ATOI(result_argv[2]);
2085             h[activehd]->disk->disksize -= OFF_T_ATOI(result_argv[2]);
2086             break;
2087
2088         case RQ_MORE_DISK: /* RQ-MORE-DISK <handle> */
2089             if (!h || activehd < 0) { /* should never happen */
2090                 error(_("!h || activehd < 0"));
2091                 /*NOTREACHED*/
2092             }
2093             h[activehd]->disk->allocated_dumpers--;
2094             h[activehd]->used = h[activehd]->reserved;
2095             if( h[++activehd] ) { /* There's still some allocated space left.
2096                                    * Tell the dumper about it. */
2097                 sched(dp)->activehd++;
2098                 chunker_cmd( chunker, CONTINUE, dp, NULL );
2099             } else { /* !h[++activehd] - must allocate more space */
2100                 sched(dp)->act_size = sched(dp)->est_size; /* not quite true */
2101                 sched(dp)->est_size = (sched(dp)->act_size/(off_t)20) * (off_t)21; /* +5% */
2102                 sched(dp)->est_size = am_round(sched(dp)->est_size, (off_t)DISK_BLOCK_KB);
2103                 if (sched(dp)->est_size < sched(dp)->act_size + 2*DISK_BLOCK_KB)
2104                     sched(dp)->est_size += 2 * DISK_BLOCK_KB;
2105                 h = find_diskspace( sched(dp)->est_size - sched(dp)->act_size,
2106                                     &dummy,
2107                                     h[activehd-1] );
2108                 if( !h ) {
2109                     /* No diskspace available. The reason for this will be
2110                      * determined in continue_port_dumps(). */
2111                     enqueue_disk( &roomq, dp );
2112                     continue_port_dumps();
2113                 } else {
2114                     /* OK, allocate space for disk and have chunker continue */
2115                     sched(dp)->activehd = assign_holdingdisk( h, dp );
2116                     chunker_cmd( chunker, CONTINUE, dp, NULL );
2117                     amfree(h);
2118                 }
2119             }
2120             break;
2121
2122         case ABORT_FINISHED: /* ABORT-FINISHED <handle> */
2123             /*
2124              * We sent an ABORT from the NO-ROOM case because this dump
2125              * wasn't going to fit onto the holding disk.  We now need to
2126              * clean up the remains of this image, and try to finish
2127              * other dumps that are waiting on disk space.
2128              */
2129             /*assert(pending_aborts);*/
2130
2131             /*free_serial(result_argv[1]);*/
2132
2133             event_release(chunker->ev_read);
2134
2135             chunker->result = cmd;
2136
2137             break;
2138
2139         case BOGUS:
2140             /* either EOF or garbage from chunker.  Turn it off */
2141             log_add(L_WARNING, _("%s pid %ld is messed up, ignoring it.\n"),
2142                     chunker->name, (long)chunker->pid);
2143
2144             /* if it was dumping something, zap it and try again */
2145             g_assert(h && activehd >= 0);
2146             qname = quote_string(dp->name);
2147             if(sched(dp)->dump_attempted) {
2148                 log_add(L_FAIL, _("%s %s %s %d [%s died]"),
2149                         dp->host->hostname, qname, sched(dp)->datestamp,
2150                         sched(dp)->level, chunker->name);
2151             } else {
2152                 log_add(L_WARNING, _("%s died while dumping %s:%s lev %d."),
2153                         chunker->name, dp->host->hostname, qname,
2154                         sched(dp)->level);
2155             }
2156             amfree(qname);
2157             dp = NULL;
2158
2159             event_release(chunker->ev_read);
2160
2161             chunker->result = cmd;
2162
2163             break;
2164
2165         default:
2166             assert(0);
2167         }
2168         g_strfreev(result_argv);
2169
2170         if(chunker->result != LAST_TOK && chunker->dumper->result != LAST_TOK)
2171             dumper_chunker_result(dp);
2172
2173     } while(areads_dataready(chunker->fd));
2174 }
2175
2176
2177 static disklist_t
2178 read_flush(void)
2179 {
2180     sched_t *sp;
2181     disk_t *dp;
2182     int line;
2183     char *hostname, *diskname, *datestamp;
2184     int level;
2185     char *destname;
2186     disk_t *dp1;
2187     char *inpline = NULL;
2188     char *command;
2189     char *s;
2190     int ch;
2191     disklist_t tq;
2192     char *qname = NULL;
2193     char *qdestname = NULL;
2194
2195     tq.head = tq.tail = NULL;
2196
2197     for(line = 0; (inpline = agets(stdin)) != NULL; free(inpline)) {
2198         dumpfile_t file;
2199
2200         line++;
2201         if (inpline[0] == '\0')
2202             continue;
2203
2204         s = inpline;
2205         ch = *s++;
2206
2207         skip_whitespace(s, ch);                 /* find the command */
2208         if(ch == '\0') {
2209             error(_("flush line %d: syntax error (no command)"), line);
2210             /*NOTREACHED*/
2211         }
2212         command = s - 1;
2213         skip_non_whitespace(s, ch);
2214         s[-1] = '\0';
2215
2216         if(strcmp(command,"ENDFLUSH") == 0) {
2217             break;
2218         }
2219
2220         if(strcmp(command,"FLUSH") != 0) {
2221             error(_("flush line %d: syntax error (%s != FLUSH)"), line, command);
2222             /*NOTREACHED*/
2223         }
2224
2225         skip_whitespace(s, ch);                 /* find the hostname */
2226         if(ch == '\0') {
2227             error(_("flush line %d: syntax error (no hostname)"), line);
2228             /*NOTREACHED*/
2229         }
2230         hostname = s - 1;
2231         skip_non_whitespace(s, ch);
2232         s[-1] = '\0';
2233
2234         skip_whitespace(s, ch);                 /* find the diskname */
2235         if(ch == '\0') {
2236             error(_("flush line %d: syntax error (no diskname)"), line);
2237             /*NOTREACHED*/
2238         }
2239         qname = s - 1;
2240         skip_quoted_string(s, ch);
2241         s[-1] = '\0';                           /* terminate the disk name */
2242         diskname = unquote_string(qname);
2243
2244         skip_whitespace(s, ch);                 /* find the datestamp */
2245         if(ch == '\0') {
2246             error(_("flush line %d: syntax error (no datestamp)"), line);
2247             /*NOTREACHED*/
2248         }
2249         datestamp = s - 1;
2250         skip_non_whitespace(s, ch);
2251         s[-1] = '\0';
2252
2253         skip_whitespace(s, ch);                 /* find the level number */
2254         if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
2255             error(_("flush line %d: syntax error (bad level)"), line);
2256             /*NOTREACHED*/
2257         }
2258         skip_integer(s, ch);
2259
2260         skip_whitespace(s, ch);                 /* find the filename */
2261         if(ch == '\0') {
2262             error(_("flush line %d: syntax error (no filename)"), line);
2263             /*NOTREACHED*/
2264         }
2265         qdestname = s - 1;
2266         skip_quoted_string(s, ch);
2267         s[-1] = '\0';
2268         destname = unquote_string(qdestname);
2269
2270         holding_file_get_dumpfile(destname, &file);
2271         if( file.type != F_DUMPFILE) {
2272             if( file.type != F_CONT_DUMPFILE )
2273                 log_add(L_INFO, _("%s: ignoring cruft file."), destname);
2274             amfree(diskname);
2275             amfree(destname);
2276             dumpfile_free_data(&file);
2277             continue;
2278         }
2279
2280         if(strcmp(hostname, file.name) != 0 ||
2281            strcmp(diskname, file.disk) != 0 ||
2282            strcmp(datestamp, file.datestamp) != 0) {
2283             log_add(L_INFO, _("disk %s:%s not consistent with file %s"),
2284                     hostname, diskname, destname);
2285             amfree(diskname);
2286             amfree(destname);
2287             dumpfile_free_data(&file);
2288             continue;
2289         }
2290         amfree(diskname);
2291
2292         dp = lookup_disk(file.name, file.disk);
2293
2294         if (dp == NULL) {
2295             log_add(L_INFO, _("%s: disk %s:%s not in database, skipping it."),
2296                     destname, file.name, file.disk);
2297             amfree(destname);
2298             dumpfile_free_data(&file);
2299             continue;
2300         }
2301
2302         if(file.dumplevel < 0 || file.dumplevel > 9) {
2303             log_add(L_INFO, _("%s: ignoring file with bogus dump level %d."),
2304                     destname, file.dumplevel);
2305             amfree(destname);
2306             dumpfile_free_data(&file);
2307             continue;
2308         }
2309
2310         if (holding_file_size(destname,1) <= 0) {
2311             log_add(L_INFO, "%s: removing file with no data.", destname);
2312             holding_file_unlink(destname);
2313             amfree(destname);
2314             dumpfile_free_data(&file);
2315             continue;
2316         }
2317
2318         dp1 = (disk_t *)alloc(SIZEOF(disk_t));
2319         *dp1 = *dp;
2320         dp1->next = dp1->prev = NULL;
2321
2322         /* add it to the flushhost list */
2323         if(!flushhost) {
2324             flushhost = alloc(SIZEOF(am_host_t));
2325             flushhost->next = NULL;
2326             flushhost->hostname = stralloc("FLUSHHOST");
2327             flushhost->up = NULL;
2328             flushhost->features = NULL;
2329         }
2330         dp1->hostnext = flushhost->disks;
2331         flushhost->disks = dp1;
2332
2333         sp = (sched_t *) alloc(SIZEOF(sched_t));
2334         sp->destname = destname;
2335         sp->level = file.dumplevel;
2336         sp->dumpdate = NULL;
2337         sp->degr_dumpdate = NULL;
2338         sp->degr_mesg = NULL;
2339         sp->datestamp = stralloc(file.datestamp);
2340         sp->est_nsize = (off_t)0;
2341         sp->est_csize = (off_t)0;
2342         sp->est_time = 0;
2343         sp->est_kps = 10;
2344         sp->priority = 0;
2345         sp->degr_level = -1;
2346         sp->dump_attempted = 0;
2347         sp->taper_attempted = 0;
2348         sp->act_size = holding_file_size(destname, 0);
2349         sp->holdp = build_diskspace(destname);
2350         if(sp->holdp == NULL) continue;
2351         sp->dumper = NULL;
2352         sp->timestamp = (time_t)0;
2353
2354         dp1->up = (char *)sp;
2355
2356         enqueue_disk(&tq, dp1);
2357         dumpfile_free_data(&file);
2358     }
2359     amfree(inpline);
2360
2361     /*@i@*/ return tq;
2362 }
2363
2364 static void
2365 read_schedule(
2366     void *      cookie)
2367 {
2368     sched_t *sp;
2369     disk_t *dp;
2370     int level, line, priority;
2371     char *dumpdate, *degr_dumpdate, *degr_mesg;
2372     int degr_level;
2373     time_t time, degr_time;
2374     time_t *time_p = &time;
2375     time_t *degr_time_p = &degr_time;
2376     off_t nsize, csize, degr_nsize, degr_csize;
2377     unsigned long kps, degr_kps;
2378     char *hostname, *features, *diskname, *datestamp, *inpline = NULL;
2379     char *command;
2380     char *s;
2381     int ch;
2382     off_t flush_size = (off_t)0;
2383     char *qname = NULL;
2384     long long time_;
2385     long long nsize_;
2386     long long csize_;
2387     long long degr_nsize_;
2388     long long degr_csize_;
2389
2390     (void)cookie;       /* Quiet unused parameter warning */
2391
2392     event_release(schedule_ev_read);
2393
2394     /* read schedule from stdin */
2395
2396     for(line = 0; (inpline = agets(stdin)) != NULL; free(inpline)) {
2397         if (inpline[0] == '\0')
2398             continue;
2399         line++;
2400
2401         s = inpline;
2402         ch = *s++;
2403
2404         skip_whitespace(s, ch);                 /* find the command */
2405         if(ch == '\0') {
2406             error(_("schedule line %d: syntax error (no command)"), line);
2407             /*NOTREACHED*/
2408         }
2409         command = s - 1;
2410         skip_non_whitespace(s, ch);
2411         s[-1] = '\0';
2412
2413         if(strcmp(command,"DUMP") != 0) {
2414             error(_("schedule line %d: syntax error (%s != DUMP)"), line, command);
2415             /*NOTREACHED*/
2416         }
2417
2418         skip_whitespace(s, ch);                 /* find the host name */
2419         if(ch == '\0') {
2420             error(_("schedule line %d: syntax error (no host name)"), line);
2421             /*NOTREACHED*/
2422         }
2423         hostname = s - 1;
2424         skip_non_whitespace(s, ch);
2425         s[-1] = '\0';
2426
2427         skip_whitespace(s, ch);                 /* find the feature list */
2428         if(ch == '\0') {
2429             error(_("schedule line %d: syntax error (no feature list)"), line);
2430             /*NOTREACHED*/
2431         }
2432         features = s - 1;
2433         skip_non_whitespace(s, ch);
2434         s[-1] = '\0';
2435
2436         skip_whitespace(s, ch);                 /* find the disk name */
2437         if(ch == '\0') {
2438             error(_("schedule line %d: syntax error (no disk name)"), line);
2439             /*NOTREACHED*/
2440         }
2441         qname = s - 1;
2442         skip_quoted_string(s, ch);
2443         s[-1] = '\0';                           /* terminate the disk name */
2444         diskname = unquote_string(qname);
2445
2446         skip_whitespace(s, ch);                 /* find the datestamp */
2447         if(ch == '\0') {
2448             error(_("schedule line %d: syntax error (no datestamp)"), line);
2449             /*NOTREACHED*/
2450         }
2451         datestamp = s - 1;
2452         skip_non_whitespace(s, ch);
2453         s[-1] = '\0';
2454
2455         skip_whitespace(s, ch);                 /* find the priority number */
2456         if(ch == '\0' || sscanf(s - 1, "%d", &priority) != 1) {
2457             error(_("schedule line %d: syntax error (bad priority)"), line);
2458             /*NOTREACHED*/
2459         }
2460         skip_integer(s, ch);
2461
2462         skip_whitespace(s, ch);                 /* find the level number */
2463         if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
2464             error(_("schedule line %d: syntax error (bad level)"), line);
2465             /*NOTREACHED*/
2466         }
2467         skip_integer(s, ch);
2468
2469         skip_whitespace(s, ch);                 /* find the dump date */
2470         if(ch == '\0') {
2471             error(_("schedule line %d: syntax error (bad dump date)"), line);
2472             /*NOTREACHED*/
2473         }
2474         dumpdate = s - 1;
2475         skip_non_whitespace(s, ch);
2476         s[-1] = '\0';
2477
2478         skip_whitespace(s, ch);                 /* find the native size */
2479         nsize_ = (off_t)0;
2480         if(ch == '\0' || sscanf(s - 1, "%lld", &nsize_) != 1) {
2481             error(_("schedule line %d: syntax error (bad nsize)"), line);
2482             /*NOTREACHED*/
2483         }
2484         nsize = (off_t)nsize_;
2485         skip_integer(s, ch);
2486
2487         skip_whitespace(s, ch);                 /* find the compressed size */
2488         csize_ = (off_t)0;
2489         if(ch == '\0' || sscanf(s - 1, "%lld", &csize_) != 1) {
2490             error(_("schedule line %d: syntax error (bad csize)"), line);
2491             /*NOTREACHED*/
2492         }
2493         csize = (off_t)csize_;
2494         skip_integer(s, ch);
2495
2496         skip_whitespace(s, ch);                 /* find the time number */
2497         if(ch == '\0' || sscanf(s - 1, "%lld", &time_) != 1) {
2498             error(_("schedule line %d: syntax error (bad estimated time)"), line);
2499             /*NOTREACHED*/
2500         }
2501         *time_p = (time_t)time_;
2502         skip_integer(s, ch);
2503
2504         skip_whitespace(s, ch);                 /* find the kps number */
2505         if(ch == '\0' || sscanf(s - 1, "%lu", &kps) != 1) {
2506             error(_("schedule line %d: syntax error (bad kps)"), line);
2507             continue;
2508         }
2509         skip_integer(s, ch);
2510
2511         degr_dumpdate = NULL;                   /* flag if degr fields found */
2512         skip_whitespace(s, ch);                 /* find the degr level number */
2513         degr_mesg = NULL;
2514         if (ch == '"') {
2515             qname = s - 1;
2516             skip_quoted_string(s, ch);
2517             s[-1] = '\0';                       /* terminate degr mesg */
2518             degr_mesg = unquote_string(qname);
2519             degr_level = -1;
2520             degr_nsize = (off_t)0;
2521             degr_csize = (off_t)0;
2522             degr_time = (time_t)0;
2523             degr_kps = 0;
2524         } else if (ch != '\0') {
2525             if(sscanf(s - 1, "%d", &degr_level) != 1) {
2526                 error(_("schedule line %d: syntax error (bad degr level)"), line);
2527                 /*NOTREACHED*/
2528             }
2529             skip_integer(s, ch);
2530
2531             skip_whitespace(s, ch);             /* find the degr dump date */
2532             if(ch == '\0') {
2533                 error(_("schedule line %d: syntax error (bad degr dump date)"), line);
2534                 /*NOTREACHED*/
2535             }
2536             degr_dumpdate = s - 1;
2537             skip_non_whitespace(s, ch);
2538             s[-1] = '\0';
2539
2540             skip_whitespace(s, ch);             /* find the degr native size */
2541             degr_nsize_ = (off_t)0;
2542             if(ch == '\0'  || sscanf(s - 1, "%lld", &degr_nsize_) != 1) {
2543                 error(_("schedule line %d: syntax error (bad degr nsize)"), line);
2544                 /*NOTREACHED*/
2545             }
2546             degr_nsize = (off_t)degr_nsize_;
2547             skip_integer(s, ch);
2548
2549             skip_whitespace(s, ch);             /* find the degr compressed size */
2550             degr_csize_ = (off_t)0;
2551             if(ch == '\0'  || sscanf(s - 1, "%lld", &degr_csize_) != 1) {
2552                 error(_("schedule line %d: syntax error (bad degr csize)"), line);
2553                 /*NOTREACHED*/
2554             }
2555             degr_csize = (off_t)degr_csize_;
2556             skip_integer(s, ch);
2557
2558             skip_whitespace(s, ch);             /* find the degr time number */
2559             if(ch == '\0' || sscanf(s - 1, "%lld", &time_) != 1) {
2560                 error(_("schedule line %d: syntax error (bad degr estimated time)"), line);
2561                 /*NOTREACHED*/
2562             }
2563             *degr_time_p = (time_t)time_;
2564             skip_integer(s, ch);
2565
2566             skip_whitespace(s, ch);             /* find the degr kps number */
2567             if(ch == '\0' || sscanf(s - 1, "%lu", &degr_kps) != 1) {
2568                 error(_("schedule line %d: syntax error (bad degr kps)"), line);
2569                 /*NOTREACHED*/
2570             }
2571             skip_integer(s, ch);
2572         } else {
2573             error(_("schedule line %d: no degraded estimate or message"), line);
2574         }
2575
2576         dp = lookup_disk(hostname, diskname);
2577         if(dp == NULL) {
2578             log_add(L_WARNING,
2579                     _("schedule line %d: %s:'%s' not in disklist, ignored"),
2580                     line, hostname, qname);
2581             amfree(diskname);
2582             continue;
2583         }
2584
2585         sp = (sched_t *) alloc(SIZEOF(sched_t));
2586         /*@ignore@*/
2587         sp->level = level;
2588         sp->dumpdate = stralloc(dumpdate);
2589         sp->est_nsize = DISK_BLOCK_KB + nsize; /* include header */
2590         sp->est_csize = DISK_BLOCK_KB + csize; /* include header */
2591         /* round estimate to next multiple of DISK_BLOCK_KB */
2592         sp->est_csize = am_round(sp->est_csize, DISK_BLOCK_KB);
2593         sp->est_size = sp->est_csize;
2594         sp->est_time = time;
2595         sp->est_kps = kps;
2596         sp->priority = priority;
2597         sp->datestamp = stralloc(datestamp);
2598
2599         if(degr_dumpdate) {
2600             sp->degr_level = degr_level;
2601             sp->degr_dumpdate = stralloc(degr_dumpdate);
2602             sp->degr_nsize = DISK_BLOCK_KB + degr_nsize;
2603             sp->degr_csize = DISK_BLOCK_KB + degr_csize;
2604             /* round estimate to next multiple of DISK_BLOCK_KB */
2605             sp->degr_csize = am_round(sp->degr_csize, DISK_BLOCK_KB);
2606             sp->degr_time = degr_time;
2607             sp->degr_kps = degr_kps;
2608             sp->degr_mesg = NULL;
2609         } else {
2610             sp->degr_level = -1;
2611             sp->degr_dumpdate = NULL;
2612             sp->degr_mesg = degr_mesg;
2613         }
2614         /*@end@*/
2615
2616         sp->dump_attempted = 0;
2617         sp->taper_attempted = 0;
2618         sp->act_size = 0;
2619         sp->holdp = NULL;
2620         sp->activehd = -1;
2621         sp->dumper = NULL;
2622         sp->timestamp = (time_t)0;
2623         sp->destname = NULL;
2624         sp->no_space = 0;
2625
2626         dp->up = (char *) sp;
2627         if(dp->host->features == NULL) {
2628             dp->host->features = am_string_to_feature(features);
2629         }
2630         remove_disk(&waitq, dp);
2631         if (dp->to_holdingdisk == HOLD_NEVER) {
2632             enqueue_disk(&directq, dp);
2633         } else {
2634             enqueue_disk(&runq, dp);
2635         }
2636         flush_size += sp->act_size;
2637         amfree(diskname);
2638     }
2639     g_printf(_("driver: flush size %lld\n"), (long long)flush_size);
2640     amfree(inpline);
2641     if(line == 0)
2642         log_add(L_WARNING, _("WARNING: got empty schedule from planner"));
2643     if(need_degraded==1) start_degraded_mode(&runq);
2644     schedule_done = 1;
2645     start_some_dumps(&runq);
2646 }
2647
2648 static unsigned long
2649 free_kps(
2650     netif_t *ip)
2651 {
2652     unsigned long res;
2653
2654     if (ip == NULL) {
2655         netif_t *p;
2656         unsigned long maxusage=0;
2657         unsigned long curusage=0;
2658         for(p = disklist_netifs(); p != NULL; p = p->next) {
2659             maxusage += interface_get_maxusage(p->config);
2660             curusage += p->curusage;
2661         }
2662         if (maxusage >= curusage)
2663             res = maxusage - curusage;
2664         else
2665             res = 0;
2666 #ifndef __lint
2667     } else {
2668         if ((unsigned long)interface_get_maxusage(ip->config) >= ip->curusage)
2669             res = interface_get_maxusage(ip->config) - ip->curusage;
2670         else
2671             res = 0;
2672 #endif
2673     }
2674
2675     return res;
2676 }
2677
2678 static void
2679 interface_state(
2680     char *time_str)
2681 {
2682     netif_t *ip;
2683
2684     g_printf(_("driver: interface-state time %s"), time_str);
2685
2686     for(ip = disklist_netifs(); ip != NULL; ip = ip->next) {
2687         g_printf(_(" if %s: free %lu"), interface_name(ip->config), free_kps(ip));
2688     }
2689     g_printf("\n");
2690 }
2691
2692 static void
2693 allocate_bandwidth(
2694     netif_t *           ip,
2695     unsigned long       kps)
2696 {
2697     ip->curusage += kps;
2698 }
2699
2700 static void
2701 deallocate_bandwidth(
2702     netif_t *           ip,
2703     unsigned long       kps)
2704 {
2705     assert(kps <= ip->curusage);
2706     ip->curusage -= kps;
2707 }
2708
2709 /* ------------ */
2710 static off_t
2711 free_space(void)
2712 {
2713     holdalloc_t *ha;
2714     off_t total_free;
2715     off_t diff;
2716
2717     total_free = (off_t)0;
2718     for(ha = holdalloc; ha != NULL; ha = ha->next) {
2719         diff = ha->disksize - ha->allocated_space;
2720         if(diff > (off_t)0)
2721             total_free += diff;
2722     }
2723     return total_free;
2724 }
2725
2726 /*
2727  * We return an array of pointers to assignedhd_t. The array contains at
2728  * most one entry per holding disk. The list of pointers is terminated by
2729  * a NULL pointer. Each entry contains a pointer to a holdingdisk and
2730  * how much diskspace to use on that disk. Later on, assign_holdingdisk
2731  * will allocate the given amount of space.
2732  * If there is not enough room on the holdingdisks, NULL is returned.
2733  */
2734
2735 static assignedhd_t **
2736 find_diskspace(
2737     off_t               size,
2738     int *               cur_idle,
2739     assignedhd_t *      pref)
2740 {
2741     assignedhd_t **result = NULL;
2742     holdalloc_t *ha, *minp;
2743     int i=0;
2744     int j, minj;
2745     char *used;
2746     off_t halloc, dalloc, hfree, dfree;
2747
2748     (void)cur_idle;     /* Quiet unused parameter warning */
2749
2750     if (size < 2*DISK_BLOCK_KB)
2751         size = 2*DISK_BLOCK_KB;
2752     size = am_round(size, (off_t)DISK_BLOCK_KB);
2753
2754     hold_debug(1, _("find_diskspace: want %lld K\n"),
2755                    (long long)size);
2756
2757     used = alloc(SIZEOF(*used) * num_holdalloc);/*disks used during this run*/
2758     memset( used, 0, (size_t)num_holdalloc );
2759     result = alloc(SIZEOF(assignedhd_t *) * (num_holdalloc + 1));
2760     result[0] = NULL;
2761
2762     while( i < num_holdalloc && size > (off_t)0 ) {
2763         /* find the holdingdisk with the fewest active dumpers and among
2764          * those the one with the biggest free space
2765          */
2766         minp = NULL; minj = -1;
2767         for(j = 0, ha = holdalloc; ha != NULL; ha = ha->next, j++ ) {
2768             if( pref && pref->disk == ha && !used[j] &&
2769                 ha->allocated_space <= ha->disksize - (off_t)DISK_BLOCK_KB) {
2770                 minp = ha;
2771                 minj = j;
2772                 break;
2773             }
2774             else if( ha->allocated_space <= ha->disksize - (off_t)(2*DISK_BLOCK_KB) &&
2775                 !used[j] &&
2776                 (!minp ||
2777                  ha->allocated_dumpers < minp->allocated_dumpers ||
2778                  (ha->allocated_dumpers == minp->allocated_dumpers &&
2779                   ha->disksize-ha->allocated_space > minp->disksize-minp->allocated_space)) ) {
2780                 minp = ha;
2781                 minj = j;
2782             }
2783         }
2784
2785         pref = NULL;
2786         if( !minp ) { break; } /* all holding disks are full */
2787         used[minj] = 1;
2788
2789         /* hfree = free space on the disk */
2790         hfree = minp->disksize - minp->allocated_space;
2791
2792         /* dfree = free space for data, remove 1 header for each chunksize */
2793         dfree = hfree - (((hfree-(off_t)1)/holdingdisk_get_chunksize(minp->hdisk))+(off_t)1) * (off_t)DISK_BLOCK_KB;
2794
2795         /* dalloc = space I can allocate for data */
2796         dalloc = ( dfree < size ) ? dfree : size;
2797
2798         /* halloc = space to allocate, including 1 header for each chunksize */
2799         halloc = dalloc + (((dalloc-(off_t)1)/holdingdisk_get_chunksize(minp->hdisk))+(off_t)1) * (off_t)DISK_BLOCK_KB;
2800
2801         hold_debug(1, _("find_diskspace: find diskspace: size %lld hf %lld df %lld da %lld ha %lld\n"),
2802                        (long long)size,
2803                        (long long)hfree,
2804                        (long long)dfree,
2805                        (long long)dalloc,
2806                        (long long)halloc);
2807         size -= dalloc;
2808         result[i] = alloc(SIZEOF(assignedhd_t));
2809         result[i]->disk = minp;
2810         result[i]->reserved = halloc;
2811         result[i]->used = (off_t)0;
2812         result[i]->destname = NULL;
2813         result[i+1] = NULL;
2814         i++;
2815     }
2816     amfree(used);
2817
2818     if(size != (off_t)0) { /* not enough space available */
2819         g_printf(_("find diskspace: not enough diskspace. Left with %lld K\n"), (long long)size);
2820         fflush(stdout);
2821         free_assignedhd(result);
2822         result = NULL;
2823     }
2824
2825     if (debug_holding > 1) {
2826         for( i = 0; result && result[i]; i++ ) {
2827             hold_debug(1, _("find_diskspace: find diskspace: selected %s free %lld reserved %lld dumpers %d\n"),
2828                            holdingdisk_get_diskdir(result[i]->disk->hdisk),
2829                            (long long)(result[i]->disk->disksize -
2830                              result[i]->disk->allocated_space),
2831                            (long long)result[i]->reserved,
2832                            result[i]->disk->allocated_dumpers);
2833         }
2834     }
2835
2836     return result;
2837 }
2838
2839 static int
2840 assign_holdingdisk(
2841     assignedhd_t **     holdp,
2842     disk_t *            diskp)
2843 {
2844     int i, j, c, l=0;
2845     off_t size;
2846     char *sfn = sanitise_filename(diskp->name);
2847     char lvl[64];
2848     assignedhd_t **new_holdp;
2849     char *qname;
2850
2851     g_snprintf( lvl, SIZEOF(lvl), "%d", sched(diskp)->level );
2852
2853     size = am_round(sched(diskp)->est_size - sched(diskp)->act_size,
2854                     (off_t)DISK_BLOCK_KB);
2855
2856     for( c = 0; holdp[c]; c++ )
2857         (void)c; /* count number of disks */
2858
2859     /* allocate memory for sched(diskp)->holdp */
2860     for(j = 0; sched(diskp)->holdp && sched(diskp)->holdp[j]; j++)
2861         (void)j;        /* Quiet lint */
2862     new_holdp = (assignedhd_t **)alloc(SIZEOF(assignedhd_t*)*(j+c+1));
2863     if (sched(diskp)->holdp) {
2864         memcpy(new_holdp, sched(diskp)->holdp, j * SIZEOF(*new_holdp));
2865         amfree(sched(diskp)->holdp);
2866     }
2867     sched(diskp)->holdp = new_holdp;
2868     new_holdp = NULL;
2869
2870     i = 0;
2871     if( j > 0 ) { /* This is a request for additional diskspace. See if we can
2872                    * merge assignedhd_t's */
2873         l=j;
2874         if( sched(diskp)->holdp[j-1]->disk == holdp[0]->disk ) { /* Yes! */
2875             sched(diskp)->holdp[j-1]->reserved += holdp[0]->reserved;
2876             holdp[0]->disk->allocated_space += holdp[0]->reserved;
2877             size = (holdp[0]->reserved>size) ? (off_t)0 : size-holdp[0]->reserved;
2878             qname = quote_string(diskp->name);
2879             hold_debug(1, _("assign_holdingdisk: merging holding disk %s to disk %s:%s, add %lld for reserved %lld, left %lld\n"),
2880                            holdingdisk_get_diskdir(
2881                                                sched(diskp)->holdp[j-1]->disk->hdisk),
2882                            diskp->host->hostname, qname,
2883                            (long long)holdp[0]->reserved,
2884                            (long long)sched(diskp)->holdp[j-1]->reserved,
2885                            (long long)size);
2886             i++;
2887             amfree(qname);
2888             amfree(holdp[0]);
2889             l=j-1;
2890         }
2891     }
2892
2893     /* copy assignedhd_s to sched(diskp), adjust allocated_space */
2894     for( ; holdp[i]; i++ ) {
2895         holdp[i]->destname = newvstralloc( holdp[i]->destname,
2896                                            holdingdisk_get_diskdir(holdp[i]->disk->hdisk), "/",
2897                                            hd_driver_timestamp, "/",
2898                                            diskp->host->hostname, ".",
2899                                            sfn, ".",
2900                                            lvl, NULL );
2901         sched(diskp)->holdp[j++] = holdp[i];
2902         holdp[i]->disk->allocated_space += holdp[i]->reserved;
2903         size = (holdp[i]->reserved > size) ? (off_t)0 :
2904                   (size - holdp[i]->reserved);
2905         qname = quote_string(diskp->name);
2906         hold_debug(1,
2907                    _("assign_holdingdisk: %d assigning holding disk %s to disk %s:%s, reserved %lld, left %lld\n"),
2908                     i, holdingdisk_get_diskdir(holdp[i]->disk->hdisk),
2909                     diskp->host->hostname, qname,
2910                     (long long)holdp[i]->reserved,
2911                     (long long)size);
2912         amfree(qname);
2913         holdp[i] = NULL; /* so it doesn't get free()d... */
2914     }
2915     sched(diskp)->holdp[j] = NULL;
2916     amfree(sfn);
2917
2918     return l;
2919 }
2920
2921 static void
2922 adjust_diskspace(
2923     disk_t *    diskp,
2924     cmd_t       cmd)
2925 {
2926     assignedhd_t **holdp;
2927     off_t total = (off_t)0;
2928     off_t diff;
2929     int i;
2930     char *qname, *hqname, *qdest;
2931
2932     (void)cmd;  /* Quiet unused parameter warning */
2933
2934     qname = quote_string(diskp->name);
2935     qdest = quote_string(sched(diskp)->destname);
2936     hold_debug(1, _("adjust_diskspace: %s:%s %s\n"),
2937                    diskp->host->hostname, qname, qdest);
2938
2939     holdp = sched(diskp)->holdp;
2940
2941     assert(holdp != NULL);
2942
2943     for( i = 0; holdp[i]; i++ ) { /* for each allocated disk */
2944         diff = holdp[i]->used - holdp[i]->reserved;
2945         total += holdp[i]->used;
2946         holdp[i]->disk->allocated_space += diff;
2947         hqname = quote_string(holdingdisk_name(holdp[i]->disk->hdisk));
2948         hold_debug(1, _("adjust_diskspace: hdisk %s done, reserved %lld used %lld diff %lld alloc %lld dumpers %d\n"),
2949                        holdingdisk_name(holdp[i]->disk->hdisk),
2950                        (long long)holdp[i]->reserved,
2951                        (long long)holdp[i]->used,
2952                        (long long)diff,
2953                        (long long)holdp[i]->disk->allocated_space,
2954                        holdp[i]->disk->allocated_dumpers );
2955         holdp[i]->reserved += diff;
2956         amfree(hqname);
2957     }
2958
2959     sched(diskp)->act_size = total;
2960
2961     hold_debug(1, _("adjust_diskspace: after: disk %s:%s used %lld\n"),
2962                    diskp->host->hostname, qname,
2963                    (long long)sched(diskp)->act_size);
2964     amfree(qdest);
2965     amfree(qname);
2966 }
2967
2968 static void
2969 delete_diskspace(
2970     disk_t *diskp)
2971 {
2972     assignedhd_t **holdp;
2973     int i;
2974
2975     holdp = sched(diskp)->holdp;
2976
2977     assert(holdp != NULL);
2978
2979     for( i = 0; holdp[i]; i++ ) { /* for each disk */
2980         /* find all files of this dump on that disk, and subtract their
2981          * reserved sizes from the disk's allocated space
2982          */
2983         holdp[i]->disk->allocated_space -= holdp[i]->used;
2984     }
2985
2986     holding_file_unlink(holdp[0]->destname);    /* no need for the entire list,
2987                                                  * because holding_file_unlink
2988                                                  * will walk through all files
2989                                                  * using cont_filename */
2990     free_assignedhd(sched(diskp)->holdp);
2991     sched(diskp)->holdp = NULL;
2992     sched(diskp)->act_size = (off_t)0;
2993 }
2994
2995 static assignedhd_t **
2996 build_diskspace(
2997     char *      destname)
2998 {
2999     int i, j;
3000     int fd;
3001     size_t buflen;
3002     char buffer[DISK_BLOCK_BYTES];
3003     dumpfile_t file;
3004     assignedhd_t **result;
3005     holdalloc_t *ha;
3006     off_t *used;
3007     char dirname[1000], *ch;
3008     struct stat finfo;
3009     char *filename = destname;
3010
3011     memset(buffer, 0, sizeof(buffer));
3012     used = alloc(SIZEOF(off_t) * num_holdalloc);
3013     for(i=0;i<num_holdalloc;i++)
3014         used[i] = (off_t)0;
3015     result = alloc(SIZEOF(assignedhd_t *) * (num_holdalloc + 1));
3016     result[0] = NULL;
3017     while(filename != NULL && filename[0] != '\0') {
3018         strncpy(dirname, filename, 999);
3019         dirname[999]='\0';
3020         ch = strrchr(dirname,'/');
3021         if (ch) {
3022             *ch = '\0';
3023             ch = strrchr(dirname,'/');
3024             if (ch) {
3025                 *ch = '\0';
3026             }
3027         }
3028
3029         if (!ch) {
3030             g_fprintf(stderr,_("build_diskspace: bogus filename '%s'\n"), filename);
3031             amfree(used);
3032             amfree(result);
3033             return NULL;
3034         }
3035
3036         for(j = 0, ha = holdalloc; ha != NULL; ha = ha->next, j++ ) {
3037             if(strcmp(dirname, holdingdisk_get_diskdir(ha->hdisk))==0) {
3038                 break;
3039             }
3040         }
3041
3042         if(stat(filename, &finfo) == -1) {
3043             g_fprintf(stderr, _("stat %s: %s\n"), filename, strerror(errno));
3044             finfo.st_size = (off_t)0;
3045         }
3046         used[j] += ((off_t)finfo.st_size+(off_t)1023)/(off_t)1024;
3047         if((fd = open(filename,O_RDONLY)) == -1) {
3048             g_fprintf(stderr,_("build_diskspace: open of %s failed: %s\n"),
3049                     filename, strerror(errno));
3050             amfree(used);
3051             amfree(result);
3052             return NULL;
3053         }
3054         if ((buflen = full_read(fd, buffer, SIZEOF(buffer))) > 0) {;
3055                 parse_file_header(buffer, &file, buflen);
3056         }
3057         close(fd);
3058         filename = file.cont_filename;
3059     }
3060
3061     for(j = 0, i=0, ha = holdalloc; ha != NULL; ha = ha->next, j++ ) {
3062         if(used[j] != (off_t)0) {
3063             result[i] = alloc(SIZEOF(assignedhd_t));
3064             result[i]->disk = ha;
3065             result[i]->reserved = used[j];
3066             result[i]->used = used[j];
3067             result[i]->destname = stralloc(destname);
3068             result[i+1] = NULL;
3069             i++;
3070         }
3071     }
3072
3073     amfree(used);
3074     return result;
3075 }
3076
3077 static void
3078 holdingdisk_state(
3079     char *      time_str)
3080 {
3081     holdalloc_t *ha;
3082     int dsk;
3083     off_t diff;
3084
3085     g_printf(_("driver: hdisk-state time %s"), time_str);
3086
3087     for(ha = holdalloc, dsk = 0; ha != NULL; ha = ha->next, dsk++) {
3088         diff = ha->disksize - ha->allocated_space;
3089         g_printf(_(" hdisk %d: free %lld dumpers %d"), dsk,
3090                (long long)diff, ha->allocated_dumpers);
3091     }
3092     g_printf("\n");
3093 }
3094
3095 static void
3096 update_failed_dump_to_tape(
3097     disk_t *    dp)
3098 {
3099 /* JLM
3100  * should simply set no_bump
3101  */
3102
3103     time_t save_timestamp = sched(dp)->timestamp;
3104     /* setting timestamp to 0 removes the current level from the
3105      * database, so that we ensure that it will not be bumped to the
3106      * next level on the next run.  If we didn't do this, dumpdates or
3107      * gnutar-lists might have been updated already, and a bumped
3108      * incremental might be created.  */
3109     sched(dp)->timestamp = 0;
3110     update_info_dumper(dp, (off_t)-1, (off_t)-1, (time_t)-1);
3111     sched(dp)->timestamp = save_timestamp;
3112 }
3113
3114 /* ------------------- */
3115 static void
3116 dump_to_tape(
3117     disk_t *    dp)
3118 {
3119     dumper_t *dumper;
3120     cmd_t cmd;
3121     int result_argc;
3122     char **result_argv;
3123     char *qname;
3124     disk_t *dp1;
3125
3126     qname = quote_string(dp->name);
3127     g_printf(_("driver: dumping %s:%s directly to tape\n"),
3128            dp->host->hostname, qname);
3129     fflush(stdout);
3130
3131     /* pick a dumper and fail if there are no idle dumpers */
3132
3133     dumper = idle_dumper();
3134     if (!dumper) {
3135         g_printf(_("driver: no idle dumpers for %s:%s.\n"), 
3136                 dp->host->hostname, qname);
3137         fflush(stdout);
3138         log_add(L_WARNING, _("no idle dumpers for %s:%s.\n"),
3139                 dp->host->hostname, qname);
3140         amfree(qname);
3141         return; /* fatal problem */
3142     }
3143
3144     /* tell the taper to read from a port number of its choice */
3145
3146     taper_cmd(PORT_WRITE, dp, NULL, sched(dp)->level, sched(dp)->datestamp);
3147     cmd = getresult(taper, 1, &result_argc, &result_argv);
3148     if(cmd != PORT) {
3149         g_printf(_("driver: did not get PORT from taper for %s:%s\n"),
3150                 dp->host->hostname, qname);
3151         fflush(stdout);
3152         log_add(L_WARNING, _("driver: did not get PORT from taper for %s:%s.\n"),
3153                 dp->host->hostname, qname);
3154         amfree(qname);
3155         return; /* fatal problem */
3156     }
3157     amfree(qname);
3158
3159     /* copy port number */
3160     dumper->output_port = atoi(result_argv[1]);
3161
3162     dumper->dp = dp;
3163     dumper->chunker = NULL;
3164     dumper->result = LAST_TOK;
3165     taper_result = LAST_TOK;
3166     sched(dp)->dumper = dumper;
3167
3168     if (dp->host->pre_script == 0) {
3169         for (dp1=dp->host->disks; dp1 != NULL; dp1 = dp1->hostnext) {
3170             run_server_scripts(EXECUTE_ON_PRE_HOST_BACKUP,
3171                                get_config_name(), dp1, -1);
3172         }
3173         dp->host->pre_script = 1;
3174     }
3175     run_server_scripts(EXECUTE_ON_PRE_DLE_BACKUP, get_config_name(), dp,
3176                        sched(dp)->level);
3177
3178     /* tell the dumper to dump to a port */
3179     dumper_cmd(dumper, PORT_DUMP, dp, NULL);
3180     dp->host->start_t = time(NULL) + 15;
3181
3182     /* update statistics & print state */
3183
3184     taper_busy = dumper->busy = 1;
3185     taper_input_error = NULL;
3186     taper_tape_error = NULL;
3187     taper_dumper = dumper;
3188     taper_disk = dp;
3189     taper_first_label = NULL;
3190     taper_written = 0;
3191     taper_state |= TAPER_STATE_DUMP_TO_TAPE;
3192     sched(dp)->act_size = sched(dp)->est_size;
3193     dp->host->inprogress += 1;
3194     dp->inprogress = 1;
3195     sched(dp)->timestamp = time((time_t *)0);
3196     allocate_bandwidth(dp->host->netif, sched(dp)->est_kps);
3197     idle_reason = NOT_IDLE;
3198
3199     short_dump_state();
3200
3201     dumper->ev_read = event_register(dumper->fd, EV_READFD,
3202                                      handle_dumper_result, dumper);
3203     taper_ev_read = event_register(taper, EV_READFD,
3204                                    handle_taper_result, NULL);
3205
3206     g_strfreev(result_argv);
3207 }
3208
3209 static int
3210 queue_length(
3211     disklist_t  q)
3212 {
3213     disk_t *p;
3214     int len;
3215
3216     for(len = 0, p = q.head; p != NULL; len++, p = p->next)
3217         (void)len;      /* Quiet lint */
3218     return len;
3219 }
3220
3221 static void
3222 short_dump_state(void)
3223 {
3224     int i, nidle;
3225     char *wall_time;
3226
3227     wall_time = walltime_str(curclock());
3228
3229     g_printf(_("driver: state time %s "), wall_time);
3230     g_printf(_("free kps: %lu space: %lld taper: "),
3231            free_kps(NULL),
3232            (long long)free_space());
3233     if(degraded_mode) g_printf(_("DOWN"));
3234     else if(!taper_busy) g_printf(_("idle"));
3235     else g_printf(_("writing"));
3236     nidle = 0;
3237     for(i = 0; i < inparallel; i++) if(!dmptable[i].busy) nidle++;
3238     g_printf(_(" idle-dumpers: %d"), nidle);
3239     g_printf(_(" qlen tapeq: %d"), queue_length(tapeq));
3240     g_printf(_(" runq: %d"), queue_length(runq));
3241     g_printf(_(" roomq: %d"), queue_length(roomq));
3242     g_printf(_(" wakeup: %d"), (int)sleep_time);
3243     g_printf(_(" driver-idle: %s\n"), _(idle_strings[idle_reason]));
3244     interface_state(wall_time);
3245     holdingdisk_state(wall_time);
3246     fflush(stdout);
3247 }
3248
3249 static TapeAction tape_action(char **why_no_new_tape)
3250 {
3251     TapeAction result = TAPE_ACTION_NO_ACTION;
3252     dumper_t *dumper;
3253     disk_t   *dp;
3254     off_t dumpers_size;
3255     off_t runq_size;
3256     off_t directq_size;
3257     off_t tapeq_size;
3258     off_t sched_size;
3259     off_t dump_to_disk_size;
3260     int   dump_to_disk_terminated;
3261
3262     dumpers_size = 0;
3263     for(dumper = dmptable; dumper < (dmptable+inparallel); dumper++) {
3264         if (dumper->busy)
3265             dumpers_size += sched(dumper->dp)->est_size;
3266     }
3267     driver_debug(1, _("dumpers_size: %lld\n"), (long long)dumpers_size);
3268
3269     runq_size = 0;
3270     for(dp = runq.head; dp != NULL; dp = dp->next) {
3271         runq_size += sched(dp)->est_size;
3272     }
3273     driver_debug(1, _("runq_size: %lld\n"), (long long)runq_size);
3274
3275     directq_size = 0;
3276     for(dp = directq.head; dp != NULL; dp = dp->next) {
3277         directq_size += sched(dp)->est_size;
3278     }
3279     driver_debug(1, _("directq_size: %lld\n"), (long long)directq_size);
3280
3281     tapeq_size = 0;
3282     for(dp = tapeq.head; dp != NULL; dp = dp->next) {
3283         tapeq_size += sched(dp)->act_size;
3284     }
3285     if (taper_disk) {
3286         tapeq_size += sched(taper_disk)->act_size - taper_written;
3287     }
3288     driver_debug(1, _("tapeq_size: %lld\n"), (long long)tapeq_size);
3289
3290     sched_size = runq_size + tapeq_size + dumpers_size;
3291     driver_debug(1, _("sched_size: %lld\n"), (long long)sched_size);
3292
3293     dump_to_disk_size = dumpers_size + runq_size;
3294     driver_debug(1, _("dump_to_disk_size: %lld\n"), (long long)dump_to_disk_size);
3295
3296     dump_to_disk_terminated = schedule_done && dump_to_disk_size == 0;
3297
3298     // Changing conditionals can produce a driver hang, take care.
3299     // 
3300     // when to start writting to a new tape
3301     if ((taper_state & TAPER_STATE_WAIT_FOR_TAPE) &&
3302         ((taper_state & TAPER_STATE_DUMP_TO_TAPE) ||    // for dump to tape
3303          !empty(directq) ||                             // if a dle is waiting for a dump to tape
3304          !empty(roomq) ||                               // holding disk constraint
3305          idle_reason == IDLE_NO_DISKSPACE ||            // holding disk constraint
3306          (flush_threshold_dumped < tapeq_size &&        // flush-threshold-dumped &&
3307           flush_threshold_scheduled < sched_size) ||    //  flush-threshold-scheduled
3308          (taperflush < tapeq_size &&                    // taperflush
3309           (force_flush == 1 ||                          //  if force_flush
3310            dump_to_disk_terminated))                    //  or all dump to disk terminated
3311         )) {
3312         result |= TAPE_ACTION_NEW_TAPE;
3313     // when to stop using new tape
3314     } else if ((taper_state & TAPER_STATE_WAIT_FOR_TAPE) &&
3315                (taperflush >= tapeq_size &&             // taperflush criteria not meet
3316                 (force_flush == 1 ||                    //  if force_flush
3317                  dump_to_disk_terminated))              //  or all dump to disk terminated
3318               ) {
3319         result |= TAPE_ACTION_NO_NEW_TAPE;
3320         if (flush_threshold_dumped >= tapeq_size) {
3321             *why_no_new_tape = _("flush-threshold-dumped criteria not met");
3322         } else if (flush_threshold_scheduled >= sched_size) {
3323             *why_no_new_tape = _("flush-threshold-scheduled criteria not met");
3324         } else {
3325             *why_no_new_tape = _("taperflush criteria not met");
3326         }
3327     }
3328
3329     // when to start a flush
3330     // We don't start a flush if taper_tape_started == 1 && dump_to_disk_terminated && force_flush == 0,
3331     // it is a criteria need to exit the first event_loop without flushing everything to tape,
3332     // they will be flush in another event_loop.
3333     if (!degraded_mode && !taper_busy && !empty(tapeq) &&
3334         (!((taper_state & TAPER_STATE_TAPE_STARTED) &&
3335             dump_to_disk_terminated && force_flush == 0) ||     // if tape already started and dump to disk not terminated
3336          ((taper_state & TAPER_STATE_TAPE_STARTED) &&
3337           force_flush == 1) ||                                  // if tape already started and force_flush
3338          !empty(roomq) ||                                       // holding disk constraint
3339          idle_reason == IDLE_NO_DISKSPACE ||                    // holding disk constraint
3340          (flush_threshold_dumped < tapeq_size &&                // flush-threshold-dumped &&
3341          flush_threshold_scheduled < sched_size) ||             //  flush-threshold-scheduled
3342          (force_flush == 1 && taperflush < tapeq_size))) {      // taperflush if force_flush
3343         result |= TAPE_ACTION_START_A_FLUSH;
3344     }
3345     return result;
3346 }
3347
3348 #if 0
3349 static void
3350 dump_state(
3351     const char *str)
3352 {
3353     int i;
3354     disk_t *dp;
3355     char *qname;
3356
3357     g_printf("================\n");
3358     g_printf(_("driver state at time %s: %s\n"), walltime_str(curclock()), str);
3359     g_printf(_("free kps: %lu, space: %lld\n"),
3360            free_kps(NULL),
3361            (long long)free_space());
3362     if(degraded_mode) g_printf(_("taper: DOWN\n"));
3363     else if(!taper_busy) g_printf(_("taper: idle\n"));
3364     else g_printf(_("taper: writing %s:%s.%d est size %lld\n"),
3365                 taper_disk->host->hostname, taper_disk->name,
3366                 sched(taper_disk)->level,
3367                 (long long)sched(taper_disk)->est_size);
3368     for(i = 0; i < inparallel; i++) {
3369         dp = dmptable[i].dp;
3370         if(!dmptable[i].busy)
3371           g_printf(_("%s: idle\n"), dmptable[i].name);
3372         else
3373           qname = quote_string(dp->name);
3374           g_printf(_("%s: dumping %s:%s.%d est kps %d size %lld time %lu\n"),
3375                 dmptable[i].name, dp->host->hostname, qname, sched(dp)->level,
3376                 sched(dp)->est_kps, (long long)sched(dp)->est_size, sched(dp)->est_time);
3377           amfree(qname);
3378     }
3379     dump_queue("TAPE", tapeq, 5, stdout);
3380     dump_queue("ROOM", roomq, 5, stdout);
3381     dump_queue("RUN ", runq, 5, stdout);
3382     g_printf("================\n");
3383     fflush(stdout);
3384 }
3385 #endif