X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=server-src%2Fdriverio.c;h=57782754606b943b9410bf5a930cc72ff9329864;hb=c6f0a88c567f8536c498f554285aed1f8150da18;hp=9973d12123c0d42d590bd638034cd893632c9c03;hpb=2df780bff19c457b0debb7adc29972a0bc2a5dc2;p=debian%2Famanda diff --git a/server-src/driverio.c b/server-src/driverio.c index 9973d12..5778275 100644 --- a/server-src/driverio.c +++ b/server-src/driverio.c @@ -25,393 +25,823 @@ * University of Maryland at College Park */ /* - * $Id: driverio.c,v 1.35.2.14.4.2.2.5.2.5 2005/09/12 13:39:55 martinea Exp $ + * $Id: driverio.c,v 1.92 2006/08/24 01:57:16 paddy_s Exp $ * * I/O-related functions for driver program */ #include "amanda.h" +#include "util.h" #include "clock.h" +#include "server_util.h" #include "conffile.h" #include "diskfile.h" #include "infofile.h" #include "logfile.h" -#include "token.h" -#include "server_util.h" +#include "timestamp.h" #define GLOBAL /* the global variables defined here */ #include "driverio.h" -void init_driverio() +int nb_chunker = 0; + +static const char *childstr(int); + +void +init_driverio(void) { dumper_t *dumper; - taper = -1; + taper_fd = -1; for(dumper = dmptable; dumper < dmptable + MAX_DUMPERS; dumper++) { - dumper->outfd = -1; + dumper->fd = -1; } } -void addfd(fd, readset, maxfd) -int fd; -fd_set *readset; -int *maxfd; +static const char * +childstr( + int fd) { - if(fd < 0 || fd >= FD_SETSIZE) { - error("addfd: descriptor %d out of range (0 .. %d)\n", - fd, FD_SETSIZE-1); - } - if(readset != NULL) - FD_SET(fd, readset); - if(maxfd != NULL) - if(fd > *maxfd) *maxfd = fd; -} - -char *childstr(fd) -int fd; -{ - static char *str = NULL; - char fd_str[NUM_STR_SIZE]; + static char buf[NUM_STR_SIZE + 32]; dumper_t *dumper; - if(fd == taper) return "taper"; - - for(dumper = dmptable; dumper < dmptable + MAX_DUMPERS; dumper++) - if(dumper->outfd == fd) return dumper->name; + if (fd == taper_fd) + return ("taper"); - ap_snprintf(fd_str, sizeof(fd_str), "%d", fd); - str = newvstralloc(str, "unknown child (fd ", fd_str, ")", NULL); - return str; + for (dumper = dmptable; dumper < dmptable + MAX_DUMPERS; dumper++) { + if (dumper->fd == fd) + return (dumper->name); + if (dumper->chunker && dumper->chunker->fd == fd) + return (dumper->chunker->name); + } + g_snprintf(buf, SIZEOF(buf), _("unknown child (fd %d)"), fd); + return (buf); } -void startup_tape_process(taper_program) -char *taper_program; +void +startup_tape_process( + char *taper_program, + int taper_parallel_write, + gboolean no_taper) { - int fd[2]; + int fd[2]; + int i; + char **config_options; + taper_t *taper; + + /* always allocate the tapetable */ + tapetable = calloc(sizeof(taper_t), taper_parallel_write+1); + + for (taper = tapetable, i = 0; i < taper_parallel_write; taper++, i++) { + taper->name = g_strdup_printf("worker%d", i); + taper->sendresult = 0; + taper->input_error = NULL; + taper->tape_error = NULL; + taper->result = 0; + taper->dumper = NULL; + taper->disk = NULL; + taper->first_label = NULL; + taper->first_fileno = 0; + taper->state = TAPER_STATE_DEFAULT; + taper->left = 0; + taper->written = 0; + + /* jump right to degraded mode if there's no taper */ + if (no_taper) { + taper->tape_error = g_strdup("no taper started (--no-taper)"); + taper->result = BOGUS; + } + } - if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) - error("taper pipe: %s", strerror(errno)); - if(fd[0] < 0 || fd[0] >= FD_SETSIZE) { - error("taper socketpair 0: descriptor %d out of range (0 .. %d)\n", - fd[0], FD_SETSIZE-1); + /* don't start the taper if we're not supposed to */ + if (no_taper) + return; + + if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) { + error(_("taper pipe: %s"), strerror(errno)); + /*NOTREACHED*/ + } + if(fd[0] < 0 || fd[0] >= (int)FD_SETSIZE) { + error(_("taper socketpair 0: descriptor %d out of range (0 .. %d)\n"), + fd[0], (int)FD_SETSIZE-1); + /*NOTREACHED*/ } - if(fd[1] < 0 || fd[1] >= FD_SETSIZE) { - error("taper socketpair 1: descriptor %d out of range (0 .. %d)\n", - fd[1], FD_SETSIZE-1); + if(fd[1] < 0 || fd[1] >= (int)FD_SETSIZE) { + error(_("taper socketpair 1: descriptor %d out of range (0 .. %d)\n"), + fd[1], (int)FD_SETSIZE-1); + /*NOTREACHED*/ } switch(taper_pid = fork()) { case -1: - error("fork taper: %s", strerror(errno)); + error(_("fork taper: %s"), strerror(errno)); + /*NOTREACHED*/ + case 0: /* child process */ aclose(fd[0]); if(dup2(fd[1], 0) == -1 || dup2(fd[1], 1) == -1) - error("taper dup2: %s", strerror(errno)); - execle(taper_program, "taper", config_name, (char *)0, safe_env()); + error(_("taper dup2: %s"), strerror(errno)); + config_options = get_config_options(2); + config_options[0] = "taper"; + config_options[1] = get_config_name(); + safe_fd(-1, 0); + execve(taper_program, config_options, safe_env()); error("exec %s: %s", taper_program, strerror(errno)); + /*NOTREACHED*/ + default: /* parent process */ aclose(fd[1]); - taper = fd[0]; - addfd(taper, &readset, &maxfd); + taper_fd = fd[0]; + taper_ev_read = NULL; } } -void startup_dump_process(dumper, dumper_program) -dumper_t *dumper; -char *dumper_program; +void +startup_dump_process( + dumper_t *dumper, + char *dumper_program) { - int fd[2]; + int fd[2]; + char **config_options; - if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) - error("%s pipe: %s", dumper->name, strerror(errno)); + if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) { + error(_("%s pipe: %s"), dumper->name, strerror(errno)); + /*NOTREACHED*/ + } switch(dumper->pid = fork()) { case -1: - error("fork %s: %s", dumper->name, strerror(errno)); + error(_("fork %s: %s"), dumper->name, strerror(errno)); + /*NOTREACHED*/ + case 0: /* child process */ aclose(fd[0]); if(dup2(fd[1], 0) == -1 || dup2(fd[1], 1) == -1) - error("%s dup2: %s", dumper->name, strerror(errno)); - execle(dumper_program, - dumper->name ? dumper->name : "dumper", - config_name, - (char *)0, - safe_env()); - error("exec %s (%s): %s", dumper_program, + error(_("%s dup2: %s"), dumper->name, strerror(errno)); + config_options = get_config_options(2); + config_options[0] = dumper->name ? dumper->name : "dumper", + config_options[1] = get_config_name(); + safe_fd(-1, 0); + execve(dumper_program, config_options, safe_env()); + error(_("exec %s (%s): %s"), dumper_program, dumper->name, strerror(errno)); + /*NOTREACHED*/ + default: /* parent process */ aclose(fd[1]); - dumper->infd = dumper->outfd = fd[0]; - addfd(dumper->outfd, &readset, &maxfd); + dumper->fd = fd[0]; + dumper->ev_read = NULL; dumper->busy = dumper->down = 0; dumper->dp = NULL; - fprintf(stderr,"driver: started %s pid %d\n", - dumper->name, dumper->pid); + g_fprintf(stderr,_("driver: started %s pid %u\n"), + dumper->name, (unsigned)dumper->pid); fflush(stderr); } } -void startup_dump_processes(dumper_program, inparallel) -char *dumper_program; -int inparallel; +void +startup_dump_processes( + char *dumper_program, + int inparallel, + char *timestamp) { int i; dumper_t *dumper; char number[NUM_STR_SIZE]; for(dumper = dmptable, i = 0; i < inparallel; dumper++, i++) { - ap_snprintf(number, sizeof(number), "%d", i); + g_snprintf(number, SIZEOF(number), "%d", i); dumper->name = stralloc2("dumper", number); + dumper->chunker = &chktable[i]; + chktable[i].name = stralloc2("chunker", number); + chktable[i].dumper = dumper; + chktable[i].fd = -1; startup_dump_process(dumper, dumper_program); + dumper_cmd(dumper, START, NULL, (void *)timestamp); + } +} + +void +startup_chunk_process( + chunker_t *chunker, + char *chunker_program) +{ + int fd[2]; + char **config_options; + + if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) { + error(_("%s pipe: %s"), chunker->name, strerror(errno)); + /*NOTREACHED*/ + } + + switch(chunker->pid = fork()) { + case -1: + error(_("fork %s: %s"), chunker->name, strerror(errno)); + /*NOTREACHED*/ + + case 0: /* child process */ + aclose(fd[0]); + if(dup2(fd[1], 0) == -1 || dup2(fd[1], 1) == -1) { + error(_("%s dup2: %s"), chunker->name, strerror(errno)); + /*NOTREACHED*/ + } + config_options = get_config_options(2); + config_options[0] = chunker->name ? chunker->name : "chunker", + config_options[1] = get_config_name(); + safe_fd(-1, 0); + execve(chunker_program, config_options, safe_env()); + error(_("exec %s (%s): %s"), chunker_program, + chunker->name, strerror(errno)); + /*NOTREACHED*/ + + default: /* parent process */ + aclose(fd[1]); + chunker->down = 0; + chunker->fd = fd[0]; + chunker->ev_read = NULL; + g_fprintf(stderr,_("driver: started %s pid %u\n"), + chunker->name, (unsigned)chunker->pid); + fflush(stderr); } } -cmd_t getresult(fd, show, result_argc, result_argv, max_arg) -int fd; -int show; -int *result_argc; -char **result_argv; -int max_arg; +cmd_t +getresult( + int fd, + int show, + int *result_argc, + char ***result_argv) { - int arg; cmd_t t; char *line; if((line = areads(fd)) == NULL) { if(errno) { - error("reading result from %s: %s", childstr(fd), strerror(errno)); + g_fprintf(stderr, _("reading result from %s: %s"), childstr(fd), strerror(errno)); } + *result_argv = NULL; *result_argc = 0; /* EOF */ } else { - *result_argc = split(line, result_argv, max_arg, " "); + *result_argv = split_quoted_strings(line); + *result_argc = g_strv_length(*result_argv); } - amfree(line); if(show) { - printf("driver: result time %s from %s:", + g_printf(_("driver: result time %s from %s:"), walltime_str(curclock()), childstr(fd)); - for(arg = 1; arg <= *result_argc; arg++) - printf(" %s", result_argv[arg]); - printf("\n"); + if(line) { + g_printf(" %s", line); + putchar('\n'); + } else { + g_printf(" (eof)\n"); + } fflush(stdout); } - -#ifdef DEBUG - printf("argc = %d\n", *result_argc); - for(arg = 0; arg < *result_argc; arg++) - printf("argv[%d] = \"%s\"\n", arg, result_argv[arg]); -#endif + amfree(line); if(*result_argc < 1) return BOGUS; for(t = (cmd_t)(BOGUS+1); t < LAST_TOK; t++) - if(strcmp(result_argv[1], cmdstr[t]) == 0) return t; + if(strcmp((*result_argv)[0], cmdstr[t]) == 0) return t; return BOGUS; } -int taper_cmd(cmd, /* optional */ ptr, destname, level, datestamp) -cmd_t cmd; -void *ptr; -char *destname; -int level; -char *datestamp; +static char * +taper_splitting_args( + disk_t *dp) +{ + GString *args = NULL; + char *q = NULL; + dumptype_t *dt = dp->config; + tapetype_t *tt; + + tt = lookup_tapetype(getconf_str(CNF_TAPETYPE)); + g_assert(tt != NULL); + + args = g_string_new(""); + + /* old dumptype-based parameters, using empty strings when not seen */ + if (dt) { /* 'dt' may be NULL for flushes */ + if (dumptype_seen(dt, DUMPTYPE_TAPE_SPLITSIZE)) { + g_string_append_printf(args, "%ju ", + (uintmax_t)dumptype_get_tape_splitsize(dt)*1024); + } else { + g_string_append(args, "\"\" "); + } + + q = quote_string(dumptype_seen(dt, DUMPTYPE_SPLIT_DISKBUFFER)? + dumptype_get_split_diskbuffer(dt) : ""); + g_string_append_printf(args, "%s ", q); + g_free(q); + + if (dumptype_seen(dt, DUMPTYPE_FALLBACK_SPLITSIZE)) { + g_string_append_printf(args, "%ju ", + (uintmax_t)dumptype_get_fallback_splitsize(dt)*1024); + } else { + g_string_append(args, "\"\" "); + } + + if (dumptype_seen(dt, DUMPTYPE_ALLOW_SPLIT)) { + g_string_append_printf(args, "%d ", + (int)dumptype_get_allow_split(dt)); + } else { + g_string_append(args, "\"\" "); + } + } else { + g_string_append(args, "\"\" \"\" \"\" \"\" "); + } + + /* new tapetype-based parameters */ + if (tapetype_seen(tt, TAPETYPE_PART_SIZE)) { + g_string_append_printf(args, "%ju ", + (uintmax_t)tapetype_get_part_size(tt)*1024); + } else { + g_string_append(args, "\"\" "); + } + + q = ""; + if (tapetype_seen(tt, TAPETYPE_PART_CACHE_TYPE)) { + switch (tapetype_get_part_cache_type(tt)) { + default: + case PART_CACHE_TYPE_NONE: + q = "none"; + break; + + case PART_CACHE_TYPE_MEMORY: + q = "memory"; + break; + + case PART_CACHE_TYPE_DISK: + q = "disk"; + break; + } + } + q = quote_string(q); + g_string_append_printf(args, "%s ", q); + g_free(q); + + q = quote_string(tapetype_seen(tt, TAPETYPE_PART_CACHE_DIR)? + tapetype_get_part_cache_dir(tt) : ""); + g_string_append_printf(args, "%s ", q); + g_free(q); + + if (tapetype_seen(tt, TAPETYPE_PART_CACHE_MAX_SIZE)) { + g_string_append_printf(args, "%ju ", + (uintmax_t)tapetype_get_part_cache_max_size(tt)*1024); + } else { + g_string_append(args, "\"\" "); + } + + + return g_string_free(args, FALSE); +} + +int +taper_cmd( + cmd_t cmd, + void *ptr, + char *destname, + int level, + char *datestamp) { char *cmdline = NULL; char number[NUM_STR_SIZE]; + char orig_kb[NUM_STR_SIZE]; + char *data_path; disk_t *dp; - int l, n, s; - char *features; + char *qname; + char *qdest; + char *q; + char *splitargs; + uintmax_t origsize; switch(cmd) { case START_TAPER: - cmdline = vstralloc(cmdstr[cmd], " ", (char *)ptr, "\n", NULL); + cmdline = vstralloc(cmdstr[cmd], + " ", destname, + " ", datestamp, + "\n", NULL); + break; + case CLOSE_VOLUME: + dp = (disk_t *) ptr; + cmdline = g_strjoin(NULL, cmdstr[cmd], + " ", sched(dp)->taper->name, + "\n", NULL); break; case FILE_WRITE: dp = (disk_t *) ptr; - ap_snprintf(number, sizeof(number), "%d", level); - features = am_feature_to_string(dp->host->features); + qname = quote_string(dp->name); + qdest = quote_string(destname); + g_snprintf(number, SIZEOF(number), "%d", level); + if (sched(dp)->origsize >= 0) + origsize = sched(dp)->origsize; + else + origsize = 0; + g_snprintf(orig_kb, SIZEOF(orig_kb), "%ju", origsize); + splitargs = taper_splitting_args(dp); cmdline = vstralloc(cmdstr[cmd], + " ", sched(dp)->taper->name, " ", disk2serial(dp), - " ", destname, + " ", qdest, " ", dp->host->hostname, - " ", features, - " ", dp->name, + " ", qname, " ", number, " ", datestamp, + " ", splitargs, + orig_kb, "\n", NULL); - amfree(features); + amfree(splitargs); + amfree(qdest); + amfree(qname); break; + case PORT_WRITE: dp = (disk_t *) ptr; - ap_snprintf(number, sizeof(number), "%d", level); - features = am_feature_to_string(dp->host->features); + qname = quote_string(dp->name); + g_snprintf(number, SIZEOF(number), "%d", level); + data_path = data_path_to_string(dp->data_path); + + /* + If we haven't been given a place to buffer split dumps to disk, + make the argument something besides and empty string so's taper + won't get confused + */ + splitargs = taper_splitting_args(dp); cmdline = vstralloc(cmdstr[cmd], + " ", sched(dp)->taper->name, " ", disk2serial(dp), " ", dp->host->hostname, - " ", features, - " ", dp->name, + " ", qname, " ", number, " ", datestamp, + " ", splitargs, + data_path, + "\n", NULL); + amfree(splitargs); + amfree(qname); + break; + case DONE: /* handle */ + dp = (disk_t *) ptr; + if (sched(dp)->origsize >= 0) + origsize = sched(dp)->origsize; + else + origsize = 0; + g_snprintf(number, SIZEOF(number), "%ju", origsize); + cmdline = vstralloc(cmdstr[cmd], + " ", sched(dp)->taper->name, + " ", disk2serial(dp), + " ", number, + "\n", NULL); + break; + case FAILED: /* handle */ + dp = (disk_t *) ptr; + cmdline = vstralloc(cmdstr[cmd], + " ", sched(dp)->taper->name, + " ", disk2serial(dp), + "\n", NULL); + break; + case NO_NEW_TAPE: + dp = (disk_t *) ptr; + q = quote_string(destname); /* reason why no new tape */ + cmdline = vstralloc(cmdstr[cmd], + " ", sched(dp)->taper->name, + " ", disk2serial(dp), + " ", q, + "\n", NULL); + amfree(q); + break; + case NEW_TAPE: + dp = (disk_t *) ptr; + cmdline = vstralloc(cmdstr[cmd], + " ", sched(dp)->taper->name, + " ", disk2serial(dp), + "\n", NULL); + break; + case START_SCAN: + dp = (disk_t *) ptr; + cmdline = vstralloc(cmdstr[cmd], + " ", sched(dp)->taper->name, + " ", disk2serial(dp), + "\n", NULL); + break; + case TAKE_SCRIBE_FROM: + dp = (disk_t *) ptr; + cmdline = vstralloc(cmdstr[cmd], + " ", sched(dp)->taper->name, + " ", disk2serial(dp), + " ", destname, /* name of worker */ "\n", NULL); - amfree(features); break; case QUIT: cmdline = stralloc2(cmdstr[cmd], "\n"); break; default: - error("Don't know how to send %s command to taper", cmdstr[cmd]); + error(_("Don't know how to send %s command to taper"), cmdstr[cmd]); + /*NOTREACHED*/ } + /* * Note: cmdline already has a '\n'. */ - printf("driver: send-cmd time %s to taper: %s", + g_printf(_("driver: send-cmd time %s to taper: %s"), walltime_str(curclock()), cmdline); fflush(stdout); - for(l = 0, n = strlen(cmdline); l < n; l += s) { - if((s = write(taper, cmdline + l, n - l)) < 0) { - printf("writing taper command: %s\n", strerror(errno)); - fflush(stdout); - amfree(cmdline); - return 0; - } + if ((full_write(taper_fd, cmdline, strlen(cmdline))) < strlen(cmdline)) { + g_printf(_("writing taper command '%s' failed: %s\n"), + cmdline, strerror(errno)); + fflush(stdout); + amfree(cmdline); + return 0; } + if(cmd == QUIT) aclose(taper_fd); amfree(cmdline); return 1; } -int dumper_cmd(dumper, cmd, /* optional */ dp) -dumper_t *dumper; -cmd_t cmd; -disk_t *dp; +int +dumper_cmd( + dumper_t *dumper, + cmd_t cmd, + disk_t *dp, + char *mesg) { char *cmdline = NULL; char number[NUM_STR_SIZE]; - char chunksize[NUM_STR_SIZE]; - char use[NUM_STR_SIZE]; - int l, n, s; - char *o; - int activehd=0; - assignedhd_t **h=NULL; + char numberport[NUM_STR_SIZE]; + char *o, *oo; char *device; char *features; + char *qname; + char *qmesg; - if(dp && sched(dp) && sched(dp)->holdp) { - h = sched(dp)->holdp; - activehd = sched(dp)->activehd; - } + switch(cmd) { + case START: + cmdline = vstralloc(cmdstr[cmd], " ", mesg, "\n", NULL); + break; + case PORT_DUMP: + if(dp && dp->device) { + device = dp->device; + } + else { + device = "NODEVICE"; + } - if(dp && dp->device) { - device = dp->device; - } - else { - device = "NODEVICE"; - } + if (dp != NULL) { + application_t *application = NULL; + char *plugin; + char *qplugin; + char *qamandad_path; + char *qclient_username; + char *qclient_port; + char *qssh_keys; + char *d_prop; + + if (dp->application != NULL) { + application = lookup_application(dp->application); + g_assert(application != NULL); + } - switch(cmd) { - case FILE_DUMP: - holdalloc(h[activehd]->disk)->allocated_dumpers++; - ap_snprintf(number, sizeof(number), "%d", sched(dp)->level); - ap_snprintf(chunksize, sizeof(chunksize), "%ld", h[0]->disk->chunksize); - ap_snprintf(use, sizeof(use), "%ld", h[0]->reserved ); - features = am_feature_to_string(dp->host->features); - o = optionstr(dp, dp->host->features, NULL); - cmdline = vstralloc(cmdstr[cmd], + device = quote_string((dp->device) ? dp->device : "NODEVICE"); + qname = quote_string(dp->name); + g_snprintf(number, SIZEOF(number), "%d", sched(dp)->level); + g_snprintf(numberport, SIZEOF(numberport), "%d", dumper->output_port); + features = am_feature_to_string(dp->host->features); + if (am_has_feature(dp->host->features, fe_req_xml)) { + o = xml_optionstr(dp, 1); + + d_prop = xml_dumptype_properties(dp); + vstrextend(&o, d_prop, NULL); + amfree(d_prop); + + if (application) { + char *xml_app; + xml_app = xml_application(dp, application, + dp->host->features); + vstrextend(&o, xml_app, NULL); + amfree(xml_app); + } + oo = quote_string(o); + amfree(o); + o = oo; + } else { + o = optionstr(dp); + } + + g_assert(dp->program); + if (0 == strcmp(dp->program, "APPLICATION")) { + g_assert(application != NULL); + plugin = application_get_plugin(application); + } else { + plugin = dp->program; + } + qplugin = quote_string(plugin); + qamandad_path = quote_string(dp->amandad_path); + qclient_username = quote_string(dp->client_username); + qclient_port = quote_string(dp->client_port); + qssh_keys = quote_string(dp->ssh_keys); + dbprintf("security_driver %s\n", dp->auth); + + cmdline = vstralloc(cmdstr[cmd], " ", disk2serial(dp), - " ", sched(dp)->destname, + " ", numberport, " ", dp->host->hostname, " ", features, - " ", dp->name, + " ", qname, " ", device, " ", number, " ", sched(dp)->dumpdate, - " ", chunksize, - " ", dp->program, - " ", use, + " ", qplugin, + " ", qamandad_path, + " ", qclient_username, + " ", qclient_port, + " ", qssh_keys, + " ", dp->auth, + " ", data_path_to_string(dp->data_path), + " ", dp->dataport_list, " |", o, "\n", NULL); - amfree(features); - amfree(o); + amfree(qplugin); + amfree(qamandad_path); + amfree(qclient_username); + amfree(qclient_port); + amfree(qssh_keys); + amfree(features); + amfree(o); + amfree(qname); + amfree(device); + } else { + error(_("PORT-DUMP without disk pointer\n")); + /*NOTREACHED*/ + } break; - case PORT_DUMP: - ap_snprintf(number, sizeof(number), "%d", sched(dp)->level); - features = am_feature_to_string(dp->host->features); - o = optionstr(dp, dp->host->features, NULL); - cmdline = vstralloc(cmdstr[cmd], + case QUIT: + case ABORT: + qmesg = quote_string(mesg); + cmdline = vstralloc(cmdstr[cmd], " ", qmesg, "\n", NULL ); + amfree(qmesg); + break; + default: + error(_("Don't know how to send %s command to dumper"), cmdstr[cmd]); + /*NOTREACHED*/ + } + + /* + * Note: cmdline already has a '\n'. + */ + if(dumper->down) { + g_printf(_("driver: send-cmd time %s ignored to down dumper %s: %s"), + walltime_str(curclock()), dumper->name, cmdline); + } else { + g_printf(_("driver: send-cmd time %s to %s: %s"), + walltime_str(curclock()), dumper->name, cmdline); + fflush(stdout); + if (full_write(dumper->fd, cmdline, strlen(cmdline)) < strlen(cmdline)) { + g_printf(_("writing %s command: %s\n"), dumper->name, strerror(errno)); + fflush(stdout); + amfree(cmdline); + return 0; + } + if (cmd == QUIT) aclose(dumper->fd); + } + amfree(cmdline); + return 1; +} + +int +chunker_cmd( + chunker_t *chunker, + cmd_t cmd, + disk_t *dp, + char *mesg) +{ + char *cmdline = NULL; + char number[NUM_STR_SIZE]; + char chunksize[NUM_STR_SIZE]; + char use[NUM_STR_SIZE]; + char *o; + int activehd=0; + assignedhd_t **h=NULL; + char *features; + char *qname; + char *qdest; + + switch(cmd) { + case START: + cmdline = vstralloc(cmdstr[cmd], " ", mesg, "\n", NULL); + break; + case PORT_WRITE: + if(dp && sched(dp) && sched(dp)->holdp) { + h = sched(dp)->holdp; + activehd = sched(dp)->activehd; + } + + if (dp && h) { + qname = quote_string(dp->name); + qdest = quote_string(sched(dp)->destname); + h[activehd]->disk->allocated_dumpers++; + g_snprintf(number, SIZEOF(number), "%d", sched(dp)->level); + g_snprintf(chunksize, SIZEOF(chunksize), "%lld", + (long long)holdingdisk_get_chunksize(h[0]->disk->hdisk)); + g_snprintf(use, SIZEOF(use), "%lld", + (long long)h[0]->reserved); + features = am_feature_to_string(dp->host->features); + o = optionstr(dp); + cmdline = vstralloc(cmdstr[cmd], " ", disk2serial(dp), - " ", sched(dp)->destname, + " ", qdest, " ", dp->host->hostname, " ", features, - " ", dp->name, - " ", device, + " ", qname, " ", number, " ", sched(dp)->dumpdate, + " ", chunksize, " ", dp->program, + " ", use, " |", o, "\n", NULL); - amfree(features); - amfree(o); - break; - case QUIT: - case ABORT: - if( dp ) { - cmdline = vstralloc(cmdstr[cmd], - " ", sched(dp)->destname, - "\n", NULL ); + amfree(features); + amfree(o); + amfree(qdest); + amfree(qname); } else { - cmdline = stralloc2(cmdstr[cmd], "\n"); + error(_("%s command without disk and holding disk.\n"), + cmdstr[cmd]); + /*NOTREACHED*/ } break; case CONTINUE: - if( dp ) { - holdalloc(h[activehd]->disk)->allocated_dumpers++; - ap_snprintf(chunksize, sizeof(chunksize), "%ld", - h[activehd]->disk->chunksize ); - ap_snprintf(use, sizeof(use), "%ld", - h[activehd]->reserved - h[activehd]->used ); + if(dp && sched(dp) && sched(dp)->holdp) { + h = sched(dp)->holdp; + activehd = sched(dp)->activehd; + } + + if(dp && h) { + qname = quote_string(dp->name); + qdest = quote_string(h[activehd]->destname); + h[activehd]->disk->allocated_dumpers++; + g_snprintf(chunksize, SIZEOF(chunksize), "%lld", + (long long)holdingdisk_get_chunksize(h[activehd]->disk->hdisk)); + g_snprintf(use, SIZEOF(use), "%lld", + (long long)(h[activehd]->reserved - h[activehd]->used)); cmdline = vstralloc(cmdstr[cmd], - " ", disk2serial(dp), - " ", h[activehd]->destname, + " ", disk2serial(dp), + " ", qdest, " ", chunksize, " ", use, "\n", NULL ); + amfree(qdest); + amfree(qname); } else { cmdline = stralloc2(cmdstr[cmd], "\n"); } break; + case QUIT: + case ABORT: + { + char *q = quote_string(mesg); + cmdline = vstralloc(cmdstr[cmd], " ", q, "\n", NULL); + amfree(q); + } + break; + case DONE: + case FAILED: + if( dp ) { + cmdline = vstralloc(cmdstr[cmd], + " ", disk2serial(dp), + "\n", NULL); + } else { + cmdline = vstralloc(cmdstr[cmd], "\n", NULL); + } + break; default: - error("Don't know how to send %s command to dumper", cmdstr[cmd]); + error(_("Don't know how to send %s command to chunker"), cmdstr[cmd]); + /*NOTREACHED*/ } + /* * Note: cmdline already has a '\n'. */ - if(dumper->down) { - printf("driver: send-cmd time %s ignored to down dumper %s: %s", - walltime_str(curclock()), dumper->name, cmdline); - } else { - printf("driver: send-cmd time %s to %s: %s", - walltime_str(curclock()), dumper->name, cmdline); + g_printf(_("driver: send-cmd time %s to %s: %s"), + walltime_str(curclock()), chunker->name, cmdline); + fflush(stdout); + if (full_write(chunker->fd, cmdline, strlen(cmdline)) < strlen(cmdline)) { + g_printf(_("writing %s command: %s\n"), chunker->name, strerror(errno)); fflush(stdout); - for(l = 0, n = strlen(cmdline); l < n; l += s) { - if((s = write(dumper->infd, cmdline + l, n - l)) < 0) { - printf("writing %s command: %s\n", dumper->name, - strerror(errno)); - fflush(stdout); - amfree(cmdline); - return 0; - } - } + amfree(cmdline); + return 0; } + if (cmd == QUIT) aclose(chunker->fd); amfree(cmdline); return 1; } -#define MAX_SERIAL MAX_DUMPERS+1 /* one for the taper */ +#define MAX_SERIAL MAX_DUMPERS*2 /* one for each dumper and taper */ long generation = 1; @@ -420,56 +850,93 @@ struct serial_s { disk_t *dp; } stable[MAX_SERIAL]; -disk_t *serial2disk(str) -char *str; +disk_t * +serial2disk( + char *str) { int rc, s; long gen; rc = sscanf(str, "%d-%ld", &s, &gen); if(rc != 2) { - error("error [serial2disk \"%s\" parse error]", str); + error(_("error [serial2disk \"%s\" parse error]"), str); + /*NOTREACHED*/ } else if (s < 0 || s >= MAX_SERIAL) { - error("error [serial out of range 0..%d: %d]", MAX_SERIAL, s); + error(_("error [serial out of range 0..%d: %d]"), MAX_SERIAL, s); + /*NOTREACHED*/ } if(gen != stable[s].gen) - printf("driver: error time %s serial gen mismatch\n", - walltime_str(curclock())); + g_printf(_("driver: serial2disk error time %s serial gen mismatch %s\n"), + walltime_str(curclock()), str); return stable[s].dp; } -void free_serial(str) -char *str; +void +free_serial( + char *str) { int rc, s; long gen; - rc = sscanf(str, "%d-%ld", &s, &gen); + rc = sscanf(str, _("%d-%ld"), &s, &gen); if(!(rc == 2 && s >= 0 && s < MAX_SERIAL)) { /* nuke self to get core dump for Brett */ - fprintf(stderr, "driver: free_serial: str \"%s\" rc %d s %d\n", + g_fprintf(stderr, _("driver: free_serial: str \"%s\" rc %d s %d\n"), str, rc, s); fflush(stderr); abort(); } if(gen != stable[s].gen) - printf("driver: error time %s serial gen mismatch\n", - walltime_str(curclock())); + g_printf(_("driver: free_serial error time %s serial gen mismatch %s\n"), + walltime_str(curclock()),str); stable[s].gen = 0; stable[s].dp = NULL; } -char *disk2serial(dp) -disk_t *dp; +void +free_serial_dp( + disk_t *dp) +{ + int s; + + for(s = 0; s < MAX_SERIAL; s++) { + if(stable[s].dp == dp) { + stable[s].gen = 0; + stable[s].dp = NULL; + return; + } + } + + g_printf(_("driver: error time %s serial not found for disk %s\n"), + walltime_str(curclock()), dp->name); +} + + +void +check_unfree_serial(void) +{ + int s; + + /* find used serial number */ + for(s = 0; s < MAX_SERIAL; s++) { + if(stable[s].gen != 0 || stable[s].dp != NULL) { + g_printf(_("driver: error time %s bug: serial in use: %02d-%05ld\n"), + walltime_str(curclock()), s, stable[s].gen); + } + } +} + +char *disk2serial( + disk_t *dp) { int s; static char str[NUM_STR_SIZE]; for(s = 0; s < MAX_SERIAL; s++) { if(stable[s].dp == dp) { - ap_snprintf(str, sizeof(str), "%02d-%05ld", s, stable[s].gen); + g_snprintf(str, SIZEOF(str), "%02d-%05ld", s, stable[s].gen); return str; } } @@ -479,7 +946,7 @@ disk_t *dp; if(stable[s].gen == 0 && stable[s].dp == NULL) break; if(s >= MAX_SERIAL) { - printf("driver: error time %s bug: out of serial numbers\n", + g_printf(_("driver: error time %s bug: out of serial numbers\n"), walltime_str(curclock())); s = 0; } @@ -487,15 +954,16 @@ disk_t *dp; stable[s].gen = generation++; stable[s].dp = dp; - ap_snprintf(str, sizeof(str), "%02d-%05ld", s, stable[s].gen); + g_snprintf(str, SIZEOF(str), "%02d-%05ld", s, stable[s].gen); return str; } -void update_info_dumper(dp, origsize, dumpsize, dumptime) - disk_t *dp; - long origsize; - long dumpsize; - long dumptime; +void +update_info_dumper( + disk_t *dp, + off_t origsize, + off_t dumpsize, + time_t dumptime) { int level, i; info_t info; @@ -505,14 +973,10 @@ void update_info_dumper(dp, origsize, dumpsize, dumptime) level = sched(dp)->level; - conf_infofile = getconf_str(CNF_INFOFILE); - if (*conf_infofile == '/') { - conf_infofile = stralloc(conf_infofile); - } else { - conf_infofile = stralloc2(config_dir, conf_infofile); - } + conf_infofile = config_dir_relative(getconf_str(CNF_INFOFILE)); if (open_infofile(conf_infofile)) { - error("could not open info db \"%s\"", conf_infofile); + error(_("could not open info db \"%s\""), conf_infofile); + /*NOTREACHED*/ } amfree(conf_infofile); @@ -523,9 +987,9 @@ void update_info_dumper(dp, origsize, dumpsize, dumptime) update_info_taper(). */ for (i = level; i < DUMP_LEVELS; ++i) { infp = &info.inf[i]; - infp->size = -1; - infp->csize = -1; - infp->secs = -1; + infp->size = (off_t)-1; + infp->csize = (off_t)-1; + infp->secs = (time_t)-1; infp->date = (time_t)-1; infp->label[0] = '\0'; infp->filenum = 0; @@ -536,34 +1000,38 @@ void update_info_dumper(dp, origsize, dumpsize, dumptime) infp->size = origsize; infp->csize = dumpsize; infp->secs = dumptime; - infp->date = sched(dp)->timestamp; + if (sched(dp)->timestamp == 0) { + infp->date = 0; + } else { + infp->date = get_time_from_timestamp(sched(dp)->datestamp); + } if(level == 0) perfp = &info.full; else perfp = &info.incr; /* Update the stats, but only if the new values are meaningful */ - if(dp->compress != COMP_NONE && origsize > 0L) { - newperf(perfp->comp, dumpsize/(float)origsize); + if(dp->compress != COMP_NONE && origsize > (off_t)0) { + newperf(perfp->comp, (double)dumpsize/(double)origsize); } - if(dumptime > 0L) { - if(dumptime >= dumpsize) + if(dumptime > (time_t)0) { + if((off_t)dumptime >= dumpsize) newperf(perfp->rate, 1); else - newperf(perfp->rate, dumpsize/dumptime); + newperf(perfp->rate, (double)dumpsize/(double)dumptime); } - if(getconf_int(CNF_RESERVE)<100) { + if(origsize >= (off_t)0 && getconf_int(CNF_RESERVE)<100) { info.command = NO_COMMAND; } - if(level == info.last_level) + if (origsize >= (off_t)0 && level == info.last_level) { info.consecutive_runs++; - else { + } else if (origsize >= (off_t)0) { info.last_level = level; info.consecutive_runs = 1; } - if(origsize >=0 && dumpsize >=0) { + if(origsize >= (off_t)0 && dumpsize >= (off_t)0) { for(i=NB_HISTORY-1;i>0;i--) { info.history[i] = info.history[i-1]; } @@ -571,52 +1039,74 @@ void update_info_dumper(dp, origsize, dumpsize, dumptime) info.history[0].level = level; info.history[0].size = origsize; info.history[0].csize = dumpsize; - info.history[0].date = sched(dp)->timestamp; + if (sched(dp)->timestamp == 0) { + info.history[0].date = 0; + } else { + info.history[0].date = get_time_from_timestamp(sched(dp)->datestamp); + } info.history[0].secs = dumptime; } - if(put_info(dp->host->hostname, dp->name, &info)) - error("infofile update failed (%s,%s)\n", dp->host->hostname, dp->name); + if (put_info(dp->host->hostname, dp->name, &info)) { + int save_errno = errno; + g_fprintf(stderr, _("infofile update failed (%s,'%s'): %s\n"), + dp->host->hostname, dp->name, strerror(save_errno)); + log_add(L_ERROR, _("infofile update failed (%s,'%s'): %s\n"), + dp->host->hostname, dp->name, strerror(save_errno)); + error(_("infofile update failed (%s,'%s'): %s\n"), + dp->host->hostname, dp->name, strerror(save_errno)); + /*NOTREACHED*/ + } close_infofile(); } -void update_info_taper(dp, label, filenum, level) -disk_t *dp; -char *label; -int filenum; -int level; +void +update_info_taper( + disk_t *dp, + char *label, + off_t filenum, + int level) { info_t info; stats_t *infp; int rc; rc = open_infofile(getconf_str(CNF_INFOFILE)); - if(rc) - error("could not open infofile %s: %s (%d)", getconf_str(CNF_INFOFILE), + if(rc) { + error(_("could not open infofile %s: %s (%d)"), getconf_str(CNF_INFOFILE), strerror(errno), rc); + /*NOTREACHED*/ + } get_info(dp->host->hostname, dp->name, &info); infp = &info.inf[level]; /* XXX - should we record these two if no-record? */ - strncpy(infp->label, label, sizeof(infp->label)-1); - infp->label[sizeof(infp->label)-1] = '\0'; + strncpy(infp->label, label, SIZEOF(infp->label)-1); + infp->label[SIZEOF(infp->label)-1] = '\0'; infp->filenum = filenum; info.command = NO_COMMAND; - if(put_info(dp->host->hostname, dp->name, &info)) - error("infofile update failed (%s,%s)\n", dp->host->hostname, dp->name); - + if (put_info(dp->host->hostname, dp->name, &info)) { + int save_errno = errno; + g_fprintf(stderr, _("infofile update failed (%s,'%s'): %s\n"), + dp->host->hostname, dp->name, strerror(save_errno)); + log_add(L_ERROR, _("infofile update failed (%s,'%s'): %s\n"), + dp->host->hostname, dp->name, strerror(save_errno)); + error(_("infofile update failed (%s,'%s'): %s\n"), + dp->host->hostname, dp->name, strerror(save_errno)); + /*NOTREACHED*/ + } close_infofile(); } /* Free an array of pointers to assignedhd_t after freeing the * assignedhd_t themselves. The array must be NULL-terminated. */ -void free_assignedhd( ahd ) -assignedhd_t **ahd; +void free_assignedhd( + assignedhd_t **ahd) { int i;