aboutsummaryrefslogtreecommitdiff
path: root/rcynic-ng/rcynic.c
diff options
context:
space:
mode:
Diffstat (limited to 'rcynic-ng/rcynic.c')
-rw-r--r--rcynic-ng/rcynic.c187
1 files changed, 170 insertions, 17 deletions
diff --git a/rcynic-ng/rcynic.c b/rcynic-ng/rcynic.c
index 998f6de9..11894248 100644
--- a/rcynic-ng/rcynic.c
+++ b/rcynic-ng/rcynic.c
@@ -356,21 +356,7 @@ typedef struct certinfo {
uri_t uri, sia, aia, crldp, manifest;
} certinfo_t;
-/**
- * Program context that would otherwise be a mess of global variables.
- */
-typedef struct rcynic_ctx {
- path_t authenticated, old_authenticated, unauthenticated;
- char *jane, *rsync_program;
- STACK_OF(OPENSSL_STRING) *rsync_cache, *backup_cache, *stale_cache;
- STACK_OF(HOST_MIB_COUNTER) *host_counters;
- STACK_OF(VALIDATION_STATUS) *validation_status;
- int indent, use_syslog, allow_stale_crl, allow_stale_manifest, use_links;
- int require_crl_in_manifest, rsync_timeout, priority[LOG_LEVEL_T_MAX];
- int allow_non_self_signed_trust_anchor, allow_object_not_in_manifest;
- log_level_t log_level;
- X509_STORE *x509_store;
-} rcynic_ctx_t;
+typedef struct rcynic_ctx rcynic_ctx_t;
/**
* States that a walk_ctx_t can be in.
@@ -430,6 +416,22 @@ typedef struct rcynic_x509_store_ctx {
const certinfo_t *subject;
} rcynic_x509_store_ctx_t;
+/**
+ * Program context that would otherwise be a mess of global variables.
+ */
+struct rcynic_ctx {
+ path_t authenticated, old_authenticated, unauthenticated;
+ char *jane, *rsync_program;
+ STACK_OF(OPENSSL_STRING) *rsync_cache, *backup_cache, *stale_cache;
+ STACK_OF(HOST_MIB_COUNTER) *host_counters;
+ STACK_OF(VALIDATION_STATUS) *validation_status;
+ STACK_OF(rsync_ctx_t) *rsync_queue;
+ int indent, use_syslog, allow_stale_crl, allow_stale_manifest, use_links;
+ int require_crl_in_manifest, rsync_timeout, priority[LOG_LEVEL_T_MAX];
+ int allow_non_self_signed_trust_anchor, allow_object_not_in_manifest;
+ log_level_t log_level;
+ X509_STORE *x509_store;
+};
/**
@@ -1463,6 +1465,156 @@ typedef enum {
} rsync_status_t;
/**
+ * Manager for queue of rsync tasks in progress.
+ *
+ * General plan here is to process one completed child, or output has
+ * accumulated from children, or block if there is absolutely nothing
+ * to do, on the theory that caller had nothing to do either or would
+ * not have called us. Once we've done something allegedly useful, we
+ * return, because this is not the event loop; if and when the event
+ * loop has nothing more important to do, we'll be called again.
+ *
+ * So this is the only place where the program blocks waiting for
+ * children, but we only do it when we know there's nothing else
+ * useful that we could be doing while we wait.
+ */
+static void rsync_mgr(const rcynic_ctx_t *rc)
+{
+ char *s, *b, buffer[URI_MAX * 4];
+ rsync_ctx_t *ctx = NULL;
+ int i, n, pid_status = -1;
+ time_t now = time(0);
+ struct timeval tv;
+ fd_set rfds;
+ pid_t pid;
+
+ assert(rc && rc->rsync_queue);
+
+ while ((pid = waitpid(-1, &pid_status, WNOHANG)) == -1 && errno == EINTR)
+ ;
+
+ switch (pid) {
+
+ case -1:
+ /*
+ * Not sure what to do here, for now just return.
+ */
+ logmsg(rc, log_sys_err, "waitpid() returned error: %s", strerror(errno));
+ return;
+
+ case 0:
+ /*
+ * No children are ready to exit, continue to select() check.
+ */
+ break;
+
+ default:
+ /*
+ * Child exited, handle that and return
+ */
+ for (i = 0; (ctx = sk_rsync_ctx_t_value(rc->rsync_queue, i)) != NULL; ++i)
+ if (ctx->pid == pid)
+ break;
+ if (ctx == NULL) {
+ logmsg(rc, log_sys_err, "Couldn't find rsync context for pid %d", pid);
+ return;
+ }
+
+
+ close(ctx->pipe_fds[0]);
+
+ assert(i >= 0 && i < sizeof(buffer));
+ if (i) {
+ buffer[i] = '\0';
+ logmsg(rc, log_telemetry, "%s", buffer);
+ }
+
+ if (n < 0 && errno != EAGAIN)
+ logmsg(rc, log_sys_err, "Problem reading rsync's output: %s",
+ strerror(errno));
+
+ if (rc->rsync_timeout && now >= ctx->deadline)
+ logmsg(rc, log_data_err,
+ "Fetch of %s took longer than %d seconds, terminating fetch",
+ ctx->uri.s, rc->rsync_timeout);
+
+ assert(ctx->pid > 0);
+ for (i = 0; i < KILL_MAX && pid == 0; i++) {
+ if ((pid = waitpid(ctx->pid, &pid_status, WNOHANG)) != 0 && WIFEXITED(pid_status))
+ break;
+ kill(ctx->pid, SIGTERM);
+ sleep(1);
+ }
+
+ if (WEXITSTATUS(pid_status)) {
+ logmsg(rc, log_data_err, "rsync exited with status %d fetching %s",
+ WEXITSTATUS(pid_status), ctx->uri.s);
+ mib_increment(rc, &ctx->uri, (rc->rsync_timeout && now >= ctx->deadline
+ ? rsync_timed_out
+ : rsync_failed));
+ } else {
+ mib_increment(rc, &ctx->uri, rsync_succeeded);
+ }
+
+ assert(strlen(ctx->uri.s) > SIZEOF_RSYNC);
+ strcpy(buffer, ctx->uri.s + SIZEOF_RSYNC);
+ if ((s = strrchr(buffer, '/')) != NULL && s[1] == '\0')
+ *s = '\0';
+ if (!sk_OPENSSL_STRING_push_strdup(rc->rsync_cache, buffer))
+ logmsg(rc, log_sys_err, "Couldn't cache URI %s, blundering onward", ctx->uri.s);
+
+ }
+
+ /*
+ * Somewhere we have to deal with timing out children that have been
+ * running too long.
+ */
+
+ /* Unconverted code below here */
+
+ n = -1;
+ i = 0;
+ while ((pid = waitpid(-1, &pid_status, WNOHANG)) == 0 &&
+ (!rc->rsync_timeout || (now = time(0)) < ctx->deadline)) {
+ FD_ZERO(&rfds);
+ FD_SET(ctx->pipe_fds[0], &rfds);
+ if (rc->rsync_timeout) {
+ tv.tv_sec = ctx->deadline - now;
+ tv.tv_usec = 0;
+ n = select(ctx->pipe_fds[0] + 1, &rfds, NULL, NULL, &tv);
+ } else {
+ n = select(ctx->pipe_fds[0] + 1, &rfds, NULL, NULL, NULL);
+ }
+ if (n == 0 || (n < 0 && errno == EINTR))
+ continue;
+ if (n < 0)
+ break;
+ while ((n = read(ctx->pipe_fds[0], buffer + i, sizeof(buffer) - i - 1)) > 0) {
+ n += i;
+ assert(n < sizeof(buffer));
+ buffer[n] = '\0';
+ for (b = buffer; (s = strchr(b, '\n')) != NULL; b = s) {
+ *s++ = '\0';
+ logmsg(rc, log_telemetry, "%s", b);
+ }
+ i = strlen(b);
+ assert(i < sizeof(buffer) && b + i < buffer + sizeof(buffer));
+ if (b == buffer && i == sizeof(buffer) - 1) {
+ logmsg(rc, log_telemetry, "%s\\", b);
+ i = 0;
+ }
+ if (i > 0) {
+ memmove(buffer, b, i);
+ }
+ }
+ if (n == 0 || (n < 0 && errno != EAGAIN))
+ break;
+ }
+
+ return;
+}
+
+/**
* Run rsync. This is fairly nasty, because we need to:
*
* @li Construct the argument list for rsync;
@@ -1599,7 +1751,7 @@ static rsync_status_t rsync(const rcynic_ctx_t *rc,
n = -1;
i = 0;
- while ((wpid = waitpid(ctx->pid, &pid_status, WNOHANG)) == 0 &&
+ while ((wpid = waitpid(-1, &pid_status, WNOHANG)) == 0 &&
(!rc->rsync_timeout || (now = time(0)) < ctx->deadline)) {
FD_ZERO(&rfds);
FD_SET(ctx->pipe_fds[0], &rfds);
@@ -1655,9 +1807,10 @@ static rsync_status_t rsync(const rcynic_ctx_t *rc,
assert(ctx->pid > 0);
for (i = 0; i < KILL_MAX && wpid == 0; i++) {
- if ((wpid = waitpid(ctx->pid, &pid_status, 0)) != 0 && WIFEXITED(pid_status))
+ if ((wpid = waitpid(ctx->pid, &pid_status, WNOHANG)) != 0 && WIFEXITED(pid_status))
break;
kill(ctx->pid, SIGTERM);
+ sleep(1);
}
if (WEXITSTATUS(pid_status)) {