daemon: removed option for listing debug sites.
[profile/ivi/speech-recognition.git] / src / daemon / config.c
1 /*
2  * Copyright (c) 2012, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *   * Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *   * Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *   * Neither the name of Intel Corporation nor the names of its contributors
14  *     may be used to endorse or promote products derived from this software
15  *     without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <fcntl.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39
40 #define _GNU_SOURCE
41 #include <getopt.h>
42
43 #include "srs/config.h"
44
45 #ifdef SYSTEMD_ENABLED
46 #    include <systemd/sd-daemon.h>
47 #endif
48
49 #include <murphy/common/mm.h>
50 #include <murphy/common/log.h>
51
52 #include "srs/daemon/context.h"
53 #include "srs/daemon/plugin.h"
54 #include "srs/daemon/config.h"
55
56 #ifndef PATH_MAX
57 #    define PATH_MAX 1024
58 #endif
59 #define MAX_ARGS 64
60
61 #define MAX_DEPTH   16
62 #define MAX_BLOCK   64
63 #define MAX_PREFIX 128
64
65 static void valgrind(const char *vg_path, int argc, char **argv, int vg_offs,
66                      int saved_argc, char **saved_argv, char **envp);
67
68 static srs_cfg_t *find_config(srs_cfg_t *settings, const char *key);
69
70
71 static int  nblock = 0;
72 static int  prflen = 0;
73 static char blocks[MAX_DEPTH][MAX_BLOCK];
74 static char prefix[MAX_PREFIX];
75
76
77 /*
78  * command line processing
79  */
80
81 static void config_set_defaults(srs_context_t *srs, const char *bin)
82 {
83 #define CFG "speech-recognition.conf"
84     static char cfg_file[PATH_MAX], plugin_dir[PATH_MAX];
85     char *e;
86     int   l;
87
88     if ((e = strstr(bin, "/src/srs-daemon")) != NULL ||
89         (e = strstr(bin, "/src/.libs/lt-srs-daemon")) != NULL) {
90         static int     warned = 0;
91         mrp_log_mask_t saved;
92
93         if (!warned) {
94             saved = mrp_log_set_mask(MRP_LOG_MASK_WARNING);
95             mrp_log_warning("***");
96             mrp_log_warning("*** Looks like we are run from the source tree.");
97             mrp_log_warning("*** Runtime defaults will be set accordingly...");
98             mrp_log_warning("***");
99             mrp_log_set_mask(saved);
100             warned = 1;
101         }
102
103         l = e - bin;
104         snprintf(cfg_file, sizeof(cfg_file), "%*.*s/%s", l, l, bin, CFG);
105         snprintf(plugin_dir, sizeof(plugin_dir), "%*.*s/src/.libs", l, l, bin);
106
107         srs->config_file = cfg_file;
108         srs->plugin_dir  = plugin_dir;
109         srs->log_mask    = MRP_LOG_UPTO(MRP_LOG_INFO);
110         srs->log_target  = MRP_LOG_TO_STDERR;
111         srs->foreground  = TRUE;
112     }
113     else {
114         srs->config_file = SRS_DEFAULT_CONFIG_FILE;
115         srs->plugin_dir  = SRS_DEFAULT_PLUGIN_DIR;
116         srs->log_mask    = MRP_LOG_MASK_ERROR;
117         srs->log_target  = MRP_LOG_TO_STDERR;
118     }
119 }
120
121
122 static void print_usage(const char *argv0, int exit_code, const char *fmt, ...)
123 {
124     va_list        ap;
125     srs_context_t  srs;
126     const char    *cfg, *plg;
127
128     mrp_clear(&srs);
129     config_set_defaults(&srs, argv0);
130     cfg = srs.config_file;
131     plg = srs.plugin_dir;
132
133     if (fmt && *fmt) {
134         va_start(ap, fmt);
135         vprintf(fmt, ap);
136         va_end(ap);
137     }
138
139     printf("usage: %s [options]\n\n"
140            "The possible options are:\n"
141            "  -c, --config-file=PATH         main configuration file to use\n"
142            "      The default configuration file is '%s'.\n"
143            "  -P, --plugin-dir=PATH          use DIR to search for plugins\n"
144            "      The default plugin directory is '%s'.\n"
145            "  -L, --load-plugin=NAME         load the given plugin\n"
146            "  -s, --set=SETTINGS.\n"
147            "      SETTINGS is of the format key1=var1[,key2=var2...]\n"
148            "  -t, --log-target=TARGET        log target to use\n"
149            "      TARGET is one of stderr,stdout,syslog, or a logfile path\n"
150            "  -l, --log-level=LEVELS         logging level to use\n"
151            "      LEVELS is a comma separated list of info, error and warning\n"
152            "  -v, --verbose                  increase logging verbosity\n"
153            "  -d, --debug                    enable given debug configuration\n"
154            "  -D, --list-debug               list known debug sites\n"
155            "  -f, --foreground               don't daemonize\n"
156            "  -h, --help                     show help on usage\n"
157            "  -V, --valgrind[=VALGRIND-PATH] try to run under valgrind\n"
158 #ifdef SYSTEMD_ENABLED
159            "  -S, --sockets=var1[,var2...]   set sockets in by systemd\n"
160 #endif
161 ,
162            argv0, cfg, plg);
163
164     if (exit_code < 0)
165         return;
166     else
167         exit(exit_code);
168 }
169
170
171 static int set_passed_sockets(srs_context_t *srs, const char *variables)
172 {
173 #ifdef SYSTEMD_ENABLED
174     const char *b, *e;
175     char        key[256], val[64];
176     int         nfd, i, n;
177     size_t      len;
178
179     nfd = sd_listen_fds(0);
180
181     if (nfd <= 0)
182         return nfd;
183
184     i = 0;
185     b = variables;
186     while (b && *b) {
187         while (*b == ',' || *b == ' ' || *b == '\t')
188             b++;
189
190         if (!*b)
191             return 0;
192
193         if (i >= nfd)
194             return 0;
195
196         if ((e = strchr(b, ',')) != NULL)
197             len = e - b;
198         else
199             len = strlen(b);
200
201         if (len >= sizeof(key)) {
202             errno = EOVERFLOW;
203             return -1;
204         }
205
206         strncpy(key, b, len);
207         key[len] = '\0';
208
209         n = snprintf(val, sizeof(val), "%d", SD_LISTEN_FDS_START + i);
210
211         if (n < 0 || n >= sizeof(val))
212             return -1;
213
214         srs_set_config(srs, key, val);
215
216         b = e;
217         i++;
218     }
219
220     return 0;
221 #else
222     errno = EOPNOTSUPP;
223     return -1;
224 #endif
225 }
226
227
228 static void config_load_plugins(srs_context_t *srs, char *plugins)
229 {
230     char name[PATH_MAX], *p, *n;
231     int  l;
232
233     p = plugins;
234     while (p && *p) {
235         while (*p == ' ')
236             p++;
237
238         n = strchr(p, ' ');
239
240         if (n != NULL) {
241             l = n - p;
242
243             if (l > (int)sizeof(name) - 1) {
244                 mrp_log_error("Plugin name '%*.*s' is too long.", l, l, p);
245                 exit(1);
246             }
247
248             strncpy(name, p, l);
249             name[l] = '\0';
250         }
251         else {
252             if (snprintf(name, sizeof(name), "%s", p) >= (int)sizeof(name)) {
253                 mrp_log_error("Plugin name '%s' is too long.", p);
254                 exit(1);
255             }
256         }
257
258         if (srs_create_plugin(srs, name) == NULL) {
259             mrp_log_error("Failed to load plugin '%s'.", name);
260             exit(1);
261         }
262
263         p = n ? n : NULL;
264     }
265 }
266
267
268 static void push_block(const char *block, int blen)
269 {
270     int plen;
271
272     if (nblock >= MAX_DEPTH) {
273         mrp_log_error("Too deeply nested configuration block: %s.%s",
274                       prefix, block);
275         exit(1);
276     }
277
278     if (blen >= MAX_BLOCK - 1) {
279         mrp_log_error("Too long block name '%s'.", block);
280         exit(1);
281     }
282
283     if (prflen + 1 + blen + 1 >= sizeof(prefix)) {
284         mrp_log_error("Too long nested block name '%s.%s'.", prefix, block);
285         exit(1);
286     }
287
288     strncpy(blocks[nblock], block, blen);
289     blocks[nblock][blen] = '\0';
290     if (nblock > 0)
291         prefix[prflen++] = '.';
292     strncpy(prefix + prflen, block, blen);
293     prefix[prflen + blen] = '\0';
294     nblock++;
295     prflen += blen;
296
297     mrp_debug("pushed block '%*.*s', prefix now '%s'", blen, blen, block,
298               prefix);
299 }
300
301
302 static void pop_block(void)
303 {
304     char *block;
305     int   blen;
306
307     if (nblock <= 0) {
308         mrp_log_error("Unbalanced block open ({) and close (}).");
309         exit(1);
310     }
311
312     block = blocks[--nblock];
313     blen  = strlen(block);
314
315     if (nblock > 0 && prflen < blen + 1) {
316         mrp_log_error("Internal error in nested block book-keeping.");
317         exit(1);
318     }
319
320     if (nblock > 0)
321         prflen -= blen + 1;
322     else
323         prflen = 0;
324     prefix[prflen] = '\0';
325
326     mrp_debug("popped block '%s', prefix now '%s'", block, prefix);
327 }
328
329
330 static void config_parse_settings(srs_context_t *srs, char *settings)
331 {
332     char   *key, *val, *next;
333     size_t  klen, vlen;
334     char    keybuf[128], valbuf[512];
335
336     while (*settings == ' ' || *settings == '\t')
337         settings++;
338
339     key = settings;
340
341     if (!strncmp(key, "load ", 5)) {
342         config_load_plugins(srs, key + 5);
343         return;
344     }
345
346     if (*key == '}') {
347         key++;
348
349         while (*key == ' ' || *key == '\t')
350             key++;
351
352         if (*key != '\0') {
353             mrp_log_error("Invalid block closing '%s'.", settings);
354             exit(1);
355         }
356
357         pop_block();
358         return;
359     }
360
361     while (key && *key) {
362         val  = strchr(key, '=');
363         next = strchr(key, ';');
364
365         if (next != NULL && val > next)
366             val = NULL;
367
368         if (val != NULL) {
369             klen = val - key;
370             val++;
371             vlen = next ? (size_t)(next - val) : strlen(val);
372         }
373         else {
374             val  = "true";
375             vlen = 4;
376             klen = next ? (size_t)(next - key) : strlen(key);
377         }
378
379         while (klen > 0 && key[klen - 1] == ' ')
380             klen--;
381         while (vlen > 0 && val[0] == ' ') {
382             val++;
383             vlen--;
384         }
385         while (vlen > 0 && val[vlen - 1] == ' ')
386             vlen--;
387
388         if (klen + prflen >= sizeof(keybuf) || vlen >= sizeof(valbuf)) {
389             mrp_log_error("Configuration setting %*.*s = %*.*s too long.",
390                           (int)klen, (int)klen, key,
391                           (int)vlen, (int)vlen, val);
392             exit(1);
393         }
394
395         if (vlen == 1 && val[0] == '{') {
396             push_block(key, klen);
397             return;
398         }
399
400         if (nblock > 0)
401             snprintf(keybuf, sizeof(keybuf), "%s.%*.*s", prefix,
402                      klen, klen, key);
403         else
404             snprintf(keybuf, sizeof(keybuf), "%*.*s", klen, klen, key);
405         strncpy(valbuf, val, vlen);
406         valbuf[vlen] = '\0';
407
408         mrp_debug("setting configuration variable %s=%s", keybuf, valbuf);
409         srs_set_config(srs, keybuf, valbuf);
410
411         key = next ? next + 1 : NULL;
412     }
413 }
414
415
416 static void config_parse_file(srs_context_t *srs, char *path)
417 {
418     FILE *fp;
419     char  line[1024], *p, *end;
420
421     fp = fopen(path, "r");
422
423     if (fp == NULL) {
424         printf("Failed to open configuration file '%s'.\n", path);
425         exit(1);
426     }
427
428     nblock = 0;
429     prflen = 0;
430
431     while ((p = fgets(line, sizeof(line), fp)) != NULL) {
432         while (*p == ' ' || *p == '\t')
433             p++;
434
435         if (*p == '#')
436             continue;
437
438         if ((end = strchr(p, '\n')) != NULL)
439             *end = '\0';
440
441         config_parse_settings(srs, p);
442     }
443
444     nblock = 0;
445     prflen = 0;
446
447     fclose(fp);
448 }
449
450
451 void config_parse_cmdline(srs_context_t *srs, int argc, char **argv,
452                           char **envp)
453 {
454 #   define OPTIONS "c:P:L:l:t:B:s:fvd:hS:V"
455     struct option options[] = {
456         { "config-file"  , required_argument, NULL, 'c' },
457         { "plugin-dir"   , required_argument, NULL, 'P' },
458         { "load-plugin"  , required_argument, NULL, 'L' },
459         { "log-level"    , required_argument, NULL, 'l' },
460         { "log-target"   , required_argument, NULL, 't' },
461         { "set"          , required_argument, NULL, 's' },
462         { "verbose"      , optional_argument, NULL, 'v' },
463         { "debug"        , required_argument, NULL, 'd' },
464         { "foreground"   , no_argument      , NULL, 'f' },
465         { "valgrind"     , optional_argument, NULL, 'V' },
466         { "sockets"      , required_argument, NULL, 'S' },
467         { "help"         , no_argument      , NULL, 'h' },
468         { NULL, 0, NULL, 0 }
469     };
470
471
472 #   define SAVE_ARG(a) do {                                     \
473         if (saved_argc >= MAX_ARGS)                             \
474             print_usage(argv[0], EINVAL,                        \
475                         "too many command line arguments");     \
476         else                                                    \
477             saved_argv[saved_argc++] = a;                       \
478     } while (0)
479 #   define SAVE_OPT(o)       SAVE_ARG(o)
480 #   define SAVE_OPTARG(o, a) SAVE_ARG(o); SAVE_ARG(a)
481     char *saved_argv[MAX_ARGS];
482     int   saved_argc;
483
484     int   opt, help;
485
486     config_set_defaults(srs, argv[0]);
487     mrp_log_set_mask(srs->log_mask);
488     mrp_log_set_target(srs->log_target);
489
490     saved_argc = 0;
491     saved_argv[saved_argc++] = argv[0];
492
493     help = FALSE;
494
495     while ((opt = getopt_long(argc, argv, OPTIONS, options, NULL)) != -1) {
496         switch (opt) {
497         case 'c':
498             SAVE_OPTARG("-c", optarg);
499             srs->config_file = optarg;
500             config_parse_file(srs, optarg);
501             break;
502
503         case 'P':
504             SAVE_OPTARG("-P", optarg);
505             srs->plugin_dir = optarg;
506             break;
507
508         case 'L':
509             SAVE_OPTARG("-L", optarg);
510             if (srs_create_plugin(srs, optarg) == NULL) {
511                 mrp_log_error("Failed to load plugin '%s'.", optarg);
512                 exit(1);
513             }
514             break;
515
516         case 'v':
517             SAVE_OPT("-v");
518             srs->log_mask <<= 1;
519             srs->log_mask  |= 1;
520             mrp_log_set_mask(srs->log_mask);
521             break;
522
523         case 'l':
524             SAVE_OPTARG("-l", optarg);
525             srs->log_mask = mrp_log_parse_levels(optarg);
526             if (srs->log_mask < 0)
527                 print_usage(argv[0], EINVAL, "invalid log level '%s'", optarg);
528             else
529                 mrp_log_set_mask(srs->log_mask);
530             break;
531
532         case 't':
533             SAVE_OPTARG("-t", optarg);
534             srs->log_target = optarg;
535             break;
536
537         case 's':
538             SAVE_OPTARG("-s", optarg);
539             nblock = 0;
540             prflen = 0;
541             config_parse_settings(srs, optarg);
542             nblock = 0;
543             prflen = 0;
544             break;
545
546         case 'd':
547             SAVE_OPTARG("-d", optarg);
548             srs->log_mask |= MRP_LOG_MASK_DEBUG;
549             mrp_debug_set_config(optarg);
550             mrp_debug_enable(TRUE);
551             break;
552
553         case 'f':
554             SAVE_OPT("-f");
555             srs->foreground = TRUE;
556             break;
557
558         case 'V':
559             valgrind(optarg, argc, argv, optind, saved_argc, saved_argv, envp);
560             break;
561
562 #ifdef SYSTEMD_ENABLED
563         case 'S':
564             SAVE_OPTARG("-S", optarg);
565             set_passed_sockets(srs, optarg);
566             break;
567 #endif
568
569         case 'h':
570             SAVE_OPT("-h");
571             help++;
572             break;
573
574         default:
575             print_usage(argv[0], EINVAL, "invalid option '%c'", opt);
576         }
577     }
578
579     if (help) {
580         print_usage(argv[0], -1, "");
581         exit(0);
582     }
583
584 }
585
586
587 /*
588  * configuration setting processing
589  *
590  * Format of a configuration entry is
591  *    setting: <key> = <value> | <key> | load <plugin>
592  *    entry: setting | setting ; entry
593  */
594
595 static srs_cfg_t *find_config(srs_cfg_t *settings, const char *key)
596 {
597     if (settings != NULL) {
598         while (settings->key != NULL) {
599             if (!strcmp(settings->key, key))
600                 return settings;
601             else
602                 settings++;
603         }
604     }
605
606     return NULL;
607 }
608
609
610 const char *srs_get_string_config(srs_cfg_t *settings, const char *key,
611                                   const char *defval)
612 {
613     srs_cfg_t *cfg = find_config(settings, key);
614
615     if (cfg != NULL) {
616         cfg->used = TRUE;
617
618         return cfg->value;
619     }
620     else
621         return defval;
622 }
623
624
625 int srs_get_bool_config(srs_cfg_t *settings, const char *key, int defval)
626 {
627     srs_cfg_t *cfg = find_config(settings, key);
628
629     if (cfg != NULL) {
630         cfg->used = TRUE;
631
632         if (!strcasecmp(cfg->value, "true"))
633             return TRUE;
634         else if (!strcasecmp(cfg->value, "false"))
635             return FALSE;
636
637         mrp_log_error("Value '%s' for key '%s' is not a boolean.",
638                       cfg->value, cfg->key);
639         exit(1);
640     }
641
642     return defval;
643 }
644
645
646 int32_t srs_get_int32_config(srs_cfg_t *settings, const char *key,
647                              int32_t defval)
648 {
649     srs_cfg_t *cfg = find_config(settings, key);
650     int32_t    val;
651     char      *end;
652
653     if (cfg != NULL) {
654         cfg->used = TRUE;
655
656         val = (int32_t)strtol(cfg->value, &end, 0);
657
658         if (end && !*end)
659             return val;
660         else {
661             mrp_log_error("Value '%s' for key '%s' is not an int32.",
662                           cfg->value, cfg->key);
663             exit(1);
664         }
665     }
666
667     return defval;
668 }
669
670
671 uint32_t srs_get_uint32_config(srs_cfg_t *settings, const char *key,
672                                uint32_t defval)
673 {
674     srs_cfg_t *cfg = find_config(settings, key);
675     uint32_t   val;
676     char      *end;
677
678     if (cfg != NULL) {
679         cfg->used = TRUE;
680
681         val = (uint32_t)strtoul(cfg->value, &end, 0);
682
683         if (end && !*end)
684             return val;
685         else {
686             mrp_log_error("Value '%s' for key '%s' is not an uint32.",
687                           cfg->value, cfg->key);
688             exit(1);
689         }
690     }
691
692     return defval;
693 }
694
695
696 int srs_collect_config(srs_cfg_t *settings, const char *prefix,
697                        srs_cfg_t **matching)
698 {
699     srs_cfg_t *m = NULL;
700     int        n = 0;
701     size_t     osize, nsize, l;
702
703     if (settings == NULL)
704         goto out;
705
706     l = strlen(prefix);
707
708     while (settings->key != NULL) {
709         if (!strncmp(settings->key, prefix, l)) {
710             osize = sizeof(*m) *  n;
711             nsize = sizeof(*m) * (n + 1);
712
713             if (!mrp_reallocz(m, osize, nsize))
714                 goto fail;
715
716             m[n].key   = mrp_strdup(settings->key);
717             m[n].value = mrp_strdup(settings->value);
718
719             if (m[n].key == NULL || m[n].value == NULL) {
720                 n++;
721                 goto fail;
722             }
723
724             n++;
725         }
726
727         settings++;
728     }
729
730  out:
731     if (m != NULL) {
732         osize = sizeof(*m) *  n;
733         nsize = sizeof(*m) * (n + 1);
734
735         if (!mrp_reallocz(m, osize, nsize))
736             goto fail;
737     }
738
739     *matching = m;
740
741     return n;
742
743  fail:
744     while (n >= 0) {
745         mrp_free(m[n].key);
746         mrp_free(m[n].value);
747     }
748
749     mrp_free(m);
750
751     *matching = NULL;
752     return -1;
753 }
754
755
756 void srs_free_config(srs_cfg_t *settings)
757 {
758     srs_cfg_t *s;
759
760     if (settings != NULL) {
761         for (s = settings; s->key != NULL; s++) {
762             mrp_free(s->key);
763             mrp_free(s->value);
764         }
765
766         mrp_free(settings);
767     }
768 }
769
770
771 void srs_set_config(srs_context_t *srs, const char *key, const char *value)
772 {
773     srs_cfg_t *var;
774     size_t     osize, nsize, diff;
775
776     var = find_config(srs->settings, key);
777
778     if (var == NULL) {
779         diff  = srs->nsetting == 0 ? 2 : 1;
780         osize = sizeof(*srs->settings) *  srs->nsetting;
781         nsize = sizeof(*srs->settings) * (srs->nsetting + diff);
782
783         if (!mrp_reallocz(srs->settings, osize, nsize))
784             goto nomem;
785
786         var = srs->settings + srs->nsetting++;
787     }
788     else {
789         mrp_log_warning("Overwriting configuration setting '%s = %s'",
790                         var->key, var->value);
791         mrp_log_warning("with new setting '%s = %s'", key, value);
792
793         mrp_free(var->key);
794         mrp_free(var->value);
795         var->key = var->value = NULL;
796     }
797
798     var->key   = mrp_strdup(key);
799     var->value = mrp_strdup(value);
800
801     if (var->key == NULL || var->value == NULL) {
802     nomem:
803         mrp_log_error("Failed to allocate configuration variable %s=%s.",
804                       key, value);
805         exit(1);
806     }
807 }
808
809
810 /*
811  * bridging to valgrind
812  */
813
814 static void valgrind(const char *vg_path, int argc, char **argv, int vg_offs,
815                      int saved_argc, char **saved_argv, char **envp)
816 {
817 #define VG_ARG(a) vg_argv[vg_argc++] = a
818     char *vg_argv[MAX_ARGS + 1];
819     int   vg_argc, normal_offs, i;
820
821     vg_argc = 0;
822
823     /* set valgrind binary */
824     VG_ARG(vg_path ? (char *)vg_path : "/usr/bin/valgrind");
825
826     /* add valgrind arguments */
827     for (i = vg_offs; i < argc; i++)
828         VG_ARG(argv[i]);
829
830     /* save offset to normal argument list for fallback */
831     normal_offs = vg_argc;
832
833     /* add our binary and our arguments */
834     for (i = 0; i < saved_argc; i++)
835         vg_argv[vg_argc++] = saved_argv[i];
836
837     /* terminate argument list */
838     VG_ARG(NULL);
839
840     /* try executing through valgrind */
841     mrp_log_warning("Executing through valgrind (%s)...", vg_argv[0]);
842     execve(vg_argv[0], vg_argv, envp);
843
844     /* try falling back to normal execution */
845     mrp_log_error("Executing through valgrind failed (error %d: %s), "
846                   "retrying without...", errno, strerror(errno));
847     execve(vg_argv[normal_offs], vg_argv + normal_offs, envp);
848
849     /* can't do either, so just give up */
850     mrp_log_error("Fallback to normal execution failed (error %d: %s).",
851                   errno, strerror(errno));
852     exit(1);
853 }