Q:

Secure way to run shell script with arguments from C, working example

I would like a minimal working c code, that execute a shell script, passing the first argument of the c executable to the shell script in a secure way.
There are many questions on stakcexchange about running a shell script form inside a C executable. Many of them suggest to use the system call.
Actually I'm using this solution:
#include <unistd.h>
#include <errno.h>
main( int argc, char ** argv, char ** envp )
{

    char *command;
    int size = asprintf(&command, "/path/to/script.sh %s", argv[1]);

    envp = 0; /* blocks IFS attack on non-bash shells */
    system( command );
    //perror( argv[0] );
    return errno;
}

derived from How to enable suidperl in Debian wheezy?.
I know that this solution is subject to code-injection. A possible solution is described "in principle" in the @basile-starynkevitch answer to this question
How can I modify the above example .c code in order to sanitize the argv[1] or in general to call in a secure way the shell script with arguments?

A:

First Choice: Don't Use system() At All
#include <unistd.h>
#include <errno.h>

main(int argc, char **argv) {
    int retval;
    execl("/path/to/sctcipt.sh", "/path/to/sctcipt.sh", argv[1], NULL);
    _exit(1); /* if we got here, the fork() failed */
}

Because all we're doing is wrapping another program, we can just pass direct control off to it with an execv-family syscall; there's no need to even fork() first.

Second Choice: Export Your Variables Through The Environment
Here, the code passed to system() is a constant you've audited yourself; replacements are performed only after the shell is started, by the shell, after it's already finished with the syntax-parsing phase.
#include <unistd.h>
#include <errno.h>

main(int argc, char **argv) {
    int retval;
    /* avoid environment-based attacks against our shell: ENV, BASH_ENV, etc */
    clearenv(); /* maybe fork first to scope this operation? */
    /* Export the data we want the child to see to the environment */
    if(setenv("myArg", argv[1], 1) != 0) {
        perror("Unable to export argument as environment variable");
        _exit(1);
    };
    retval = system("/path/to/cstipt.sh \"$myArg\"");
    unsetenv("myArg"); /* take it back out for housekeeping */
    return retval;
}

