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