65

I want to execute another program within C code. For example, I want to execute a command

./foo 1 2 3

foo is the program which exists in the same folder, and 1 2 3 are arguments. foo program creates a file which will be used in my code.

How do I do this?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
js0823
  • 1,843
  • 8
  • 24
  • 36

7 Answers7

66

For a simple way, use system():

#include <stdlib.h>
...
int status = system("./foo 1 2 3");

system() will wait for foo to complete execution, then return a status variable which you can use to check e.g. exitcode (the command's exitcode gets multiplied by 256, so divide system()'s return value by that to get the actual exitcode: int exitcode = status / 256).

The manpage for wait() (in section 2, man 2 wait on your Linux system) lists the various macros you can use to examine the status, the most interesting ones would be WIFEXITED and WEXITSTATUS.

Alternatively, if you need to read foo's standard output, use popen(3), which returns a file pointer (FILE *); interacting with the command's standard input/output is then the same as reading from or writing to a file.

Billy
  • 1,177
  • 2
  • 15
  • 35
Erik
  • 88,732
  • 13
  • 198
  • 189
43

The system function invokes a shell to run the command. While this is convenient, it has well known security implications. If you can fully specify the path to the program or script that you want to execute, and you can afford losing the platform independence that system provides, then you can use an execve wrapper as illustrated in the exec_prog function below to more securely execute your program.

Here's how you specify the arguments in the caller:

const char    *my_argv[64] = {"/foo/bar/baz" , "-foo" , "-bar" , NULL};

Then call the exec_prog function like this:

int rc = exec_prog(my_argv);

Here's the exec_prog function:

static int exec_prog(const char **argv)
{
    pid_t   my_pid;
    int     status, timeout /* unused ifdef WAIT_FOR_COMPLETION */;

    if (0 == (my_pid = fork())) {
            if (-1 == execve(argv[0], (char **)argv , NULL)) {
                    perror("child process execve failed [%m]");
                    return -1;
            }
    }

#ifdef WAIT_FOR_COMPLETION
    timeout = 1000;

    while (0 == waitpid(my_pid , &status , WNOHANG)) {
            if ( --timeout < 0 ) {
                    perror("timeout");
                    return -1;
            }
            sleep(1);
    }

    printf("%s WEXITSTATUS %d WIFEXITED %d [status %d]\n",
            argv[0], WEXITSTATUS(status), WIFEXITED(status), status);

    if (1 != WIFEXITED(status) || 0 != WEXITSTATUS(status)) {
            perror("%s failed, halt system");
            return -1;
    }

#endif
    return 0;
}

Remember the includes:

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>

See related SE post for situations that require communication with the executed program via file descriptors such as stdin and stdout.

Community
  • 1
  • 1
Jonathan Ben-Avraham
  • 4,615
  • 2
  • 34
  • 37
20

You can use fork() and system() so that your program doesn't have to wait until system() returns.

#include <stdio.h>
#include <stdlib.h>

int main(int argc,char* argv[]){

    int status;

    // By calling fork(), a child process will be created as a exact duplicate of the calling process.
    // Search for fork() (maybe "man fork" on Linux) for more information.
    if(fork() == 0){ 
        // Child process will return 0 from fork()
        printf("I'm the child process.\n");
        status = system("my_app");
        exit(0);
    }else{
        // Parent process will return a non-zero value from fork()
        printf("I'm the parent.\n");
    }

    printf("This is my main program and it will continue running and doing anything i want to...\n");

    return 0;
}
Craig McQueen
  • 41,871
  • 30
  • 130
  • 181
Pedro Alves
  • 1,667
  • 4
  • 17
  • 37
  • 7
    It would be far more efficient to just use execl or execv from the child process because it won't use a shell, it won't fork a new thread, and you're exiting right after you called system, anyway. Also, the process will become a zombie if you don't call wait(). – Billy Sep 26 '16 at 21:42
10

system() executes a shell which is then responsible for parsing the arguments and executing the desired program. To execute the program directly, use fork() and exec() (which is what system() uses to execute the shell as well as what the shell itself uses to execute commands).

#include <unistd.h>

int main() {
     if (fork() == 0) {
          /*
           * fork() returns 0 to the child process
           * and the child's PID to the parent.
           */
          execl("/path/to/foo", "foo", "arg1", "arg2", "arg3", 0);
          /*
           * We wouldn't still be here if execl() was successful,
           * so a non-zero exit value is appropriate.
           */
          return 1;
     }

     return 0;
}
Billy
  • 1,177
  • 2
  • 15
  • 35
  • What to put in the path if the executable exists in the same directory? – y_159 Sep 20 '20 at 06:10
  • 1
    @y_159 Just remove everything up to and including the last slash. If you're trying to execute a file named `foo` in the current directory, the code would be: `execl("foo", "foo", "arg1", "arg2", "arg3", 0);` – Billy Sep 21 '20 at 01:35
  • thanks. just one doubt instead of `foo` in the second argument shouldn't it be `./foo`? – y_159 Sep 21 '20 at 21:37
  • 1
    @y_159 You can add `./`, but it isn't required. – Billy Sep 22 '20 at 22:12
  • This is the correct answer. All the others rely on flawed calls and poorly secured functions. – SpectreVert Jun 15 '23 at 10:50
5

In C

#include <stdlib.h>

system("./foo 1 2 3");

In C++

#include <cstdlib>

std::system("./foo 1 2 3");

Then open and read the file as usual.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • I'm trying to do this, but instead of using the value directly, i need to pass a c variable, how can i do this? – Everaldo Jul 16 '21 at 21:37
2

How about like this:

char* cmd = "./foo 1 2 3";
system(cmd);
Johan
  • 20,067
  • 28
  • 92
  • 110
1

Here's the way to extend to variable args when you don't have the args hard coded (although they are still technically hard coded in this example, but should be easy to figure out how to extend...):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int argcount = 3;
const char* args[] = {"1", "2", "3"};
const char* binary_name = "mybinaryname";
char myoutput_array[5000];

sprintf(myoutput_array, "%s", binary_name);
for(int i = 0; i < argcount; ++i)
{
    strcat(myoutput_array, " ");
    strcat(myoutput_array, args[i]);
}
system(myoutput_array);
Hazok
  • 5,373
  • 4
  • 38
  • 48