Execve: how can I initialize char * argv [] with multiple commands instead of a single command?

execve: how can I initialize char *argv[ ] multiple commands instead of a single command?
If I want to execute 4 commands, can I use the following statement?

 char *argv[4][ ] = { {...}, {...}, {...} }; 

And to execute them with execve, can I use a loop with var from 1 to 4?

+5
source share
3 answers

You cannot execute multiple commands with just one call to execve . In a loop, you will need to fork your program to make several execve calls. The manpage execve says:

execve () does not return successfully, and the text, data, bss, and the stack of the calling process are overwritten by the loaded program. [...]

Return value
If success, execve () is not returned, a -1 error is returned, and errno is set accordingly.

Method using fork:

Output:

 Hello 1 Hello 2 Hello 3 

code:

 #include <unistd.h> #include <stdio.h> int main(void) { int idx; char *argv[][4] = { {"/bin/sh", "-c", "echo Hello 1", 0}, {"/bin/sh", "-c", "echo Hello 2", 0}, {"/bin/sh", "-c", "echo Hello 3", 0} }; for (idx = 0; idx < 3; idx++) { if (0 == fork()) continue; execve(argv[idx][0], &argv[idx][0], NULL); fprintf(stderr, "Oops!\n"); } return 0; } 

Method using concatenation of commands:
A workaround would be to root the commands using the shell:

Output:

 Hello 1 Hello 2 

code:

 #include <unistd.h> #include <stdio.h> int main(void) { char *argv[] = {"/bin/sh", "-c", "echo Hello 1 && echo Hello 2", 0}; execve(argv[0], &argv[0], NULL); fprintf(stderr, "Oops!\n"); return 0; } 
+4
source

The exec*() family of functions replaces the current current process with the new executable. Thus, it is not possible to execute several commands, because as soon as you call execve() , your own program no longer starts - the process now executes a new program.

The existing answer shows the "classic" approach of using fork() to create a new process and call the exec*() function. This has a bit of overhead for copying some process related resources, which are immediately replaced by calling exec*() . To solve this inefficiency, vfork() was invented. vfork() must not do any copying and therefore do anything other than calling _exit() , or one of the exec*() functions in the child created by vfork() is undefined behavior.

This is a huge source of errors and was later removed from the POSIX standard, so you should not use vfork() in a modern program. There is currently a new way to solve this problem: posix_spawn() . This function creates a new process directly with the new executable. Since this is a good match for what you are trying to achieve in your question, here is a tiny use case:

 #include <stdio.h> #include <spawn.h> #include <sys/types.h> #include <sys/wait.h> extern char **environ; int main(void) { char *argv[][3] = { { "echo", "First command", 0}, { "echo", "Second command", 0} }; for (int i = 0; i < 2; ++i) { pid_t pid; if (posix_spawn(&pid, "/bin/echo", 0, 0, argv[i], environ) != 0) { fputs("Error spawning child.\n", stderr); } else { // could get exit code etc here, see // https://linux.die.net/man/2/waitpid wait(0); } } return 0; } 
+1
source

Well, you canโ€™t. Just. The execve(2) system call is not a call to execute several commands, but only to overwrite the space allocated by the process by loading a new program image into its virtual space. This means that the only way to execute several commands from execve(2) is to load the shell and execute several commands. You should understand that this means loading the program into memory and executing it, rather than executing programs or shell scripts in general. When you understand this, you can understand the reason for loading the shell to execute several commands in a line (for example, the example below or what the system(3) function call does)

 execlp("/bin/bash", "bash", "-c", "echo foo; echo bar", NULL); 
For instance,

will execute two different echo codes that are passed to the bash(1) shell in one line of parameters.

Note

I used the similar execvp(2) system call for simplicity, but the same applies to execve(2) (which is the complete general system call interface, although both translate to the same exec() system call.

0
source

Source: https://habr.com/ru/post/1270209/


All Articles