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