summaryrefslogtreecommitdiff
path: root/klibc/klibc/exec_l.c
blob: cdae11e9810f12b5c34520ae9f8ac3065593b5f4 (plain)
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
/*
 * exec_l.c
 *
 * Common implementation of execl() execle() execlp()
 */

#include <stdarg.h>
#include <alloca.h>
#include <unistd.h>

int NAME (const char *path, const char *arg0, ...)
{
  va_list ap, cap;
  int argc = 1, rv;
  const char **argv, **argp;
  const char *arg;
#if EXEC_E
  char * const * envp;
#else
#define envp environ
#endif

  va_start(ap, arg0);
  va_copy(cap, ap);

  /* Count the number of arguments */
  do {
    arg = va_arg(cap, const char *);
    argc++;
  } while ( arg );

  va_end(cap);
  
  /* Allocate memory for the pointer array */ 
  argp = argv = alloca(argc*sizeof(const char *));
  if ( !argv ) {
    va_end(ap);
    return -1;
  }

  /* Copy the list into an array */
  *argp++ = arg0;
  do {
    *argp++ = arg = va_arg(ap, const char *);
  } while ( arg );

#if EXEC_E
  /* execle() takes one more argument for the environment pointer */
  envp = va_arg(ap, char * const *);
#endif

  rv = (EXEC_P ? execvpe : execve)(path, (char * const *)argv, envp);

  va_end(ap);

  return rv;
}