Sfoglia il codice sorgente

ncd: implement interface for modules to initiate interpreter termination and read extra command line arguments

ambrop7 14 anni fa
parent
commit
dd478b1a94
3 ha cambiato i file con 142 aggiunte e 4 eliminazioni
  1. 28 0
      ncd/NCDModule.c
  2. 50 0
      ncd/NCDModule.h
  3. 64 4
      ncd/ncd.c

+ 28 - 0
ncd/NCDModule.c

@@ -156,6 +156,13 @@ static void process_event_job_handler (NCDModuleProcess *o)
     }
 }
 
+static void inst_assert_backend (NCDModuleInst *n)
+{
+    ASSERT(n->state == STATE_DOWN_PCLEAN || n->state == STATE_DOWN_UNCLEAN || n->state == STATE_DOWN_CLEAN ||
+           n->state == STATE_UP || n->state == STATE_DOWN_DIE || n->state == STATE_UP_DIE ||
+           n->state == STATE_DYING)
+}
+
 void NCDModuleInst_Init (NCDModuleInst *n, const struct NCDModule *m, const NCDObject *method_object, NCDValue *args, void *user, const struct NCDModuleInst_params *params)
 {
     ASSERT(m)
@@ -436,6 +443,27 @@ void NCDModuleInst_Backend_SetError (NCDModuleInst *n)
     n->is_error = 1;
 }
 
