#include "config.h" #include "conf.h" #include "err.h" #include "lock.h" #include "tapeio.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef NEED_LIBUTIL #include #endif #ifdef NEED_STRINGS #include #endif RCSID("$Id: taper.c,v 1.1.1.1 1999/02/02 23:29:39 shmit Exp $"); struct tapelist { char filen[MAXPATHLEN]; struct tapelist *next; }; int canjmp = 0; int taperunning = 0; sigjmp_buf child_buf; void sig_child(int signo) { int status; (void)wait(&status); taperunning = 0; if (canjmp) siglongjmp(child_buf, 1); } void tapefile(int tapefd, const char *filen) { char buffer[BUFFSIZE]; char *vol; fileheader_t header; ssize_t total = 0, readb; time_t start; int fd; setproctitle("Dumping %s to tape", filen); fd = open(filen, O_RDONLY); if (fd == -1) { err("%s: couldn't open: %s.\n", filen, strerror(errno)); return; } /* Write the header. */ header.type = FILEMARK; header.date = time(NULL); /* Extract host and volume names from filename. */ vol = (char *)rindex(filen, '/'); if (vol) strncpy(buffer, vol+1, sizeof(buffer)); else strncpy(buffer, filen, sizeof(buffer)); vol = index(buffer, ':'); if (vol) { *vol = '\0'; strncpy(header.vol, vol+1, sizeof(header.vol)); } else header.vol[0] = '\0'; strncpy(header.host, buffer, sizeof(header.host)); if (writeheader(tapefd, &header) == -1) { err("%s: couldn't write file header: %s.\n", filen, strerror(errno)); return; } /* Write the data. */ start = time(NULL); while ((readb = read(fd, buffer, sizeof(buffer))) > 0) { ssize_t wrote = 0, n; total += readb; while (wrote < readb) { n = write(tapefd, buffer, readb); if (n == -1) { err("%s: couldn't write to tape: %s.\n", filen, strerror(errno)); close(fd); return; } wrote += n; } } if (readb == -1) err("%s: couldn't read from dump: %s.\n", filen, strerror(errno)); if (mt_weof(tapefd, 1) == -1) err("%s: couldn't write EOF marker: %s.\n", filen, strerror(errno)); printf("DEBUG: wrote %d bytes in %ld seconds.\n", total, time(NULL)-start); close(fd); } int main(int argc, char *argv[]) { struct tapelist *list = NULL; const config_t *option; char *labelstr, *tapedev; struct sigaction sa; fileheader_t header; tapelabel_t label; sigset_t set, oset; int tapefd; if (read_config(SERVER_CONFIG_FILE) == -1) return 1; option = findopt(LABELSTR); if (!option) { err("Taper: " LABELSTR " hasn't been set.\n"); return 1; } labelstr = option->strvalue; option = findopt(TAPEDEV); if (!option) { err("Taper: " TAPEDEV " hasn't been set.\n"); return 1; } tapedev = option->strvalue; tapefd = open(tapedev, O_RDWR); if (tapefd == -1) { err("Taper: Couldn't open tape device %s: %s.\n", tapedev, strerror(errno)); return 1; } if (mt_rewind(tapefd) == -1) { err("Taper: couldn't rewind tape: %s.\n", strerror(errno)); return 1; } if (readlabel(tapefd, &label) == -1) { close(tapefd); return 1; } if (memcmp(label.labelstr, labelstr, sizeof(labelstr))) { err("Taper: label `%s' doesn't match expected label `%s'.\n", label.labelstr, labelstr); return 1; } sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = sig_child; sigaction(SIGCHLD, &sa, NULL); /* Loop waiting for input from the dumper. */ for (;;) { char buffer[MAXLINE]; if (!canjmp && sigsetjmp(child_buf, 1)) { if (list) { struct tapelist *p = list; pid_t pid; taperunning = 1; pid = fork(); if (pid == -1) { err("Taper: couldn't fork: %s.\n", strerror(errno)); return 1; } else if (!pid) { tapefile(tapefd, p->filen); exit(0); } list = list->next; free(p); } } canjmp = 1; if (!fgets(buffer, sizeof(buffer), stdin)) { err("Taper: dumper died abnormally.\n"); break; } sigemptyset(&set); sigaddset(&set, SIGCHLD); sigprocmask(SIG_BLOCK, &set, &oset); if (!memcmp(buffer, DISK_REQ, sizeof(DISK_REQ)-1)) { char *index = buffer+sizeof(DISK_REQ)-1; /* * Special case the event when the taper isn't * running and the list is NULL so we can start * the process and continue it when we've dumped * everything so far to tape. */ index[strlen(index)-1] = '\0'; if (!list && !taperunning) { pid_t pid; taperunning = 1; pid = fork(); if (pid == -1) { err("Taper: couldn't fork: %s.\n", strerror(errno)); break; } else if (!pid) { tapefile(tapefd, index); exit(0); } } else { struct tapelist *p, *q = list; p = malloc(sizeof(struct tapelist)); if (!p) { err("Taper: couldn't malloc: %s.\n", strerror(errno)); break; } strncpy(p->filen, index, sizeof(p->filen)); p->next = NULL; if (q) { while (q->next) q = q->next; q->next = p; } else list = p; } } if (!memcmp(buffer, DUMP_DONE, sizeof(DUMP_DONE)-1)) break; sigprocmask(SIG_SETMASK, &oset, NULL); } if (list || taperunning) { /* * Make sig_child exit without a siglongjmp, then unblock * the signal. */ canjmp = 0; sigprocmask(SIG_SETMASK, &oset, NULL); /* Wait for the first child to exit. */ sigemptyset(&set); sigsuspend(&set); /* Then run through the pending files. */ while (list) { struct tapelist *p = list; tapefile(tapefd, list->filen); list = list->next; free(p); } } header.type = STOPMARK; if (writeheader(tapefd, &header) == -1) { err("Taper: couldn't write end-of-tape marker: %s.\n", strerror(errno)); close(tapefd); return 1; } close(tapefd); return 0; }