aboutsummaryrefslogtreecommitdiff
path: root/src/arm/do_start_process.c
blob: f4d3424ff179ad7010433953ed26bcb394eeff06 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
 * Actually start a process.  All of the arguments given to this
 * function are strings that are used for the "argv" array.  However,
 * if those strings contain spaces, the given argument is split into
 * multiple argv entries without spaces.  Similarly, if an argument is
 * the empty string, it is skipped.  This function has the inherent
 * limitation that it does NOT allow passing command line arguments
 * with spaces to the new process.
 *
 * @param lsocks array of listen sockets to dup starting at fd3 (systemd-style), or NULL
 * @param first_arg first argument for argv (may be an empty string)
 * @param ... more arguments, NULL terminated
 * @return PID of the started process, -1 on error
 */
static struct GNUNET_OS_Process *
do_start_process (const SOCKTYPE *lsocks, const char *first_arg, ...)
{
  va_list ap;
  char **argv;
  unsigned int argv_size;
  const char *arg;
  const char *rpos;
  char *pos;
  char *cp;
  const char *last;
  struct GNUNET_OS_Process *proc;

  argv_size = 1;
  va_start (ap, first_arg);
  arg = first_arg;
  last = NULL;
/* *INDENT-OFF* */
  do
    {
/* *INDENT-ON* */
  rpos = arg;
  while ('\0' != *rpos)
  {
    if (' ' == *rpos)
    {
      if (last != NULL)
        argv_size++;
      last = NULL;
      while (' ' == *rpos)
        rpos++;
    }
    if ((last == NULL) && (*rpos != '\0'))
      last = rpos;
    if (*rpos != '\0')
      rpos++;
  }
  if (last != NULL)
    argv_size++;
/* *INDENT-OFF* */
    }
  while (NULL != (arg = (va_arg (ap, const char*))));
/* *INDENT-ON* */
  va_end (ap);

  argv = GNUNET_malloc (argv_size * sizeof (char *));
  argv_size = 0;
  va_start (ap, first_arg);
  arg = first_arg;
  last = NULL;
/* *INDENT-OFF* */
  do
    {
/* *INDENT-ON* */
  cp = GNUNET_strdup (arg);
  pos = cp;
  while ('\0' != *pos)
  {
    if (' ' == *pos)
    {
      *pos = '\0';
      if (last != NULL)
        argv[argv_size++] = GNUNET_strdup (last);
      last = NULL;
      pos++;
      while (' ' == *pos)
        pos++;
    }
    if ((last == NULL) && (*pos != '\0'))
      last = pos;
    if (*pos != '\0')
      pos++;
  }
  if (last != NULL)
    argv[argv_size++] = GNUNET_strdup (last);
  last = NULL;
  GNUNET_free (cp);
/* *INDENT-OFF* */
    }
  while (NULL != (arg = (va_arg (ap, const char*))));
/* *INDENT-ON* */
  va_end (ap);
  argv[argv_size] = NULL;
  proc = GNUNET_OS_start_process_v (lsocks, argv[0], argv);
  while (argv_size > 0)
    GNUNET_free (argv[--argv_size]);
  GNUNET_free (argv);
  return proc;
}