+void NCDModuleInst_Backend_InterpExit (NCDModuleInst *n, int exit_code)
+{
+    DebugObject_Access(&n->d_obj);
+    inst_assert_backend(n);
+    
+    n->params->func_interp_exit(n->user, exit_code);
+}
+
+int NCDModuleInst_Backend_InterpGetArgs (NCDModuleInst *n, NCDValue *out_value)
+{
+    DebugObject_Access(&n->d_obj);
+    inst_assert_backend(n);
+    ASSERT(out_value)
+    
+    int res = n->params->func_interp_getargs(n->user, out_value);
+    ASSERT(res == 0 || res == 1)
+    ASSERT(!res || (NCDValue_Type(out_value), 1))
+    
+    return res;
+}
+
 int NCDModuleProcess_Init (NCDModuleProcess *o, NCDModuleInst *n, const char *template_name, NCDValue args, void *user, NCDModuleProcess_handler_event handler_event)
 {
     DebugObject_Access(&n->d_obj);

+ 50 - 0
ncd/NCDModule.h

@@ -109,6 +109,29 @@ typedef int (*NCDModuleInst_func_getobj) (void *user, const char *name, NCDObjec
  */
 typedef int (*NCDModuleInst_func_initprocess) (void *user, struct NCDModuleProcess_s *p, const char *template_name);
 
+/**
+ * Function called when the module instance wants the interpreter to
+ * initiate termination, as if it received an external terminatio request (signal).
+ * 
+ * @param user as in {@link NCDModuleInst_Init}
+ * @param exit_code exit code to return the the operating system. This overrides any previously
+ *                  set exit code, and will be overriden by a signal to the value 1.
+ *   
+ */
+typedef void (*NCDModuleInst_func_interp_exit) (void *user, int exit_code);
+
+/**
+ * Function called when the module instance wants the interpreter to
+ * provide its extra command line arguments.
+ * 
+ * @param user as in {@link NCDModuleInst_Init}
+ * @param out_value on success, the interpreter will write the list of extra command
+ *                  line arguments here
+ * @return 1 on success, 0 on failure
+ *   
+ */
+typedef int (*NCDModuleInst_func_interp_getargs) (void *user, NCDValue *out_value);
+
 #define NCDMODULEPROCESS_EVENT_UP 1
 #define NCDMODULEPROCESS_EVENT_DOWN 2
 #define NCDMODULEPROCESS_EVENT_TERMINATED 3
@@ -228,6 +251,14 @@ struct NCDModuleInst_params {
      * Log function which appends a log prefix with {@link BLog_Append}.
      */
     BLog_logfunc logfunc;
+    /**
+     * Callback to request interpreter termination.
+     */
+    NCDModuleInst_func_interp_exit func_interp_exit;
+    /**
+     * Callback to get extra command line arguments.
+     */
+    NCDModuleInst_func_interp_getargs func_interp_getargs;
 };
 
 /**
@@ -401,6 +432,25 @@ void NCDModuleInst_Backend_Log (NCDModuleInst *n, int channel, int level, const
  */
 void NCDModuleInst_Backend_SetError (NCDModuleInst *n);
 
+/**
+ * Initiates interpreter termination.
+ * 
+ * @param n backend instance handle
+ * @param exit_code exit code to return to the operating system. This overrides
+ *                  any previously set exit code, and will be overriden by a
+ *                  termination signal to the value 1.
+ */
+void NCDModuleInst_Backend_InterpExit (NCDModuleInst *n, int exit_code);
+
+/**
+ * Retrieves extra command line arguments passed to the interpreter.
+ * 
+ * @param n backend instance handle
+ * @param out_value the arguments will be written here on success as a list value
+ * @return 1 on success, 0 on failure
+ */
+int NCDModuleInst_Backend_InterpGetArgs (NCDModuleInst *n, NCDValue *out_value);
+
 /**
  * Initializes a process in the interpreter from a process template.
  * This must be called on behalf of a module backend instance.

+ 64 - 4
ncd/ncd.c

@@ -150,6 +150,8 @@ struct {
     char *config_file;
     int retry_time;
     int no_udev;
+    char **extra_args;
+    int num_extra_args;
 } options;
 
 // reactor
@@ -157,6 +159,7 @@ BReactor ss;
 
 // are we terminating
 int terminating;
+int main_exit_code;
 
 // process manager
 BProcessManager manager;
@@ -180,6 +183,7 @@ static void print_help (const char *name);
 static void print_version (void);
 static int parse_arguments (int argc, char *argv[]);
 static void signal_handler (void *unused);
+static void start_terminate (int exit_code);
 static int arg_value_init_string (struct arg_value *o, const char *string);
 static int arg_value_init_variable (struct arg_value *o, struct NCDConfig_strings *ast_names);
 static void arg_value_init_list (struct arg_value *o);
@@ -219,6 +223,8 @@ static void process_statement_instance_func_event (struct process_statement *ps,
 static int process_statement_instance_func_getobj (struct process_statement *ps, const char *objname, NCDObject *out_object);
 static int process_statement_instance_func_initprocess (struct process_statement *ps, NCDModuleProcess *mp, const char *template_name);
 static void process_statement_instance_logfunc (struct process_statement *ps);
+static void process_statement_instance_func_interp_exit (struct process_statement *ps, int exit_code);
+static int process_statement_instance_func_interp_getargs (struct process_statement *ps, NCDValue *out_value);
 static void process_moduleprocess_func_event (struct process *p, int event);
 static int process_moduleprocess_func_getobj (struct process *p, const char *name, NCDObject *out_object);
 
@@ -228,6 +234,9 @@ int main (int argc, char **argv)
         return 1;
     }
     
+    // set exit code
+    main_exit_code = 1;
+    
     // open standard streams
     open_standard_streams();
     
@@ -364,6 +373,8 @@ int main (int argc, char **argv)
     module_params.func_getobj = (NCDModuleInst_func_getobj)process_statement_instance_func_getobj;
     module_params.func_initprocess = (NCDModuleInst_func_initprocess)process_statement_instance_func_initprocess;
     module_params.logfunc = (BLog_logfunc)process_statement_instance_logfunc;
+    module_params.func_interp_exit = (NCDModuleInst_func_interp_exit)process_statement_instance_func_interp_exit;
+    module_params.func_interp_getargs = (NCDModuleInst_func_interp_getargs)process_statement_instance_func_interp_getargs;
     
     // init processes list
     LinkedList2_Init(&processes);
@@ -417,7 +428,7 @@ fail0:
     // finish objects
     DebugObjectGlobal_Finish();
     
-    return 1;
+    return main_exit_code;
 }
 
 void print_help (const char *name)
@@ -438,7 +449,8 @@ void print_help (const char *name)
         "        [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n"
         "        --config-file <file>\n"
         "        [--retry-time <ms>]\n"
-        "        [--no-udev]\n",
+        "        [--no-udev]\n"
+        "        [-- [<extra_arg>] ...]\n",
         name
     );
 }
@@ -468,6 +480,8 @@ int parse_arguments (int argc, char *argv[])
     options.config_file = NULL;
     options.retry_time = DEFAULT_RETRY_TIME;
     options.no_udev = 0;
+    options.extra_args = NULL;
+    options.num_extra_args = 0;
     
     for (int i = 1; i < argc; i++) {
         char *arg = argv[i];
@@ -566,6 +580,11 @@ int parse_arguments (int argc, char *argv[])
         else if (!strcmp(arg, "--no-udev")) {
             options.no_udev = 1;
         }
+        else if (!strcmp(arg, "--")) {
+            options.extra_args = &argv[i + 1];
+            options.num_extra_args = argc - i - 1;
+            i += options.num_extra_args;
+        }
         else {
             fprintf(stderr, "unknown option: %s\n", arg);
             return 0;
@@ -588,6 +607,13 @@ void signal_handler (void *unused)
 {
     BLog(BLOG_NOTICE, "termination requested");
     
+    start_terminate(1);
+}
+
+void start_terminate (int exit_code)
+{
+    main_exit_code = exit_code;
+    
     if (terminating) {
         return;
     }
@@ -595,7 +621,7 @@ void signal_handler (void *unused)
     terminating = 1;
     
     if (LinkedList2_IsEmpty(&processes)) {
-        BReactor_Quit(&ss, 1);
+        BReactor_Quit(&ss, 0);
         return;
     }
     
@@ -1189,7 +1215,7 @@ void process_work_job_handler (struct process *p)
             
             // if program is terminating amd there are no more processes, exit program
             if (terminating && LinkedList2_IsEmpty(&processes)) {
-                BReactor_Quit(&ss, 1);
+                BReactor_Quit(&ss, 0);
             }
             return;
         }
@@ -1713,6 +1739,40 @@ void process_statement_instance_logfunc (struct process_statement *ps)
     BLog_Append("module: ");
 }
 
+void process_statement_instance_func_interp_exit (struct process_statement *ps, int exit_code)
+{
+    ASSERT(ps->state != SSTATE_FORGOTTEN)
+    
+    start_terminate(exit_code);
+}
+
+int process_statement_instance_func_interp_getargs (struct process_statement *ps, NCDValue *out_value)
+{
+    ASSERT(ps->state != SSTATE_FORGOTTEN)
+    
+    NCDValue_InitList(out_value);
+    
+    for (int i = 0; i < options.num_extra_args; i++) {
+        NCDValue arg;
+        if (!NCDValue_InitString(&arg, options.extra_args[i])) {
+             process_statement_log(ps, BLOG_ERROR, "NCDValue_InitString failed");
+             goto fail1;
+        }
+        
+        if (!NCDValue_ListAppend(out_value, arg)) {
+            process_statement_log(ps, BLOG_ERROR, "NCDValue_ListAppend failed");
+            NCDValue_Free(&arg);
+            goto fail1;
+        }
+    }
+    
+    return 1;
+    
+fail1:
+    NCDValue_Free(out_value);
+    return 0;
+}
+
 void process_moduleprocess_func_event (struct process *p, int event)
 {
     ASSERT(p->module_process)