Quellcode durchsuchen

system: BProcess: add setsid option. ncd: modules: runonce: add setsid option

ambrop7 vor 14 Jahren
Ursprung
Commit
587751adfb
3 geänderte Dateien mit 71 neuen und 12 gelöschten Zeilen
  1. 12 1
      ncd/modules/runonce.c
  2. 27 11
      system/BProcess.c
  3. 32 0
      system/BProcess.h

+ 12 - 1
ncd/modules/runonce.c

@@ -187,6 +187,7 @@ static void func_new (NCDModuleInst *i)
     
     int keep_stdout = 0;
     int keep_stderr = 0;
+    int do_setsid = 0;
     
     // read options
     for (NCDValue *opt = (opts_arg ? NCDValue_ListFirst(opts_arg) : NULL); opt; opt = NCDValue_ListNext(opts_arg, opt)) {
@@ -206,6 +207,9 @@ static void func_new (NCDModuleInst *i)
         else if (!strcmp(optname, "keep_stderr")) {
             keep_stderr = 1;
         }
+        else if (!strcmp(optname, "do_setsid")) {
+            do_setsid = 1;
+        }
         else {
             ModuleLog(o->i, BLOG_ERROR, "unknown option name");
             goto fail1;
@@ -233,8 +237,15 @@ static void func_new (NCDModuleInst *i)
     }
     fds[nfds] = -1;
     
+    // build params
+    struct BProcess_params params;
+    params.username = NULL;
+    params.fds = fds;
+    params.fds_map = fds_map;
+    params.do_setsid = do_setsid;
+    
     // start process
-    if (!BProcess_InitWithFds(&o->process, o->i->params->manager, (BProcess_handler)process_handler, o, exec, CmdLine_Get(&cl), NULL, fds, fds_map)) {
+    if (!BProcess_Init2(&o->process, o->i->params->manager, (BProcess_handler)process_handler, o, exec, CmdLine_Get(&cl), params)) {
         ModuleLog(i, BLOG_ERROR, "BProcess_Init failed");
         CmdLine_Free(&cl);
         free(exec);

+ 27 - 11
system/BProcess.c

@@ -185,7 +185,7 @@ static int fds_contains (const int *fds, int fd, size_t *pos)
     return 0;
 }
 
-int BProcess_InitWithFds (BProcess *o, BProcessManager *m, BProcess_handler handler, void *user, const char *file, char *const argv[], const char *username, const int *fds, const int *fds_map)
+int BProcess_Init2 (BProcess *o, BProcessManager *m, BProcess_handler handler, void *user, const char *file, char *const argv[], struct BProcess_params params)
 {
     // init arguments
     o->m = m;
@@ -194,7 +194,7 @@ int BProcess_InitWithFds (BProcess *o, BProcessManager *m, BProcess_handler hand
     
     // count fds
     size_t num_fds;
-    for (num_fds = 0; fds[num_fds] >= 0; num_fds++);
+    for (num_fds = 0; params.fds[num_fds] >= 0; num_fds++);
     
     // block signals
     // needed to prevent parent's signal handlers from being called
@@ -234,7 +234,7 @@ int BProcess_InitWithFds (BProcess *o, BProcessManager *m, BProcess_handler hand
         if (!fds2) {
             abort();
         }
-        memcpy(fds2, fds, (num_fds + 1) * sizeof(fds2[0]));
+        memcpy(fds2, params.fds, (num_fds + 1) * sizeof(fds2[0]));
         
         // find maximum file descriptors
         int max_fd = sysconf(_SC_OPEN_MAX);
@@ -252,13 +252,13 @@ int BProcess_InitWithFds (BProcess *o, BProcessManager *m, BProcess_handler hand
             close(i);
         }
         
-        const int *orig_fds_map = fds_map;
+        const int *orig_fds_map = params.fds_map;
         
         // map fds to requested fd numbers
         while (*fds2 >= 0) {
             // resolve possible conflict
             size_t cpos;
-            if (fds_contains(fds2 + 1, *fds_map, &cpos)) {
+            if (fds_contains(fds2 + 1, *params.fds_map, &cpos)) {
                 // dup() the fd to a new number; the old one will be closed
                 // in the following dup2()
                 if ((fds2[1 + cpos] = dup(fds2[1 + cpos])) < 0) {
@@ -266,9 +266,9 @@ int BProcess_InitWithFds (BProcess *o, BProcessManager *m, BProcess_handler hand
                 }
             }
             
-            if (*fds2 != *fds_map) {
+            if (*fds2 != *params.fds_map) {
                 // dup fd
-                if (dup2(*fds2, *fds_map) < 0) {
+                if (dup2(*fds2, *params.fds_map) < 0) {
                     abort();
                 }
                 
@@ -277,14 +277,19 @@ int BProcess_InitWithFds (BProcess *o, BProcessManager *m, BProcess_handler hand
             }
             
             fds2++;
-            fds_map++;
+            params.fds_map++;
         }
         
         // make sure standard streams are open
         open_standard_streams();
         
+        // make session leader if requested
+        if (params.do_setsid) {
+            setsid();
+        }
+        
         // assume identity of username, if requested
-        if (username) {
+        if (params.username) {
             long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
             if (bufsize < 0) {
                 bufsize = 16384;
@@ -297,12 +302,12 @@ int BProcess_InitWithFds (BProcess *o, BProcessManager *m, BProcess_handler hand
             
             struct passwd pwd;
             struct passwd *res;
-            getpwnam_r(username, &pwd, buf, bufsize, &res);
+            getpwnam_r(params.username, &pwd, buf, bufsize, &res);
             if (!res) {
                 abort();
             }
             
-            if (initgroups(username, pwd.pw_gid) < 0) {
+            if (initgroups(params.username, pwd.pw_gid) < 0) {
                 abort();
             }
             
@@ -343,6 +348,17 @@ fail0:
     return 0;
 }
 
+int BProcess_InitWithFds (BProcess *o, BProcessManager *m, BProcess_handler handler, void *user, const char *file, char *const argv[], const char *username, const int *fds, const int *fds_map)
+{
+    struct BProcess_params params;
+    params.username = username;
+    params.fds = fds;
+    params.fds_map = fds_map;
+    params.do_setsid = 0;
+    
+    return BProcess_Init2(o, m, handler, user, file, argv, params);
+}
+
 int BProcess_Init (BProcess *o, BProcessManager *m, BProcess_handler handler, void *user, const char *file, char *const argv[], const char *username)
 {
     int fds[] = {-1};

+ 32 - 0
system/BProcess.h

@@ -98,6 +98,38 @@ int BProcessManager_Init (BProcessManager *o, BReactor *reactor) WARN_UNUSED;
  */
 void BProcessManager_Free (BProcessManager *o);
 
+struct BProcess_params {
+    const char *username;
+    const int *fds;
+    const int *fds_map;
+    int do_setsid;
+};
+
+/**
+ * Initializes the process.
+ * 'file', 'argv', 'username', 'fds' and 'fds_map' arguments are only used during this
+ * function call.
+ * If no file descriptor is mapped to a standard stream (file descriptors 0, 1, 2),
+ * then /dev/null will be opened in the child for that standard stream.
+ * 
+ * @param o the object
+ * @param m process manager
+ * @param handler handler called when the process terminates
+ * @param user argument to handler
+ * @param file path to executable file
+ * @param argv arguments array, including the zeroth argument, terminated with a NULL pointer
+ * @param params.username user account to run the program as, or NULL to not switch user
+ * @param params.fds array of file descriptors in the parent to map to file descriptors in the child,
+ *            terminated with -1
+ * @param params.fds_map array of file descriptors in the child that file descriptors in 'fds' will
+ *                be mapped to, in the same order. Must contain the same number of file descriptors
+ *                as the 'fds' argument, and does not have to be terminated with -1.
+ * @param params.do_setsid if set to non-zero, will make the child call setsid() before exec'ing.
+ *                         Failure of setsid() will be ignored.
+ * @return 1 on success, 0 on failure
+ */
+int BProcess_Init2 (BProcess *o, BProcessManager *m, BProcess_handler handler, void *user, const char *file, char *const argv[], struct BProcess_params params) WARN_UNUSED;
+
 /**
  * Initializes the process.
  * 'file', 'argv', 'username', 'fds' and 'fds_map' arguments are only used during this