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);
Related
I'm doing this assignment in which a number of child processes are generated and if they're aborted (ctrl-\ or ctrl-4) the parent process should run instead. This is the code:
int main(int argc, char *argv[])
{
/* The rest of the code is omitted. "times", "arg1"
and "cmd1" are parameters passed when running the program */
for(cont = 0; cont < times; cont++)
{
pid = fork();
if(pid == 0)
execvp(arg1,cmd1);
else if (pid >0) {
wait(&status);
if (WCOREDUMP(status) !=0)
printf("Core dump generado\n");
}
}
return 0;
}
The program runs a Linux command a number of times, with argv[1] being the number of times, and arg[2], argv[3] and so on the Linux command itself.
It runs fine if it's not cancelled. But when I try to abort it (for instance using a sleep command and then typing ctrl-4):
./ntimes 2 sleep 10
^\Quit (Core dumped)
it generates a dump. I want the parent process to print a message instead. I've tried with signal handling functions and many other things, but I can't seem to make it work.
SIGQUIT targets the whole foreground process group of your terminal—it kills the parent along with the child.
To prevent it from killing the parent, you need to either:
ignore it or block it in the parent
catch it in the parent
With approach 1., you'll need to unblock it/unignore it in the child before execing.
With approach 2., the signal disposition will be automatically defaulted upon execing so it won't affect the child, however, having at least one signal handler will open your application up to the possibility of EINTR errors on long-blocking syscalls such as wait, so you'll need to account for that.
Here's an example of approach 2. You can try it on e.g., ./a.out sleep 10 #press Ctrl+\ shortly after this.
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>
void h(int Sig){}
int main(int argc, char *argv[])
{
sigaction(SIGQUIT, &(struct sigaction){.sa_handler=h}, 0);
int cont, status, times=1;
pid_t pid;
for(cont = 0; cont < times; cont++)
{
pid = fork();
if(pid == 0)
execvp(argv[1],argv+1);
else if (pid >0) {
// retry on EINTR
int rc; do{ rc=wait(&status); }while(0>rc && EINTR==errno);
if (0>rc) return perror("wait"),1;
if (WIFSIGNALED(status)){
if (WCOREDUMP(status))
printf("Core dump generado\n");
}
}
}
return 0;
}
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);
I'm trying to get the results of each run of the program (both the parent and child). The results print once on the screen and only once in a file. I can't seem to get two unique files created (one representing parent and one representing child). I'm not sure if getpid() is the effective way to separate parent and child identification. What could I be doing wrong?
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static char *app1="/path/to/app1";
static char *app;
static pid_t forky=-1;
void otherfunction(){
int aflag=1;
//do something
if (aflag==1){
//run app 1
app=app1;
printf("Starting fork\n");
forky=fork();
}
}
int main(){
char dat[40000],test[10000];
sprintf(dat,"Exec start\nFORKY = %d\nPID = %d\nPPID = %d\n",forky,getpid(),getppid());
sprintf(test,"/TEST%d",getpid());
int h=open(test,O_WRONLY|O_CREAT);
write(1,dat,strlen(dat));
write(h,dat,strlen(dat));
close(h);
otherfunction();
return 0;
}
You're creating the file before you call fork. The fork is the last thing you do and then both processes just return 0.
As specified in fork's man page, the process created by calling fork is a copy of the parent process except for some specific differences, and this child process starts execution as if resuming from after the call to fork. So, it's kind of like you get two returns from fork, one for the parent and one for the child. So, it looks like you ask two questions here:
How to differentiate parent and child
Again, the man page mentions that fork will return the child's pid in the parent process and 0 for the child process so the following code sample will get you distinguished output from both:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
pid_t pid = fork();
if (pid == 0)
printf("Hello from child!!!\n");
else if(pid > 0)
printf("Hello from parent!!!\n");
else
printf("Wow, fork failed!!!");
return 0;
}
Obtaining separate files for each process
As mentioned above, both processes resume from after the call to fork, so the files must be created after calling to fork. In your example you are calling otherfunction last in main, so fork is pretty much the last call in both processes.
The following is an example that will give you different files with different content for each process, as well as print in stdout for each process. The usage of getpid here is just so you can actually check what the man page says.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv)
{
pid_t pid = fork();
int h;
char *test;
char dat[100];
if (pid == 0)
test = "child";
else if(pid > 0)
test = "parent";
else
test = "failed";
h = open(test,O_WRONLY|O_CREAT);
sprintf(dat, "%s | fork returned = %d | my_pid = %d\n", test, pid, getpid());
write(1,dat,strlen(dat));
write(h,dat,strlen(dat));
close(h);
}
//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 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);