Fork failing in C - c

I'm having a problem with fork running in a function I'm using to create a terminal for a school project.
This function is called to handle the user input when they type in a command:
void handleExternalCommands(char ** arr)
{
pid_t pid;
pid = fork();
printf("pid is ", (long) pid);
if (pid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
int status = execvp(arr[0], arr);
printf("im in the child process");
if (status == -1)
{
// error handle
}
}
wait();
}
However, no matter what I type in, I can't actually make it inside of the if statement. If I try to find out what's going on with pid by using:
printf(pid);
I get a segmentation fault error?
Thanks for your help in advance, everyone.
UPDATE:
I've changed the code to what it is above. Printing the pid only happens once and it prints nothing: "pid is "

If the execvp() works, the printf() is never executed. You'd only see the message from printf() if (a) you added a newline to the end and (b) the execvp() failed. (OK: you might see it eventually even without a newline, but the newline is a good idea.)
Move the printf() to before the execvp() and (definitely) add the newline and you should see the information. See also printf() anomaly after fork(), but note you are running into a different consequence of not terminating printf() output with newlines.
As to printf(pid) crashing, you need to read the manual on printf()
and add compiler options so you get told about erroneous use.
You probably need:
printf("PID %d\n", pid);
That assumes that pid_t is sufficiently compatible with int not to run into trouble — a moderately safe assumption, but one which can be avoided by writing:
printf("PID %d\n", (int)pid);
(or use int pid; as the definition). But the key point is that you need to use printf() correctly, and execvp() does not return unless it fails.

Related

c execute external program multiple times

