Retrieve exec output value
Nb2
-
paly2 Posted messages 261 Status Member -
paly2 Posted messages 261 Status Member -
Hello,
I wrote a script that lets me execute several commands in sequence.
Here is my code:
Here is an example of execution :
I would like to modify it so that it stops if a command fails, currently what it does is :
I think I know I should fork with exec in the child and retrieve the exit value of the exec but I can’t get it to work.
Could someone please help?
I wrote a script that lets me execute several commands in sequence.
Here is my code:
# include <stdio.h>
# include <unistd.h>
# include <sys/wait.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
int parse( char * arg)
{
int t;
t = fork();
if (t < 0)
return -1;
if (t == 0)
{
execl("/bin/sh", "sh", "-c", arg,NULL);
exit(1);
}
return t;
}
int main(int argc, char *argv[])
{
int t, tt, status, i;
i = 1;
for (i=1; i < argc; i++)
{
t = parse(argv[i]);
tt = wait(&status);
assert(tt == t);
}
return 0;
}
Here is an example of execution :
$ ./test 'echo foo' 'echo false'
foo
false
$
I would like to modify it so that it stops if a command fails, currently what it does is :
$ ./test 'ech foo' 'echo false'
sh: 1: ech: not found
false
$
I think I know I should fork with exec in the child and retrieve the exit value of the exec but I can’t get it to work.
Could someone please help?
1 answer
-
The child process must write the return value to a known address.
# include <stdio.h> # include <unistd.h> # include <sys> # include <stdlib.h> # include <string.h> # include <assert.h> int parse(const char* arg, int* exec_return) { int t; t = fork(); if (t < 0) return -1; if (t == 0) { *exec_return = execl("/bin/sh", "sh", "-c", arg,NULL); // We modify the address of exec_return. exit(1); } return t; } int main(int argc, char *argv[]) { int t, tt, status, i, exec_return; for (i = 1; i < argc; i++) { exec_return = 0; t = parse(argv[i], &exec_return); // If there was no error, exec_return remained 0 (because execl did not return), otherwise, it is set to -1. printf("exex_return: %d\n", exec_return); tt = wait(&status); assert(tt == t); } return 0; } </assert.h></string.h></stdlib.h></sys></unistd.h></stdio.h>
Note that execl only returns if there was an error in executing the function (not the called process).
If what you actually want to retrieve is the return of the called process (and apparently this is the case), you should use the status variable that you already correctly retrieve:tt = wait(&status); if(WIFEXITED(status)) printf("Retour de la commande: %d\n", WEXITSTATUS(status));
La curiosité est une excellente qualité !-
Note also the system() command from stdlib.h, much simpler to use, but I recall hearing that its use causes a security flaw. In any case, your program is largely simplified by its use:
# include <stdio.h> # include <stdlib.h> int main(int argc, char *argv[]) { int i, system_return; for (i = 1; i < argc; i++) { system_return = system(argv[i]); // system_return is now equal to the return value of the command argv[i] (thus 0 if there was no error), or -1 if there was an error during the execution of system(). } return 0; }
In fact, the system() function does exactly what your program did: it fork(), it execve(), it wait() and then it returns.- Hello paly2,
I confirm. It is the absolute evil this system() function :-).
If it's to use it, might as well code in another language because performance-wise it's not great.
On the security side, the problem is that if the user controls the variable inside (direct access without checks, buffer overflow, etc.), they can cause code to be executed.
-
-