aboutsummaryrefslogtreecommitdiffstats
path: root/taper.c
diff options
context:
space:
mode:
Diffstat (limited to 'taper.c')
-rw-r--r--taper.c297
1 files changed, 297 insertions, 0 deletions
diff --git a/taper.c b/taper.c
new file mode 100644
index 0000000..66bdc57
--- /dev/null
+++ b/taper.c
@@ -0,0 +1,297 @@
+#include "config.h"
+#include "conf.h"
+#include "err.h"
+#include "lock.h"
+#include "tapeio.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mtio.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef NEED_LIBUTIL
+#include <libutil.h>
+#endif
+
+#ifdef NEED_STRINGS
+#include <strings.h>
+#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;
+}