Add setup additional environment for command launch option
authorAleksei Vereshchagin <avereschagin@dev.rtsoft.ru>
Wed, 5 Sep 2018 15:26:07 +0000 (18:26 +0300)
committerAleksei Vereshchagin <avereschagin@dev.rtsoft.ru>
Mon, 10 Sep 2018 14:00:10 +0000 (17:00 +0300)
README.md
profctl.c

index f2231d97e93adbb3a6208ceb8ea585b7feb8b282..74be00813a8c53434ea0e57ad36657eb10b03e16 100644 (file)
--- a/README.md
+++ b/README.md
@@ -36,3 +36,5 @@ profctl [options...] [command [args]]
   server port for data output
 * `-s, --stat=port`
   server port for statistic output
+* `-E, --env [VAR=VAL ...]`
+  setup additional environment for command launch
index 2b7f73ba00053949d079e998f20dd3118ef8b25c..e3d918bed4e5b3d4b4138b32d75e424608c02685 100644 (file)
--- a/profctl.c
+++ b/profctl.c
@@ -40,6 +40,7 @@ static struct termios sterm;
 static char *appid = NULL;
 static int app_pid = -1;
 static int cmd_pid = -1;
+static int cmd_idx = -1;
 static char *pname = NULL;
 static char *ename = NULL;
 static char *oname = NULL;
@@ -57,6 +58,14 @@ static FILE *ctrl_file_out = NULL;
 static FILE *data_file_out = NULL;
 static FILE *stat_file_out = NULL;
 
+#ifndef ADDITIONAL_ENV_SIZE
+#define ADDITIONAL_ENV_SIZE 128
+#endif
+
+static int env_mode = 0;
+static char *additional_env[ADDITIONAL_ENV_SIZE];
+static int additional_env_index = 0;
+
 volatile int global_stop = 0;
 
 int is_running(int pid)
@@ -77,6 +86,7 @@ static struct option long_options[] = {
        {"control",     required_argument, 0, 'c'},
        {"data",        required_argument, 0, 'd'},
        {"stat",        required_argument, 0, 's'},
+       {"env",         optional_argument, 0, 'E'},
        {0, 0, 0, 0}
 };
 
@@ -201,9 +211,31 @@ static void CheckValue(char **value, const char *info)
 static int process_option(int argc, char **argv)
 {
        int option_index;
+       int result = -1;
+
+       result = getopt_long(argc, argv, "-a:p:ve:o:it:wc:d:s:E::",
+               long_options, &option_index);
+
+       if (result == 1) {
+               // NOTE: check if -E params handled
+               if (env_mode) {
+                       // NOTE: code duplication, should be refactored (see below)
+                       if (additional_env_index == ADDITIONAL_ENV_SIZE) {
+                               log_error("Too many environment variables");
+                               exit(1);
+                       }
+                       additional_env[additional_env_index++] = optarg;
+                       return 0;
+               } else {
+                       // NOTE: start of command line, case `profctl ... <cmd> ...`
+                       cmd_idx = optind - 1;
+                       return -1;
+               }
+       } else {
+               env_mode = 0;
+       }
 
-       switch (getopt_long(argc, argv, "+a:p:ve:o:it:wc:d:s:",
-               long_options, &option_index)) {
+       switch (result) {
        case 'a': CheckValue(&appid, "appid"); break;
        case 'p': CheckValue(&pname, "pipe name"); break;
        case 'e': CheckValue(&ename, "exe name"); break;
@@ -215,9 +247,28 @@ static int process_option(int argc, char **argv)
        case 'c': controlPort = atoi(optarg); break;
        case 'd': dataPort = atoi(optarg); break;
        case 's': statPort = atoi(optarg); break;
+       case 'E':
+               env_mode = 1;
+               // NOTE: -E option can be used as -Eu=a v=b, not only -E u=a v=b
+               if (optarg) {
+                       // NOTE: code duplication, should be refactored (see above)
+                       if (additional_env_index == ADDITIONAL_ENV_SIZE) {
+                               log_error("Too many environment variables");
+                               exit(1);
+                       }
+                       additional_env[additional_env_index++] = optarg;
+               }
+               break;
        case '?': exit(1);
-       default:
+       case -1:
+               // NOTE: start of command line, case `profctl ... -- <cmd> ...`
+               if (optind != argc) {
+                       cmd_idx = optind;
+               }
                return -1;
+       default:
+               // NOTE: should not be reachable
+               abort();
        }
        return 0;
 }
@@ -620,11 +671,14 @@ int main(int argc, char **argv)
                fclose(stdout); // NOTE: detaching from stdin/out/err streams
        }
 
-       if (optind != argc) {
+       if (cmd_idx != -1) {
                // TODO: should be refactored: use separated launcher
 
                if (verbose) {
-                       log_message("launch command process %s", argv[optind]);
+                       log_message("launch command process %s", argv[cmd_idx]);
+                       for (int i = 0; i < additional_env_index; i++) {
+                               log_message("  additional environment: %s", additional_env[i]);
+                       }
                }
 
                cmd_pid = fork();
@@ -637,7 +691,10 @@ int main(int argc, char **argv)
                        close(STDOUT_FILENO);
                        close(STDERR_FILENO);
 
-                       execv(argv[optind], &argv[optind]);
+                       for (int i = 0; i < additional_env_index; i++) {
+                               putenv(additional_env[i]);
+                       }
+                       execv(argv[cmd_idx], &argv[cmd_idx]);
                        exit(1);
                } else if (cmd_pid == -1) {
                        log_system_error_and_exit("cannot fork command process");