1

I'm working on a project that basically does the same thing as strace(1) using ptrace(). Basically we have a controller.c program that takes an executable as an argument and it outputs any system calls made by the executable (for example % controller ls -l) We are using the execve() to run the executable file, but we are having a little bit of trouble. execve takes the following arguments

 execve( const char *filename, char *const argv[], char *const envp[] )

where filename in this instance would be "ls", and argv[] is a list of the arguments for the given file name. So we have something that looks like this (in the C file)

int main(int argc, char *argv[],char *envp[]){
  pid_t child;
  child = fork;

  if(/* CHILD */){
    ptrace(PTRACE_TRACEME,0, NULL, NULL);

    if(argc == 2) {
      execve(argv[1],NULL,envp);
    }
    else {
      execve( argv[1], /* ARGUMENT LIST */, envp);
    }

  } else /* PARENT */ {
    //PARENT CODE 
  }
}

So if we get an executable, for example controller ls -l, where argv[0] = "controller", argv[1] = "ls", and argv[2] = "-l", how can we pass the correct parameter at "ARGUMENT LIST" (where the arguments in this case is just "-l" but it could be more)?

Basically, how do we initialize an array of type const char * such that the array has the argument values for the executable? Do we even need to worry about having extra values in the array and just past argv for ARGUMENT LIST?

Thanks for your help!

AusCBloke
  • 18,014
  • 6
  • 40
  • 44
user1348913
  • 189
  • 4
  • 12
  • I don't work with C much. Does this syntax work for taking a sub-array of some array? (I'm going to give it a try) – user1348913 Sep 16 '12 at 23:16
  • First, you don't need that inner `if/else` at all, and seond, why not just `&argv[1]` for the middle argument to `execve`? – Carl Norum Sep 16 '12 at 23:16
  • `argv + n` simply is an array/pointer that points to the `n`th element of argv. It's equivalent to `&argv[n]`. – epsalon Sep 16 '12 at 23:21

2 Answers2

1

You can simply pass argv + 1 (to skip your program's name). argv + 1 is a pointer to an array starting from the second element of argv, which is the executed program's name. argv + 1 is equivalent to &argv[1], and you can use whatever style you prefer.

As mentioned in the comments, section 5.1.2.2.1 of the standard specified that argv is indeed null-terminated. The section below is retained for completeness.

In case C doesn't guarantee argv is null-terminated (and it's not clear to me whether it does or not), you can do:

char **new_argv = malloc((argc-1) * sizeof(char*));
for (int i = 0; i < argc - 1) new_argv[i] = argv[i+1];

and use new_argv for the argument list.

epsalon
  • 2,294
  • 12
  • 19
  • I think you'll find that C does in fact guarantee that the argv and envp arrays are null-terminated. – Neil Sep 16 '12 at 23:36
  • @Neil - did you find proof of that somewhere? I just took a quick look in the spec, but I didn't anything that jumped out at me. – Carl Norum Sep 17 '12 at 00:00
  • @CarlNorum: The answer to [this question](http://stackoverflow.com/questions/3772796/argvargc) mentions that 5.1.2.2.1 of the standard specifies that `argv` is null terminated, which is what I've always believed to be true. `envp` has to be terminated by a NULL in order to be able to tell the end of it. – AusCBloke Sep 17 '12 at 00:25
  • @AusCBloke, I'm looking at that right now and I see the line. I don't know how I missed it earlier - it's staring me right in the face: "`argv[argc]` shall be a null pointer.". `envp` doesn't really enter into it, since it's not standard C anyway. – Carl Norum Sep 17 '12 at 04:10
1
execve(argv[1], argv+1, envp);
wildplasser
  • 43,142
  • 8
  • 66
  • 109