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