i'm trying to call an external program from my code with some arguments. As i'm trying to see how different parameters change it's output i have to run it multiple times (about 1000 times). Every time the external program runs i'm just interested in one line of its output although it is printing a lot of (for my purpose) useless stuff. The line i'm interested in is right above the special identifier("some_signal") in the output. So i thought i'll wait till this line appears and read the line above.
I tried the following:
pid_t pid = 0;
int pipefd[2];
FILE* output;
char line[256]; // pipe read buffer
char prev_line[256]; // prev. line pipe buffer
char signal[] = "some_signal\n";
int status = 0;
double obj_Val;
pipe (pipefd); //create pipe
pid = fork (); //span child process
if (pid == 0)
{
// redirect child's output to pipe
close (pipefd[0]);
dup2 (pipefd[1], STDOUT_FILENO);
dup2 (pipefd[1], STDERR_FILENO);
execl ("/some/path",
"some/path",
"some_argument", (char*) NULL);
}
else if (pid < (pid_t) 0)
{
printf("fork failed \n");
return EXIT_FAILURE;
}
else
{
// get child output to pipe
close (pipefd[1]);
output = fdopen (pipefd[0], "r");
while (fgets (line, sizeof(line), output), signal != NULL)
{
if(strcmp(line, signal) == 0)
{
obj_Val = atof (prev_line);
kill (pid, SIGTERM);
waitpid (pid, &status, WNOHANG);
kill (pid, SIGKILL);
waitpid (pid, &status, 0);
break;
}//end if
strcpy (prev_line, line);
}//end while
}
This works fine for like 100 runs or so and then one out of two errors occurs. The first one is a segmentation fault. The second one is the calling program printing out all the output of the called program (without the line containing the wanted signal) and goes into an infinite loop (my guess is, since the signal is missing the while loop won't terminate).
Maybe someone can provide a hint or a link where to look and what to look for, or preferably tell me what i'm doing wrong.
Your while condition is broken: signal != NULL is always true, as signal is an array; and because of the comma , operator the entire condition is always true.
And because of the following, you're not checking the return value of fgets, which means that nothing was read and the buffer is uninitialized.
Also prev_line is not initialized before you do atof on it for the first time.
In any case, compile with -Wall -Werror and fix the remaining errors.

Writing a shell in C for linux, exec for one certain process is infinitely looping

This is the relevant snippet of code:
if(!strcmp(args[0],"run")){
pid_t pid = fork();
if(pid == 0){
execvp(args[1], args);
fprintf(stdout, "Process could not be found in this directory\n");
kill((int)getpid(), SIGKILL);
}
else{
if(pid < 0)
exit(1);
fprintf(stdout, "PID of Process = %d\n", pid);
int success = waitpid(pid, &childExitStatus, WUNTRACED | WCONTINUED);
if(success == -1)
exit(EXIT_FAILURE);
}
}
Now when I run a process like Libre Office math, it will only open one instance of it. However, when I try to open xterm using this code, it will continue to exec over and over, creating many instances of xterm before I do an interrupt and exit. I don't see any loops that would cause this to happen. Any insight into why this would be?
The execvp() call is incorrect because it passes an additional argument "run" at the start. When executing xterm in this manner, the effect is similar to xterm xterm and has xterm use xterm as the shell. The new xterm inherits a SHELL environment variable that causes it to start another xterm, until limits are exhausted.
In addition to jilles' answer to your immediate problem, you should know that calling fprintf if execvp fails is unwise as it can lead to duplication of previously-buffered output. It also means you cannot safely use vfork, which can still be a valuable optimization (particularly if the parent process uses a lot of memory).
There is no good way to report an exec failure, unfortunately. I tend to just do
if (pid == 0) {
execvp(...);
/* if we got here, something bad happened */
_exit(127);
}

how to use correctly fork() and exec()

I have this code;
pid_t process;
process = fork();
if (process < 0){
//fork error
perror("fork");
exit(EXIT_FAILURE);
}
if (process == 0){
//i try here the execl
execl ("process.c", "process" , n, NULL);
}
else {
wait(NULL);
}
I don't know if this use of fork() and exec() combined is correct. When I try to run the program from the bash I do not receive any result, so I thought it could be a problem in this part of code.
Thanks.
One problem is that
if (process = 0){
should read
if (process == 0){
Otherwise you're assigning zero to process and only calling execl if result is non-zero (i.e. never).
Also, you're trying to exec something called process.c. There's no doubt that one could have an executable called process.c. However, conventionally names ending in .c are given to C source code files. If process.c is indeed a C file, you need to compile and link it first.
Once you've built the executable, you need to either place it somewhere on $PATH or specify its full path to execle(). In many Unix environments placing it in the current directory won't be enough.
Finally, it's unclear what n is in the execle() call, but the name hints at a numeric variable. You need to make sure that it's a string and not, for example, an integer.
Well as per the answers and comments above your code should look somewhat like this
pid_t process;
process = vfork(); //if your sole aim lies in creating a child that will ultimately call exec family functions then its advisable to use vfork
if (process < 0)
{
//fork error
perror("fork");
exit(EXIT_FAILURE);
}
if (process == 0)
{
//i try here the execl
char N[MAX_DIGITS];//A correction here
itoa(n,N);//write this function yourself
execl ("process", "process" , N, NULL);// Here process is the name of the executable N is your original argument
fprintf(stderr,"execl failed\n");//check for error in execl
}
else
{
wait(NULL);
}
Notice the use of vfork instead of fork.Its because it would be much more efficient.The reason could be found here

c: catch a segfault in exec() which was run in a child process

EDIT:
I am trying to write a simple smoketest, where all options and reasonable parameters are tested.
I used popen() to execute the program that should be tested.
Using this approach does not work, because if the process dies with a signal (SIGINT, SIGSEGV...) the pipe from popen() does not tell me what happend.
Writing a signal handler did not help since popen creates a new process that receives the signals but not my smoketest.
Thanks to the answers i used pipe(), fork() and execv() to create my own popen()-version.
When the program now segfaults there is the problem that the pipe is useless (a read caused weird behavior -> blocked the process until i send a sigkill to the parent!)
To avoid this i tried different things and my solution is the following (it is simple but it took me a while to figure it out). so here is my example-code:
static int child_dead = 0;
void sigaction_sigchld(int signal) { /* Child died */
child_dead = 1;
}
int main(int argc, char *argv[], char *env[])
{
char *crashing_program = "/program_path/and_name";
int ret;
int byte;
pid = fork();
if(pid == 0) /* Child */
{
execve(crashing_program, argv, env);
/* if execve returns that it mus have failed! */
fprintf(stderr, "Exec failed\n");
_exit(-1);
} else /* Parent */
{
if(!child_dead)
{
byte = read(pipe_out[1], line, BUFFSIZE);
if(!byte){
perror("Smoketest:Line:xxx");
} else
{
fprintf(stdout, line);
}
}
wait(&child_status);
/*
check if the child died with SIGSEGV etc
*/
}
This seems to work fine as long as i only have one child at a time which is sufficient for me though. I anyone has a better idea or any tipps for me i would be glad to update this entry.
Last but not least: Of course using this method it is probably impossible to do any cleanup.
Cheers.
See the documentation for waitpid(2). There are a bunch of macros you can use to test how the child process was terminated. In particular, you can use WIFSIGNALED() and WTERMSIG() to test if the child process was terminated by a signal, and if so, which signal:
int status = pclose(...);
if (WIFSIGNALED(status))
{
// It was terminated by a signal
if (WTERMSIG(status) == SIGSEGV)
{
// It was terminated by a segfault
}
}
Edit: As stated in the comments, you'd rather make use of fork and exec, then use waitpid(2) to correctly update status.

execv, wait, Unix programming, How to wait for a child

Hi I'm working on a unix shell and I'm running into two problems. I was wondering if any of you could help me out. My first problem is that the shell is not waiting for the child process to terminate. I can actually go type more commands while the child process is running. My second problems is in the following two lines. I'm not getting any display on the shell.
fprintf(stderr, "Process name is: %s\n", commandArgv[0]);
fprintf(stderr, "Child pid = %d\n", pid);
I have the following method to execute a process entered by the user: i.e. firefox, ls -a, etc
void execute(char *command[], char *file, int descriptor){
pid_t pid;
pid = fork();
if(pid == -1){
printf("error in execute has occurred\n");
}
if(pid == 0){
execvp(*command,command);
fprintf(stderr, "Process name is: %s\n", commandArgv[0]);
fprintf(stderr, "Child pid = %d\n", pid);
wait(&status);
exit(EXIT_SUCCESS);
}
else{
printf("ignore for now\n");
}
}
This is where I call the execute command. It works fine and launches a process, but it doesn't wait for it to finish.
execute(commandArgv, "STANDARD",0);
Do you guys have any idea what I might be doing wrong? Thanks I really appreciate any time you take to help me on this.
Once execvp() runs, it will never return. It replaces in-memory the running app with whatever was provided. So your fprintf() and wait() are in the wrong place.
Other than getting the actual logic worked out correctly (Stéphane's suggestions all good) you might also want to fflush(stderr) after fprintf-ing, to ensure your error messages make it out right away instead of being buffered.
You have a little error in how the process works. After execvp is called, there is no turning back. fork() gives you have the parent and an identical child, but execvp overwrite child image to be the command you are calling.
The execvp returns only when a severe errors occur that prevent overwriting the image. So, you need to print things before its call. So you also may want to change the EXIT_SUCCESS to an EXIT_FAILURE there.
Now there is another mistake using wait: you always want the parent waiting for the child, not the other way around. You cannot ask for the child to wait. She has nothing to wait, she will run and terminate. So, you need to move the wait() call to the else part.
void execute(char *command[], char *file, int descriptor)
{
pid_t pid;
pid = fork();
if(pid == -1)
{
printf("fork() error in execute() has occurred\n");
return; /* return here without running the next else statement*/
}
if(pid == 0)
{
fprintf(stderr, "Process name is: %s\n", commandArgv[0]);
fprintf(stderr, "Child pid = %d\n", getpid());
execvp(*command,command);
fprintf(stderr, "Error! Can't overwrite child's image!\n");
exit(EXIT_FAILURE);
}
else
{
printf("Parent waiting for child pid: %d\n", pid);
wait(&status);
printf("Parent running again\n");
}
}
But reading your question, maybe you actually don't want the parent to wait. If that is the case, just don't use the wait() function.
Take care,
Beco
Edited: some minor mistakes. pid of child is getpid()

Resources