From: Arran Cudbard-Bell Date: Wed, 28 Apr 2021 14:20:28 +0000 (-0500) Subject: Increment the semaphore in the child process too X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d938f1288684f0ee724cdbfdc6fee6ad615fd65f;p=thirdparty%2Ffreeradius-server.git Increment the semaphore in the child process too --- diff --git a/src/bin/radiusd.c b/src/bin/radiusd.c index 5a502b95e5f..24465996d17 100644 --- a/src/bin/radiusd.c +++ b/src/bin/radiusd.c @@ -712,6 +712,14 @@ int main(int argc, char *argv[]) #endif goto cleanup; + /* + * The child needs to increment the semaphore as the parent + * is going to exit, and it will decrement the semaphore. + */ + } else if (pid == 0) { + if (main_config_exclusive_proc_child(main_config) < 0) { + PWARN("%s - Failed incrementing exclusive proc semaphore in child", program); + } } /* so the pipe is correctly widowed if the parent exits?! */ diff --git a/src/lib/server/main_config.c b/src/lib/server/main_config.c index f6a12ac76e5..de9c4b7384c 100644 --- a/src/lib/server/main_config.c +++ b/src/lib/server/main_config.c @@ -826,9 +826,21 @@ void main_config_raddb_dir_set(main_config_t *config, char const *name) * running the process under something like systemd and running it under * debug mode. */ -void main_config_exclusive_proc_done(main_config_t *config) +void main_config_exclusive_proc_done(main_config_t const *config) { - fr_sem_close(config->multi_proc_sem_id, NULL); + if (config->multi_proc_sem_id >= 0) fr_sem_close(config->multi_proc_sem_id, NULL); +} + +/** Increment the semaphore in the child process so that it's not released when the parent exits + * + * @param[in] config specifying the path to the main config file. + * @return + * - 0 on success. + * - -1 on failure. + */ +int main_config_exclusive_proc_child(main_config_t const *config) +{ + return fr_sem_take(config->multi_proc_sem_id, config->multi_proc_sem_path, true); } /** Check to see if we're the only process using this configuration file @@ -848,7 +860,7 @@ int main_config_exclusive_proc(main_config_t *config) if (unlikely(sem_initd)) return 0; - MEM(path = talloc_asprintf(NULL, "%s/%s.conf", config->raddb_dir, config->name)); + MEM(path = talloc_asprintf(config, "%s/%s.conf", config->raddb_dir, config->name)); sem_id = fr_sem_get(path, 0, main_config->uid_is_set ? main_config->uid : geteuid(), main_config->gid_is_set ? main_config->gid : getegid(), @@ -858,10 +870,13 @@ int main_config_exclusive_proc(main_config_t *config) return -1; } + config->multi_proc_sem_id = -1; + ret = fr_sem_wait(sem_id, path, true, true); switch (ret) { case 0: /* we have the semaphore */ config->multi_proc_sem_id = sem_id; + config->multi_proc_sem_path = path; sem_initd = true; break; @@ -871,10 +886,15 @@ int main_config_exclusive_proc(main_config_t *config) fr_sem_pid(&pid, sem_id); fr_strerror_printf("Refusing to start - PID %u already running with \"%s\"", pid, path); + talloc_free(path); } break; + + default: + talloc_free(path); + break; } - talloc_free(path); + return ret; } diff --git a/src/lib/server/main_config.h b/src/lib/server/main_config.h index f3ef714f7d0..b119c2be218 100644 --- a/src/lib/server/main_config.h +++ b/src/lib/server/main_config.h @@ -136,6 +136,7 @@ struct main_config_s { bool allow_multiple_procs; //!< Allow multiple instances of radiusd to run with the ///< same config file. unsigned int multi_proc_sem_id; //!< Semaphore we use to prevent multiple processes running. + char *multi_proc_sem_path; //!< Semaphore path. uint32_t max_networks; //!< for the scheduler uint32_t max_workers; //!< for the scheduler @@ -148,6 +149,7 @@ void main_config_raddb_dir_set(main_config_t *config, char const *path); void main_config_dict_dir_set(main_config_t *config, char const *path); void main_config_exclusive_proc_done(main_config_t const *config); +int main_config_exclusive_proc_child(main_config_t const *config); int main_config_exclusive_proc(main_config_t *config); main_config_t *main_config_alloc(TALLOC_CTX *ctx); diff --git a/src/lib/util/sem.c b/src/lib/util/sem.c index e1384db1c15..ff76753e873 100644 --- a/src/lib/util/sem.c +++ b/src/lib/util/sem.c @@ -163,6 +163,32 @@ int fr_sem_cgid(uid_t *gid, int sem_id) return 0; } +/** Increment the semaphore by 1 + * + * @param[in] sem_id to take. + * @param[in] file to use in error messages. + * @param[in] undo_on_exit decrement the semaphore on exit. + * @return + * - -1 on failure. + * - 0 on success. + */ +int fr_sem_take(int sem_id, char const *file, bool undo_on_exit) +{ + struct sembuf sop = { + .sem_num = 0, + .sem_op = 1, + .sem_flg = undo_on_exit * SEM_UNDO + }; + + if (semop(sem_id, &sop, 1) < 0) { + fr_strerror_printf("Failed waiting on semaphore bound to \"%s\" - %s", file, + fr_syserror(errno)); + return -1; + } + + return 0; +} + /** Wait for a semaphore to reach 0, then increment it by 1 * * @param[in] sem_id to operate on. diff --git a/src/lib/util/sem.h b/src/lib/util/sem.h index bfce6b034d5..33e097f671f 100644 --- a/src/lib/util/sem.h +++ b/src/lib/util/sem.h @@ -38,6 +38,8 @@ int fr_sem_cuid(uid_t *uid, int sem_id); int fr_sem_cgid(gid_t *gid, int sem_id); +int fr_sem_take(int sem_id, char const *file, bool undo_on_exit); + int fr_sem_wait(int sem_id, char const *file, bool undo_on_exit, bool nonblock); int fr_sem_close(int sem_id, char const *file);