#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?! */
* 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
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(),
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;
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;
}
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
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);
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.
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);