+ OPENSSL_free(thost);
+ OPENSSL_free(tport);
+ OPENSSL_free(tpath);
+
+ return ret;
+}
+
+static void
+log_message(int level, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+#ifdef OCSP_DAEMON
+ if (multi) {
+ char buf[1024];
+ if (vsnprintf(buf, sizeof(buf), fmt, ap) > 0) {
+ syslog(level, "%s", buf);
+ }
+ if (level >= LOG_ERR)
+ ERR_print_errors_cb(print_syslog, &level);
+ }
+#endif
+ if (!multi) {
+ BIO_printf(bio_err, "%s: ", prog);
+ BIO_vprintf(bio_err, fmt, ap);
+ BIO_printf(bio_err, "\n");
+ }
+ va_end(ap);
+}
+
+#ifdef OCSP_DAEMON
+
+static int print_syslog(const char *str, size_t len, void *levPtr)
+{
+ int level = *(int *)levPtr;
+ int ilen = (len > MAXERRLEN) ? MAXERRLEN : len;
+
+ syslog(level, "%.*s", ilen, str);
+
+ return ilen;
+}
+
+static int index_changed(CA_DB *rdb)
+{
+ struct stat sb;
+
+ if (rdb != NULL && stat(rdb->dbfname, &sb) != -1) {
+ if (rdb->dbst.st_mtime != sb.st_mtime
+ || rdb->dbst.st_ctime != sb.st_ctime
+ || rdb->dbst.st_ino != sb.st_ino
+ || rdb->dbst.st_dev != sb.st_dev) {
+ syslog(LOG_INFO, "index file changed, reloading");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void killall(int ret, pid_t *kidpids)
+{
+ int i;
+
+ for (i = 0; i < multi; ++i)
+ if (kidpids[i] != 0)
+ (void)kill(kidpids[i], SIGTERM);
+ OPENSSL_free(kidpids);
+ sleep(1);
+ exit(ret);
+}
+
+static int termsig = 0;
+
+static void noteterm (int sig)
+{
+ termsig = sig;
+}
+
+/*
+ * Loop spawning up to `multi` child processes, only child processes return
+ * from this function. The parent process loops until receiving a termination
+ * signal, kills extant children and exits without returning.
+ */
+static void spawn_loop(void)
+{
+ pid_t *kidpids = NULL;
+ int status;
+ int procs = 0;
+ int i;
+
+ openlog(prog, LOG_PID, LOG_DAEMON);
+
+ if (setpgid(0, 0)) {
+ syslog(LOG_ERR, "fatal: error detaching from parent process group: %s",
+ strerror(errno));
+ exit(1);
+ }
+ kidpids = app_malloc(multi * sizeof(*kidpids), "child PID array");
+ for (i = 0; i < multi; ++i)
+ kidpids[i] = 0;
+
+ signal(SIGINT, noteterm);
+ signal(SIGTERM, noteterm);
+
+ while (termsig == 0) {
+ pid_t fpid;
+
+ /*
+ * Wait for a child to replace when we're at the limit.
+ * Slow down if a child exited abnormally or waitpid() < 0
+ */
+ while (termsig == 0 && procs >= multi) {
+ if ((fpid = waitpid(-1, &status, 0)) > 0) {
+ for (i = 0; i < procs; ++i) {
+ if (kidpids[i] == fpid) {
+ kidpids[i] = 0;
+ --procs;
+ break;
+ }
+ }
+ if (i >= multi) {
+ syslog(LOG_ERR, "fatal: internal error: "
+ "no matching child slot for pid: %ld",
+ (long) fpid);
+ killall(1, kidpids);
+ }
+ if (status != 0) {
+ if (WIFEXITED(status))
+ syslog(LOG_WARNING, "child process: %ld, exit status: %d",
+ (long)fpid, WEXITSTATUS(status));
+ else if (WIFSIGNALED(status))
+ syslog(LOG_WARNING, "child process: %ld, term signal %d%s",
+ (long)fpid, WTERMSIG(status),
+#ifdef WCOREDUMP
+ WCOREDUMP(status) ? " (core dumped)" :
+#endif
+ "");
+ sleep(1);
+ }
+ break;
+ } else if (errno != EINTR) {
+ syslog(LOG_ERR, "fatal: waitpid(): %s", strerror(errno));
+ killall(1, kidpids);
+ }
+ }
+ if (termsig)
+ break;