]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Increment the semaphore in the child process too
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 28 Apr 2021 14:20:28 +0000 (09:20 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 28 Apr 2021 14:20:44 +0000 (09:20 -0500)
src/bin/radiusd.c
src/lib/server/main_config.c
src/lib/server/main_config.h
src/lib/util/sem.c
src/lib/util/sem.h

index 5a502b95e5f230ac99c9cf3188d364bcb913d8b2..24465996d17936a982ff8caec30a501f11e25f18 100644 (file)
@@ -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?! */
index f6a12ac76e5f911fe6aaf310151c37ac2c083ed6..de9c4b7384cc37b9a3b00daa0330f0469d98de67 100644 (file)
@@ -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;
 }
index f3ef714f7d07ec8ff09378e942fb6c799034e1eb..b119c2be21876abe22af1a1c33972fd597e0a1ad 100644 (file)
@@ -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);
index e1384db1c157ba05e1cf561b88ab48f2284e6323..ff76753e873ec4243d48112758db8fa1da357d5e 100644 (file)
@@ -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.
index bfce6b034d5934ffea9c487e64ffe3b85eba1c7d..33e097f671f7734d27ed5584a9dfbb1c026eb001 100644 (file)
@@ -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);