X-Git-Url: http://git.vrable.net/?p=cumulus.git;a=blobdiff_plain;f=remote.cc;h=5a20c2301cb026fefbeccb6bfbaef2b11d22e41b;hp=5f04618c89cd31de0e53466e38af4308f4600698;hb=f38dd9bcb0caffd3fc9126b05788c936690e8288;hpb=0dfc70e01ddb7d2bce0db03d5364c0bd3a2bb308 diff --git a/remote.cc b/remote.cc index 5f04618..5a20c23 100644 --- a/remote.cc +++ b/remote.cc @@ -28,6 +28,9 @@ #include #include +#include +#include +#include #include #include #include @@ -38,12 +41,14 @@ #include "remote.h" #include "store.h" +#include "util.h" using std::string; -RemoteStore::RemoteStore(const string &stagedir) +RemoteStore::RemoteStore(const string &stagedir, const string &script) { staging_dir = stagedir; + backup_script = script; /* A background thread is created for each RemoteStore to manage the actual * transfers to a remote server. The main program thread can enqueue @@ -57,7 +62,7 @@ RemoteStore::RemoteStore(const string &stagedir) if (pthread_create(&thread, NULL, RemoteStore::start_transfer_thread, (void *)this) != 0) { fprintf(stderr, "Cannot create remote storage thread: %m\n"); - throw IOException("pthread_create"); + fatal("pthread_create"); } } @@ -86,7 +91,6 @@ RemoteStore::~RemoteStore() * which will upload it to the remote server. */ RemoteFile *RemoteStore::alloc_file(const string &name, const string &type) { - fprintf(stderr, "Allocate file: %s\n", name.c_str()); pthread_mutex_lock(&lock); files_outstanding++; pthread_mutex_unlock(&lock); @@ -100,8 +104,6 @@ RemoteFile *RemoteStore::alloc_file(const string &name, const string &type) * responsible for its destruction. */ void RemoteStore::enqueue(RemoteFile *file) { - fprintf(stderr, "Enqueue: %s\n", file->remote_path.c_str()); - pthread_mutex_lock(&lock); while (transfer_queue.size() >= MAX_QUEUE_SIZE) @@ -118,14 +120,12 @@ void RemoteStore::enqueue(RemoteFile *file) /* Wait for all transfers to finish. */ void RemoteStore::sync() { - fprintf(stderr, "RemoteStore::sync() start\n"); pthread_mutex_lock(&lock); while (busy) pthread_cond_wait(&cond, &lock); pthread_mutex_unlock(&lock); - fprintf(stderr, "RemoteStore::sync() end\n"); } void *RemoteStore::start_transfer_thread(void *arg) @@ -138,6 +138,48 @@ void *RemoteStore::start_transfer_thread(void *arg) /* Background thread for transferring backups to a remote server. */ void RemoteStore::transfer_thread() { + /* If a transfer script was specified, launch it and connect to both stdin + * and stdout. fd_in is stdin of the child, and fd_out is stdout for the + * child. */ + pid_t pid = 0; + FILE *fd_in = NULL, *fd_out = NULL; + + if (backup_script != "") { + int fds[4]; + + if (pipe(&fds[0]) < 0) { + fatal("Unable to create pipe for upload script"); + } + if (pipe(&fds[2]) < 0) { + fatal("Unable to create pipe for upload script"); + } + + pid = fork(); + if (pid < 0) { + fprintf(stderr, "Unable to fork for upload script: %m\n"); + fatal("fork: upload script"); + } + + if (pid > 0) { + /* Parent */ + close(fds[0]); + close(fds[3]); + cloexec(fds[1]); fd_in = fdopen(fds[1], "w"); + cloexec(fds[2]); fd_out = fdopen(fds[2], "r"); + } else if (pid == 0) { + /* Child */ + if (dup2(fds[0], 0) < 0) + exit(1); + if (dup2(fds[3], 1) < 0) + exit(1); + for (int i = 0; i < 3; i++) + close(fds[i]); + + execlp("/bin/sh", "/bin/sh", "-c", backup_script.c_str(), NULL); + fatal("exec failed"); + } + } + while (true) { RemoteFile *file = NULL; @@ -161,37 +203,45 @@ void RemoteStore::transfer_thread() pthread_mutex_unlock(&lock); // Transfer the file - fprintf(stderr, "Start transfer: %s\n", file->remote_path.c_str()); if (backup_script != "") { - pid_t pid = fork(); - if (pid < 0) { - fprintf(stderr, "Unable to fork for upload script: %m\n"); - throw IOException("fork: upload script"); - } - if (pid == 0) { - string cmd = backup_script; - cmd += " " + file->local_path + " " + file->type + " " - + file->remote_path; - execlp("/bin/sh", "/bin/sh", "-c", cmd.c_str(), NULL); - throw IOException("exec failed"); - } + string cmd = "PUT "; + cmd += uri_encode(file->type) + " "; + cmd += uri_encode(file->remote_path) + " "; + cmd += uri_encode(file->local_path) + "\n"; - int status = 0; - waitpid(pid, &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - fprintf(stderr, "Warning: error code from upload script: %d\n", - status); - } + fputs(cmd.c_str(), fd_in); + fflush(fd_in); + + char *resp = NULL; + size_t n; + if (getline(&resp, &n, fd_out) < 0 || resp == NULL) + fatal("error reading response from upload script"); + if (strchr(resp, '\n')) + *strchr(resp, '\n') = '\0'; + if (strcmp(resp, "OK") != 0) + fatal("error response from upload script"); if (unlink(file->local_path.c_str()) < 0) { fprintf(stderr, "Warning: Deleting temporary file %s: %m\n", file->local_path.c_str()); } } - fprintf(stderr, "Finish transfer: %s\n", file->remote_path.c_str()); delete file; } + + if (fd_in) fclose(fd_in); + + if (pid) { + int status = 0; + waitpid(pid, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + fprintf(stderr, "Warning: error code from upload script: %d\n", + status); + } + } + + if (fd_out) fclose(fd_out); } RemoteFile::RemoteFile(RemoteStore *remote, @@ -205,5 +255,5 @@ RemoteFile::RemoteFile(RemoteStore *remote, fd = open(local_path.c_str(), O_WRONLY | O_CREAT, 0666); if (fd < 0) - throw IOException("Error opening output file"); + fatal("Error opening output file"); }