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?
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.
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.
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;
}
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 woundn't still be here if execl() was successful,
* so a non-zero exit value is appropriate.
*/
return 1;
}
return 0;
}
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.
How about like this:
char* cmd = "./foo 1 2 3";
system(cmd);
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);
Related
I am very new at C but am currently working on creating a C program to serve as a shell interface. It is supposed to accept commands and then execute each command in a separate process. I am currently stuck trying to get C to recognize that it is a command. I am unsure how to do this, and can't seem to find any useful examples.
Here is my code, it is saying that everything is not a valid command ("no cmd"). Does anyone have any idea why this would be occurring? Is C not able to recognize it is a command in the execvp() function or do I need to implement something for that specific purpose?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_LINE 80
/* 80 chars per line per command */
int main(void) {
//char *args[MAX_LINE/2 + 1];
char *args = calloc(MAX_LINE, (MAX_LINE/2 +1));
const size_t sz = MAX_LINE;
pid_t pid;
/* command line (of 80) has max of 40 arguments*/
int should_run = 1;
while (should_run) {
printf("osh>"); //beginning of command line
fgets(args, sz, stdin); //gets the stdin
char *token = strtok(args, " \n"); //supposed to break str if it has a space or line and recognize there are 2 commands
printf("%s\n", token);
token = strtok(NULL," \n");
printf("%s\n", token);
pid_t parent = getpid();
pid = fork(); //forking child
if(pid == 0){ //if forking occurred
int status = execvp(&args[0], &args); //status of input, is it a command?
printf("%d", status);
printf("forked!");
if(status == -1) { //if cmd err, print
printf("no cmd");
return 1;
} else {
printf("line will be printed");
}
return 0;
}
fflush(stdout); //flush
/*
* After reading user input, the steps are :
* 1: fork a child process
* 2: the child process will invoke execvp()
* 3: parent process waits for the child to exit before
continuing
*/
}
exit(0);
/**
return to the operating system:
-exit this process
-flush all
*/
}
If you look at the documentation for the exec family of functions, you'll note that the functions only return if the exec failed. That's because exec, when successful, completely replaces the calling process with the invoked program.
What you need to do is, from the parent process (i.e., the one that got a positive value returned from fork), wait on the child process via waitpid.
pid_t pid;
pid = fork();
if ( pid < 0 ) {
// Handle the error.
}
else if ( pid == 0 ) {
execvp(&args[0], &args);
// The fact that we've reached this line means that execvp failed.
exit(1);
}
else {
int status;
while ( waitpid(pid, &status, 0) != pid ) {} // We need this loop in case waitpid gets interrupted by a signal.
// status doesn't equal the return value of the child process. We need to extract that with macros.
if ( WIFEXITED(status) ) {
printf("Child process exited with code %i\n", WEXITSTATUS(status));
}
else {
printf("Child process was terminated by signal number %i\n", WTERMSIG(status));
}
}
I'm using popen to read the output of a third party program. I'd like to detect and restart things if the sub-program fails.
How would I do that? If the child dies, the process didn't exit normally and therefore can't use WEXITSTATUS to check.
Is there another way?
Here's a simple example:
PINGER.C
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
int i = 0;
while (1)
{
//fprintf(stderr, "StdErr %d\n", i);
printf("stdout %d\n", i++);
fflush(stdout);
if (i == 5)
i = i / 0; // Die a horrible death
sleep(1);
}
}
WATCHER.C
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int
main(int argc, char **argv)
{
char *cmd = "./pinger";
printf("Running '%s'\n", cmd);
FILE *fp = popen(cmd, "r");
if (!fp)
{
perror("popen failed:");
exit(1);
}
char inLine[1024];
int bytesRead = 0;
int i = 0;
while (fgets(inLine, sizeof(inLine), fp) != NULL)
{
int len = strlen(inLine);
if (inLine[len-1] == '\n')
inLine[len-1] = '\0';
printf("Received: '%s'\n", inLine);
}
printf("feof=%d ferror=%d: %s\n", feof(fp), ferror(fp), strerror(errno));
int rc = pclose(fp);
printf("pclose returned: %d. IFEXITED=%d\n", rc, WIFEXITED(rc));
}
Here's the output:
$ ./popenTest
calling popen
Running './pinger'
pipe open
Received: 'stdout 0'
Received: 'stdout 1'
Received: 'stdout 2'
Received: 'stdout 3'
Received: 'stdout 4'
feof=1 ferror=0: Success
pclose returned: 8. IFEXITED=0 EXITSTATUS=0
(According to this post, you actually can't use WEXITSTATUS if the command didn't exit normally, but I tried anyway)
Read the POSIX specification of pclose() (and popen() too). It says:
Return value
Upon successful return, pclose() shall return the termination status of the command language interpreter. Otherwise, pclose() shall return -1 and set errno to indicate the error.
Thus, you can get the exit status of the process indirectly via the return value of pclose(). That will be a number between 0 and 255. Shells often report the 'death of a child by signal' by returning the value 128 + signal_number. The specification outlines circumstances in which the status may not be available (your program called wait() and got the information for the process opened by popen() before you called pclose(), for example). Reading the specification of popen() explains the use of 'the command language interpreter' in the specification of pclose().
A process returns an exit status by returning from its main() with an exit code, or by calling _exit(statuscode). If the process is terminated abnormally, for example due to a signal or a fault, the process never gets a chance to do any of those, so there is no exitstatus.
In that case, all you can know is that the process terminates with an error.
If you want to restart on all cases where a program terminates on error, you need to check both WIFEXITED and WEXITSTATUS:
do {
rc = run_your_child_process();
} while (!WIFEXITED(rc) || WEXITSTATUS(rc) == 0);
// child terminated without error
//code for foo (run executable as ./a.out)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/wait.h>
int main (int argc, char **argv) {
pid_t pid;
pid = fork();
int i = 1;
char *parms[] = {"test2", "5", NULL}; //test executable named test2
if(pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
}
else if(pid == 0) {
printf("Child pid is %d\n", pid);
i = execv("test2", parms); //exec call to test with a param of 5
}
else {
wait(NULL);
}
printf("I is now %d\n", i); //i is still 1 here, why?
return 0;
}
Hey everybody, I am trying to learn a little bit about fork and execv() calls. I make my foo.c program above make a call to a file I have named test.c. I fork a child and have the child make a call to execv, which will just add 10 to the parameter read in. I am unsure of why the variable does not change, at the bottom of my foo.c function. Does the call need to be a pointer or return an address? Any help would be greatly appreciated. Thanks
Code for test.c (executable named test2)
#include <stdio.h>
int main(int argc, char ** argv[]) {
int i = atoi(argv[1]);
i = i +10;
printf("I in test is %d\n", i);
return i;
}
You only call execv() in the child process. The exec() family functions never return if it runs successfully. See evec(3):
The exec() functions only return if an error has occurred. The return value is -1, and errno is set to indicate the error.
You printed the value of i in the parent process, it never changed in the parent process.
To get the exit status from the child process, you can make use of wait() or waitpid():
else {
int waitstatus;
wait(&waitstatus);
i = WEXITSTATUS(waitstatus);
}
I'm trying to make a program which is getting 2 pathes for files to main, and calling linux' cmp command in order to compare them.
If they equal, I want to return 2, and if they're different, 1.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, const char* argv[])
{
pid_t pid;
int stat;
//child process
if ((pid=fork())==0)
{
execl("/usr/bin/cmp", "/usr/bin/cmp", "-s",argv[1], argv[2], NULL);
}
//parent process
else
{
WEXITSTATUS(stat);
if(stat==0)
return 2;
else if(stat==1)
return 1; //never reach here
}
printf("%d\n",stat);
return 0;
}
For some reason if the files are the same, I do succeed in returning 2, but if they're different, it won't go into if(stat==1), but to return 0.
Why is this happening? I checked that cmp on the files through terminal does truly return 1 if they're different, so why this doesnt work?
Do it like this:
//parent process
else
{
// get the wait status value, which possibly contains the exit status value (if WIFEXITED)
wait(&status);
// if the process exited normally (i.e. not by signal)
if (WIFEXITED(status))
// retrieve the exit status
status = WEXITSTATUS(status);
// ...
In your code:
WEXITSTATUS(&stat);
Tries to extract a status from a pointer, but WEXITSTATUS() takes int as parameter.
Must be:
WEXITSTATUS(stat);
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?
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.
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.
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;
}
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 woundn't still be here if execl() was successful,
* so a non-zero exit value is appropriate.
*/
return 1;
}
return 0;
}
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.
How about like this:
char* cmd = "./foo 1 2 3";
system(cmd);
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);