2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
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.
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.
23 * Author: James da Silva, Systems Design and Analysis Group
24 * Computer Science Department
25 * University of Maryland at College Park
28 * $Id: driverio.c,v 1.35.2.14.4.2.2.5 2003/01/01 23:28:54 martinea Exp $
30 * I/O-related functions for driver program
39 #include "server_util.h"
41 #define GLOBAL /* the global variables defined here */
50 for(dumper = dmptable; dumper < dmptable + MAX_DUMPERS; dumper++) {
56 void addfd(fd, readset, maxfd)
61 if(fd < 0 || fd >= FD_SETSIZE) {
62 error("addfd: descriptor %d out of range (0 .. %d)\n",
68 if(fd > *maxfd) *maxfd = fd;
74 static char *str = NULL;
75 char fd_str[NUM_STR_SIZE];
78 if(fd == taper) return "taper";
80 for(dumper = dmptable; dumper < dmptable + MAX_DUMPERS; dumper++)
81 if(dumper->outfd == fd) return dumper->name;
83 ap_snprintf(fd_str, sizeof(fd_str), "%d", fd);
84 str = newvstralloc(str, "unknown child (fd ", fd_str, ")", NULL);
89 void startup_tape_process(taper_program)
94 if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1)
95 error("taper pipe: %s", strerror(errno));
96 if(fd[0] < 0 || fd[0] >= FD_SETSIZE) {
97 error("taper socketpair 0: descriptor %d out of range (0 .. %d)\n",
100 if(fd[1] < 0 || fd[1] >= FD_SETSIZE) {
101 error("taper socketpair 1: descriptor %d out of range (0 .. %d)\n",
102 fd[1], FD_SETSIZE-1);
105 switch(taper_pid = fork()) {
107 error("fork taper: %s", strerror(errno));
108 case 0: /* child process */
110 if(dup2(fd[1], 0) == -1 || dup2(fd[1], 1) == -1)
111 error("taper dup2: %s", strerror(errno));
112 execle(taper_program, "taper", config_name, (char *)0, safe_env());
113 error("exec %s: %s", taper_program, strerror(errno));
114 default: /* parent process */
117 addfd(taper, &readset, &maxfd);
121 void startup_dump_process(dumper, dumper_program)
123 char *dumper_program;
127 if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1)
128 error("%s pipe: %s", dumper->name, strerror(errno));
130 switch(dumper->pid = fork()) {
132 error("fork %s: %s", dumper->name, strerror(errno));
133 case 0: /* child process */
135 if(dup2(fd[1], 0) == -1 || dup2(fd[1], 1) == -1)
136 error("%s dup2: %s", dumper->name, strerror(errno));
137 execle(dumper_program,
138 dumper->name ? dumper->name : "dumper",
142 error("exec %s (%s): %s", dumper_program,
143 dumper->name, strerror(errno));
144 default: /* parent process */
146 dumper->infd = dumper->outfd = fd[0];
147 addfd(dumper->outfd, &readset, &maxfd);
148 dumper->busy = dumper->down = 0;
150 fprintf(stderr,"driver: started %s pid %d\n",
151 dumper->name, dumper->pid);
156 void startup_dump_processes(dumper_program, inparallel)
157 char *dumper_program;
162 char number[NUM_STR_SIZE];
164 for(dumper = dmptable, i = 0; i < inparallel; dumper++, i++) {
165 ap_snprintf(number, sizeof(number), "%d", i);
166 dumper->name = stralloc2("dumper", number);
168 startup_dump_process(dumper, dumper_program);
172 cmd_t getresult(fd, show, result_argc, result_argv, max_arg)
183 if((line = areads(fd)) == NULL) {
185 error("reading result from %s: %s", childstr(fd), strerror(errno));
187 *result_argc = 0; /* EOF */
189 *result_argc = split(line, result_argv, max_arg, " ");
194 printf("driver: result time %s from %s:",
195 walltime_str(curclock()),
197 for(arg = 1; arg <= *result_argc; arg++)
198 printf(" %s", result_argv[arg]);
204 printf("argc = %d\n", *result_argc);
205 for(arg = 0; arg < *result_argc; arg++)
206 printf("argv[%d] = \"%s\"\n", arg, result_argv[arg]);
209 if(*result_argc < 1) return BOGUS;
211 for(t = (cmd_t)(BOGUS+1); t < LAST_TOK; t++)
212 if(strcmp(result_argv[1], cmdstr[t]) == 0) return t;
218 int taper_cmd(cmd, /* optional */ ptr, destname, level, datestamp)
225 char *cmdline = NULL;
226 char number[NUM_STR_SIZE];
233 cmdline = vstralloc(cmdstr[cmd], " ", (char *)ptr, "\n", NULL);
237 ap_snprintf(number, sizeof(number), "%d", level);
238 features = am_feature_to_string(dp->host->features);
239 cmdline = vstralloc(cmdstr[cmd],
240 " ", disk2serial(dp),
242 " ", dp->host->hostname,
252 ap_snprintf(number, sizeof(number), "%d", level);
253 features = am_feature_to_string(dp->host->features);
254 cmdline = vstralloc(cmdstr[cmd],
255 " ", disk2serial(dp),
256 " ", dp->host->hostname,
265 cmdline = stralloc2(cmdstr[cmd], "\n");
268 error("Don't know how to send %s command to taper", cmdstr[cmd]);
271 * Note: cmdline already has a '\n'.
273 printf("driver: send-cmd time %s to taper: %s",
274 walltime_str(curclock()), cmdline);
276 for(l = 0, n = strlen(cmdline); l < n; l += s) {
277 if((s = write(taper, cmdline + l, n - l)) < 0) {
278 printf("writing taper command: %s\n", strerror(errno));
288 int dumper_cmd(dumper, cmd, /* optional */ dp)
293 char *cmdline = NULL;
294 char number[NUM_STR_SIZE];
295 char chunksize[NUM_STR_SIZE];
296 char use[NUM_STR_SIZE];
300 assignedhd_t **h=NULL;
304 if(dp && sched(dp) && sched(dp)->holdp) {
305 h = sched(dp)->holdp;
306 activehd = sched(dp)->activehd;
309 if(dp && dp->device) {
318 holdalloc(h[activehd]->disk)->allocated_dumpers++;
319 ap_snprintf(number, sizeof(number), "%d", sched(dp)->level);
320 ap_snprintf(chunksize, sizeof(chunksize), "%ld", h[0]->disk->chunksize);
321 ap_snprintf(use, sizeof(use), "%ld", h[0]->reserved );
322 features = am_feature_to_string(dp->host->features);
323 o = optionstr(dp, dp->host->features, NULL);
324 cmdline = vstralloc(cmdstr[cmd],
325 " ", disk2serial(dp),
326 " ", sched(dp)->destname,
327 " ", dp->host->hostname,
332 " ", sched(dp)->dumpdate,
342 ap_snprintf(number, sizeof(number), "%d", sched(dp)->level);
343 features = am_feature_to_string(dp->host->features);
344 o = optionstr(dp, dp->host->features, NULL);
345 cmdline = vstralloc(cmdstr[cmd],
346 " ", disk2serial(dp),
347 " ", sched(dp)->destname,
348 " ", dp->host->hostname,
353 " ", sched(dp)->dumpdate,
363 cmdline = vstralloc(cmdstr[cmd],
364 " ", sched(dp)->destname,
367 cmdline = stralloc2(cmdstr[cmd], "\n");
372 holdalloc(h[activehd]->disk)->allocated_dumpers++;
373 ap_snprintf(chunksize, sizeof(chunksize), "%ld",
374 h[activehd]->disk->chunksize );
375 ap_snprintf(use, sizeof(use), "%ld",
376 h[activehd]->reserved - h[activehd]->used );
377 cmdline = vstralloc(cmdstr[cmd],
378 " ", h[activehd]->destname,
383 cmdline = stralloc2(cmdstr[cmd], "\n");
387 error("Don't know how to send %s command to dumper", cmdstr[cmd]);
390 * Note: cmdline already has a '\n'.
393 printf("driver: send-cmd time %s ignored to down dumper %s: %s",
394 walltime_str(curclock()), dumper->name, cmdline);
396 printf("driver: send-cmd time %s to %s: %s",
397 walltime_str(curclock()), dumper->name, cmdline);
399 for(l = 0, n = strlen(cmdline); l < n; l += s) {
400 if((s = write(dumper->infd, cmdline + l, n - l)) < 0) {
401 printf("writing %s command: %s\n", dumper->name,
413 #define MAX_SERIAL MAX_DUMPERS+1 /* one for the taper */
420 } stable[MAX_SERIAL];
422 disk_t *serial2disk(str)
428 rc = sscanf(str, "%d-%ld", &s, &gen);
430 error("error [serial2disk \"%s\" parse error]", str);
431 } else if (s < 0 || s >= MAX_SERIAL) {
432 error("error [serial out of range 0..%d: %d]", MAX_SERIAL, s);
434 if(gen != stable[s].gen)
435 printf("driver: error time %s serial gen mismatch\n",
436 walltime_str(curclock()));
440 void free_serial(str)
446 rc = sscanf(str, "%d-%ld", &s, &gen);
447 if(!(rc == 2 && s >= 0 && s < MAX_SERIAL)) {
448 /* nuke self to get core dump for Brett */
449 fprintf(stderr, "driver: free_serial: str \"%s\" rc %d s %d\n",
455 if(gen != stable[s].gen)
456 printf("driver: error time %s serial gen mismatch\n",
457 walltime_str(curclock()));
462 char *disk2serial(dp)
466 static char str[NUM_STR_SIZE];
468 /* find unused serial number */
469 for(s = 0; s < MAX_SERIAL; s++) if(stable[s].gen == 0) break;
470 if(s >= MAX_SERIAL) {
471 printf("driver: error time %s bug: out of serial numbers\n",
472 walltime_str(curclock()));
476 stable[s].gen = generation++;
479 ap_snprintf(str, sizeof(str), "%02d-%05ld", s, stable[s].gen);
483 void update_info_dumper(dp, origsize, dumpsize, dumptime)
495 level = sched(dp)->level;
497 conf_infofile = getconf_str(CNF_INFOFILE);
498 if (*conf_infofile == '/') {
499 conf_infofile = stralloc(conf_infofile);
501 conf_infofile = stralloc2(config_dir, conf_infofile);
503 if (open_infofile(conf_infofile)) {
504 error("could not open info db \"%s\"", conf_infofile);
506 amfree(conf_infofile);
508 get_info(dp->host->hostname, dp->name, &info);
510 /* Clean up information about this and higher-level dumps. This
511 assumes that update_info_dumper() is always run before
512 update_info_taper(). */
513 for (i = level; i < DUMP_LEVELS; ++i) {
518 infp->date = (time_t)-1;
519 infp->label[0] = '\0';
523 /* now store information about this dump */
524 infp = &info.inf[level];
525 infp->size = origsize;
526 infp->csize = dumpsize;
527 infp->secs = dumptime;
528 infp->date = sched(dp)->timestamp;
530 if(level == 0) perfp = &info.full;
531 else perfp = &info.incr;
533 /* Update the stats, but only if the new values are meaningful */
534 if(dp->compress != COMP_NONE && origsize > 0L) {
535 newperf(perfp->comp, dumpsize/(float)origsize);
538 if(dumptime >= dumpsize)
539 newperf(perfp->rate, 1);
541 newperf(perfp->rate, dumpsize/dumptime);
544 if(getconf_int(CNF_RESERVE)<100) {
545 info.command = NO_COMMAND;
548 if(level == info.last_level)
549 info.consecutive_runs++;
551 info.last_level = level;
552 info.consecutive_runs = 1;
554 if(put_info(dp->host->hostname, dp->name, &info))
555 error("infofile update failed (%s,%s)\n", dp->host->hostname, dp->name);
560 void update_info_taper(dp, label, filenum, level)
570 rc = open_infofile(getconf_str(CNF_INFOFILE));
572 error("could not open infofile %s: %s (%d)", getconf_str(CNF_INFOFILE),
573 strerror(errno), rc);
575 get_info(dp->host->hostname, dp->name, &info);
577 infp = &info.inf[level];
578 /* XXX - should we record these two if no-record? */
579 strncpy(infp->label, label, sizeof(infp->label)-1);
580 infp->label[sizeof(infp->label)-1] = '\0';
581 infp->filenum = filenum;
583 info.command = NO_COMMAND;
585 if(put_info(dp->host->hostname, dp->name, &info))
586 error("infofile update failed (%s,%s)\n", dp->host->hostname, dp->name);
591 /* Free an array of pointers to assignedhd_t after freeing the
592 * assignedhd_t themselves. The array must be NULL-terminated.
594 void free_assignedhd( ahd )
599 if( !ahd ) { return; }
601 for( i = 0; ahd[i]; i++ ) {
602 amfree(ahd[i]->destname);