diff options
author | Brian Cully <bjc@kublai.com> | 2022-03-09 21:10:26 -0500 |
---|---|---|
committer | Brian Cully <bjc@kublai.com> | 2022-03-09 21:37:48 -0500 |
commit | 720864f2a76d4ee3ed75cb99298b8e94c01f1b29 (patch) | |
tree | 7a163efe3d699725a9e9dd2c17aebaa6a6feadc7 /run-dump.c | |
download | ticra-main.tar.gz ticra-main.zip |
I used to really hate AMANDA.
Diffstat (limited to 'run-dump.c')
-rw-r--r-- | run-dump.c | 490 |
1 files changed, 490 insertions, 0 deletions
diff --git a/run-dump.c b/run-dump.c new file mode 100644 index 0000000..a5a34ff --- /dev/null +++ b/run-dump.c @@ -0,0 +1,490 @@ +#include "config.h" +#include "conf.h" +#include "err.h" +#include "strutil.h" + +#include <errno.h> +#include <fcntl.h> +#include <netinet/in.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#ifdef NEED_LIBUTIL +#include <libutil.h> +#endif + +#ifdef NEED_STRINGS +#include <strings.h> +#endif + +RCSID("$Id: run-dump.c,v 1.1.1.1 1999/02/02 23:29:39 shmit Exp $"); + +short exit_status = -1; + +void +sig_pipe(int signo) +{ + err("SIGPIPE caught.\n"); + exit_status = -2; +} + +void +sig_child(int signo) +{ + int status; + + if (wait(&status) == -1) { + err("Couldn't clean up child: %s.\n", strerror(errno)); + return; + } + + exit_status = WEXITSTATUS(status); +} + +char ** +genargs(const char *expression, int level, const char *vol) +{ + /* TODO: generate dynamically. */ + static char *args[32]; + char word[MAXLINE]; + const char *p = expression; + char *sub; + int i = 0; + + while (i < 31 && (p = getword(p, word))) { + sub = index(word, '%'); + if (!sub) { + args[i] = malloc(strlen(word)+1); + strcpy(args[i], word); + } else { + args[i] = malloc(MAXLINE); + + *sub = '\0'; + switch (*++sub) { + case 'l': + snprintf(args[i], MAXLINE, "%s%d%s", + word, level, ++sub); + break; + case 'v': + snprintf(args[i], MAXLINE, "%s%s%s", + word, vol, ++sub); + break; + case '%': + snprintf(args[i], MAXLINE, "%s%%%s", + word, ++sub); + break; + default: + fprintf(stderr, + "Don't understand substitution" + " code `%%%c'\n", *sub); + return NULL; + } + } + i++; + } + sub = index(word, '%'); + if (!sub) { + args[i] = malloc(strlen(word)+1); + strcpy(args[i], word); + } else { + args[i] = malloc(MAXLINE); + + *sub = '\0'; + switch (*++sub) { + case 'l': + snprintf(args[i], MAXLINE, "%s%d%s", + word, level, ++sub); + break; + case 'v': + snprintf(args[i], MAXLINE, "%s%s%s", + word, vol, ++sub); + break; + case '%': + snprintf(args[i], MAXLINE, "%s%%%s", + word, ++sub); + break; + default: + fprintf(stderr, + "Don't understand substitution" + " code `%%%c'\n", *sub); + return NULL; + } + } + + args[++i] = NULL; + + return args; +} + +int +senddump(int outfd, disk_t *disk, int dumplevel) +{ + char buffer[MAXLINE]; + char path[MAXPATHLEN] = ""; + int pout[2], perr[2], errfd = -1, error = 0; + pid_t pid; + ssize_t readb; + struct sigaction sa, ocsa, opsa; + + setproctitle("Dumping %s", disk->vol); + + if (pipe(pout) == -1 || pipe(perr) == -1) { + err("Couldn't create pipes: %s.\n", strerror(errno)); + close(outfd); + return -1; + } + + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sa.sa_handler = sig_child; + sigaction(SIGCHLD, &sa, &ocsa); + sa.sa_handler = sig_pipe; + sigaction(SIGPIPE, &sa, &opsa); + + pid = fork(); + if (pid == -1) { + err("Couldn't fork: %s.\n", strerror(errno)); + close(outfd); + return -1; + } else if (!pid) { + char **args; + + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); + + close(pout[0]); close(perr[0]); + if (dup2(pout[1], STDOUT_FILENO) == -1 || + dup2(perr[1], STDERR_FILENO) == -1) { + err("Couldn't set up pipes: %s.\n", strerror(errno)); + exit(1); + } + + args = genargs(disk->type->d_cmdline, dumplevel, disk->vol); + if (!args) + exit(1); + + if (execvp(args[0], args) == -1) { + fprintf(stderr, "Couldn't exec %s: %s.\n", + args[0], strerror(errno)); + exit(1); + } + } + + close(pout[1]); close(perr[1]); + if (fcntl(pout[0], F_SETFL, O_NONBLOCK) == -1 || + fcntl(perr[0], F_SETFL, O_NONBLOCK) == -1) { + err("Couldn't set pipes to non-blocking: %s.\n", + strerror(errno)); + close(outfd); + return -1; + } + + while (exit_status == -1) { + fd_set readfds; + + FD_ZERO(&readfds); + FD_SET(pout[0], &readfds); + FD_SET(perr[0], &readfds); + + readb = select(FD_SETSIZE, &readfds, NULL, NULL, NULL); + if (readb == -1) { + if (errno == EINTR) + continue; + fprintf(stderr, + "Dumper died abnormally: %s.\n", + strerror(errno)); + error = 1; + break; + } + + if (FD_ISSET(pout[0], &readfds)) { + READO: + readb = read(pout[0], buffer, sizeof(buffer)); + if (readb == -1) { + if (errno == EINTR) + goto READO; + fprintf(stderr, "Read died abnormally: %s.\n", + strerror(errno)); + error = 1; + break; + } + + write(outfd, buffer, readb); + } + if (FD_ISSET(perr[0], &readfds)) { + if (errfd == -1) { + sprintf(path, "%s/ticra-dumperr.%d", TMPPATH, + getpid()); + errfd = open(path, + O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (errfd == -1) { + err("Couldn't open error output file" + " `%s': %s.\n", path, + strerror(errno)); + error = 1; + break; + } + } + READE: + readb = read(perr[0], buffer, sizeof(buffer)); + if (readb == -1) { + if (errno == EINTR) + goto READE; + fprintf(stderr, + "Stderr read died abnormally: %s\n", + strerror(errno)); + error = 1; + break; + } + + write(errfd, buffer, readb); + } + } + if (errfd != -1) + close(errfd); + close(outfd); + + sigaction(SIGPIPE, NULL, &opsa); + sigaction(SIGCHLD, NULL, &ocsa); + + if (!exit_status) { + printf(DUMP_DONE "\n"); + fflush(stdout); + if (*path) + (void)unlink(path); + return 0; + } + + + switch (exit_status) { + case -1: + fprintf(stderr, "Exit status unset.\n"); + break; + case -2: + /* TODO: handle me. */ + err("You're probably dead, this shouldn't happen.\n"); + return -1; + default: + if (*path) { + fprintf(stderr, + "Error occured while dumping %s;" + " output follows:\n", disk->vol); + fflush(stderr); + + errfd = open(path, O_RDONLY); + if (errfd != -1) { + while ((readb = read(errfd, buffer, + sizeof(buffer))) > 0) + write(STDERR_FILENO, buffer, readb); + close(errfd); + break; + } + } + fprintf(stderr, "Dump process returned %d.\n", exit_status); + } + + printf(DUMP_DONE "\n"); + fflush(stdout); + return 0; +} + +int +do_sendme(disklist_t *disklist, char *buffer, int sock) +{ + char word[MAXLINE], vol[MAXLINE]; + disklist_t *disk = disklist; + char *p = buffer; + auth_t authtype = -1; + int dumplevel = 0; + + while ((p = getword(p, word))) { + if (!strncmp(word, DISK_NAME, sizeof(word))) { + p = getword(p, vol); + if (!p) { + err("NAME without argument"); + return -1; + } + } else if (!strncmp(word, DISK_LEVEL, sizeof(word))) { + p = getword(p, word); + if (!p) { + err("LEVEL command without argument"); + return -1; + } + dumplevel = atoi(word); + } else if (!strncmp(word, DISK_AUTH, sizeof(word))) { + p = getword(p, word); + if (!strncmp(word, AUTH_NOAUTH, sizeof(word))) + authtype = NOAUTH; + else if (!strncmp(word, AUTH_RSH, sizeof(word))) + authtype = RSH; + else { + err("Don't understand auth type `%s'.\n", + word); + return -1; + } + } else { + err("Don't understand DISK field `%s'.\n", word); + return -1; + } + } + + while (disk && strncmp(disk->disk.vol, vol, sizeof(disk->disk.vol))) + disk = disk->next; + + if (!disk) { + err("Disk `%s' not found in diskilst.\n", vol); + return -1; + } + + /* TODO: figure this stuff out. */ + switch (authtype) { + case NOAUTH: { + struct sockaddr_in fa; + int newsock, fromlen = sizeof(fa); + + exit_status = -1; + printf(REQ_ACK "\n"); + fflush(stdout); + + /* + * TODO: for some reason accept doesn't die when the + * sshd does. + */ + setproctitle("Waiting for connection"); + newsock = accept(sock, (struct sockaddr *)&fa, &fromlen); + if (newsock == -1) { + err("Couldn't accept a new connection: %s.\n", + strerror(errno)); + return -1; + } + + if (senddump(newsock, &disk->disk, dumplevel) == -1) + return -1; + }; break; + case RSH: + err("RSH auth currently not supported.\n"); + break; + default: + err("AUTH field has not been set.\n", authtype); + } + + return 0; +} + +int +main(int argc, char *argv[]) +{ + char buffer[MAXLINE]; + disklist_t *disklist; + int sock = 0; + + if (read_config(CLIENT_CONFIG_FILE) == -1) { + err("Couldn't open config file %s: %s.\n", + CLIENT_CONFIG_FILE, strerror(errno)); + return 1; + } + + printf(INIT_REQ "\n"); + fflush(stdout); + + if (fgets(buffer, sizeof(buffer), stdin) == NULL) { + err("NULL input waiting for handshake ACK.\n"); + return 1; + } + + if (strncmp(buffer, INIT_ACK "\n", sizeof(buffer))) { + err("Recieved invalid handshake ACK: %s.", buffer); + return 1; + } + + if (read_dumptypes(DATADIR "/dumptypes") == -1) + return 1; + + disklist = read_disklist(DATADIR "/disklist"); + if (!disklist) + return 1; + + setproctitle("Waiting for instructions"); + while (fgets(buffer, sizeof(buffer), stdin)) { + char word[MAXLINE]; + char *p = buffer; + + p = getword(p, word); + if (!strncmp(word, DUMP_SENDME, sizeof(word))) { + if (do_sendme(disklist, p, sock) == -1) + return 2; + } else if (!strncmp(word, DUMP_DONE, sizeof(word))) + break; + else if (!strncmp(word, PORT_REQ, sizeof(word))) { + sockopt_t opt; + struct sockaddr_in sa; + int port; + + p = getword(p, word); + if (!p) { + err("PORT command without argument.\n"); + return 3; + } + port = atoi(word); + if (!p) { + err("PORT `%s' isn't a number.\n", word); + return 3; + } + + if (!port) + break; + + sock = socket(PF_INET, SOCK_STREAM, 0); + if (!sock) { + err("Couldn't initialize socket: %s.\n", + strerror(errno)); + return 3; + } + + opt = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + &opt, sizeof(opt)) == -1) { + err("Couldn't make socket re-usable: %s.\n", + strerror(errno)); + return 3; + } + + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = INADDR_ANY; + if (bind(sock, (struct sockaddr *)&sa, + sizeof(sa)) == -1) { + err("Couldn't bind to port %d: %s.\n", + port, strerror(errno)); + return 3; + } + + if (listen(sock, 0) == -1) { + err("Couldn't set backlog on socket: %s.\n", + strerror(errno)); + return 3; + } + + printf(REQ_ACK "\n"); + fflush(stdout); + } else { + err("Don't understand command `%s'.\n", word); + return 4; + } + + setproctitle("Waiting for instructions"); + } + + return 0; +} |