Restart C program from Bash terminal - c

I've been working on my school project and I've been stuck on this step for a few days now. Any kind of help would be highly appreciated!
What I've tried so far:
Compiling the script. It compiles correctly and I'm able to run it by typing ./process.o, however I cannot make it so when I kill it, it restarts. I've been googling and trying various things but nothing seems to work, it always kills the process but doesn't restart it.
kill -SIGKILL (PID)
kill 2 (PID)
kill 1 (PID)
kill -HUP 3155
Various other commands that only killed it, nothing seems to work. Do I have to modify the code or something? I'm deeply confused.
Here's what I have to do:
Make a new file with C. Save it with name process.c (Did this)
#include <stdio.h>
#include <unistd.h>
int main() {
printf("Creating a background process..\n");
pid_t pid = fork();
if (pid > 0) return 0; /* Host process ends */
if (pid < 0) return -1; /* Forking didn't work */
while(1) { } /* While loop */
return 0;
}
Compile the following code to working program called process.o and start the process. (Did this, works to this point)
Use a kill command which restarts the process.o (Killing the process works, but it doesn't restart it)

You need to keep the parent process running to monitor the child process. If the parent detects that the child is no longer running, it can restart it.
The parent can use the wait system call to detect when the child exits.
while (1) {
pid_t pid = fork();
if (pid < 0) {
return -1;
} else if (pid > 0) {
// parent waits for child to finish
// when it does, it goes back to the top of the loop and forks again
wait(NULL);
} else {
// child process
while (1);
}
}

Related

Running bash in interactive mode stops my own shell

I'm writing a shell as a hobby and more specifically because I'm bored but passionate. My shell works great, I even implemented pipelines. But there is one thing that keeps my shell crashing or entering in a for loop and it's only happening when I run bash through my shell.
So I'm in trouble when I issue this command bash -ic <some_command>. If my shell is the default one and I launch an instance and I issue this command above, my shell gets in an infinite loop. Whereas if the default shell is bash and I launch an instance then I run my shell through the first bash prompt and THEN run bash -ic <some_command> through my shell, it gets stopped and I'm back to bash.
Here is a minimal example of the main issue:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void loop_pipe(char ***cmd)
{
pid_t pid, wpid;
int status;
pid = fork();
if (pid == 0)
{
// Child process
if (execvp((*cmd)[0],*cmd) == -1)
perror("Command error");
exit(EXIT_FAILURE);
}
else if (pid < 0)
{
// Error forking
perror("Fork error");
}
else
{
// Parent process
do {
wpid = waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
}
int main()
{
char *ls[] = {"bash", "-ic", "uname", NULL};
char **cmd[] = {ls, NULL};
while (1)
{
loop_pipe(cmd);
}
}
The problem here is that after running the command, the process gets stopped so the output is this:
./a.out
Linux
[4]+ Stopped ./a.out
I really don't now what's causing this, but it has to do with bash conflicting with my shell. I also tried to ignore SIGINT and SIGSTOP But it still gets stopped (by bash i guess ?) If someone could help the situation that would be great.
Because my project has more than one source file, I link it not sure if it's right way to do it.

Fork() and execv() not running in parallel, why?

I'm trying to run a series of commands through execv() and forking a new process in C to run each one, and yet for some reason they aren't running in parallel. The following code is run for each process, with "full" being the filepath and "args" being the arguments. I know that the execv() part isn't the issue, it has to do with the way I'm forking and waiting.
int status;
pid_t pid = fork();
if (pid == 0) {
execv(full, args);
//perror("execv");
} else if (pid < 0) {
printf("%s\n", "Failed to fork");
status = -1;
} else {
if (waitpid(pid, &status, 0) != pid) {
status = -1;
return status;
}
}
When running this code, the forked commands simply run one after the other. I don't know how this could be happening.
If you don't want to wait for each child process, don't call waitpid immediately; as written, you fork a child, then immediately stop all processing in the parent until the child process exits, preventing you from forking any further children. If you want to launch multiple children without leaving zombie processes lying around (and possibly monitoring them all at some point to figure out their exit status), you can do one of:
Store off the pids from each fork in an array, and call waitpid on them one by one after you've launched all the processes you need to launch
Store a count of successfully launched child processes and call wait that many times to wait on them in whatever order they complete.
Ignore the SIGCHLD from the child processes entirely, for when you don't care when they exit, don't need to know their status, etc.

fork() - have parent process do work without waiting for child process

I'm making a shell in C for a school project that is capable of running processes in parallel if it is commanded to do so.
This is the loop of the shell application that waits for commands:
while (1) {
action = parseShellArgs();
if (action == 1) {
printf("Exiting...\n");
break;
} else if (action == 0) {
int pid = fork();
if (pid < 0) {
printf("Failed to fork\n");
} else if (pid == 0) {
(*NUM_PROCESSES_RUNNING)++;
printf("There are %d processes running\n", *NUM_PROCESSES_RUNNING);
char * solverArgs[] = {"a", shellArgs[1], NULL}; // first element is placeholder for argv[0]
execv("CircuitRouter-SeqSolver", solverArgs);
exit(0);
} else if (pid > 0) {
if (*NUM_PROCESSES_RUNNING >= MAXCHILDREN) {
printf("All processes are busy\n");
continue;
}
int status, childpid;
wait(&status);
childpid = WEXITSTATUS(status);
(*NUM_PROCESSES_RUNNING)--;
printf("There are %d processes running\n", *NUM_PROCESSES_RUNNING);
(void)childpid; // suppress "unused variable" warning
} else {
printf("Wait what\n");
}
} else {
printf("Oops, bad input\n");
}
}
Please do disregard the constants being incremented and decremented.
Now, this only works partially. Whenever I give it a command to create another process and run another program (condition action == 0, this has been tested and works), the fork happens and the program is correctly executed.
However, I cannot fork multiple times. What I mean by this is: the program forks and the child executes as instructed in the execv call. The problem is that instead of the parent process then goes back to expecting input to possibly fork again, it waits for the child process to finish.
What I am trying to make this cycle do is for the parent to always be expecting input and forking as commanded, having multiple children if necessary. But as I explained above, the parent gets "stuck" waiting for the single child to finish and only then resumes activity.
Thank you in advance.
Edit: I have experimented multiple combinations of not waiting for the child process, using extra forks to expect input etc.
From man wait.2
The wait() system call suspends execution of the calling process until
one of its children terminates.
Your program gets stuck because that's what wait does. Use waitpid instead with WNOHANG.
waitpid(pid_child, &status, WNOHANG);
doesn't suspend execution of the calling process. You can read the waitpid man page to find out the return values and how to know if a child terminated.

finding process id using program name

My program receives a string (a shell script's path) as input. Now I have to launch that shell script and find out the process id for it.
I'm using the system() function to launch a shell script and after that using popen() with ps -aef | grep "ShellScript" to get its PID.
It's being suggested to me that there's a better way to do it. The way I did it will give a wrong PID if multiple scripts are running at same time.
What is the correct way to get a PID for a given script name after launching it?
Firstly you should not use system().
A better approach would be using fork(), which returns a PID > 0 if you are in the parent process and return 0 if you are in the child.
Any other return satus is an error and errno is set accordingly.
When you are in the child process you should exec your command, while you should either wait for it in the parent one if you want to avoid to have a zombie process or handle SIGCHLD signal.
Always read man for better insight.
Here is a brief example
int pid = -1;
If((pid = fork()) > 0)
{
/* Parent process*/
wait(NULL);
}
else if(pid == 0)
{
/*Child process*/
execv(....);
exit (0);
}
else
{
/*Error*/
perror("fork()");
}

fork() function will never return 0

I am currently trying to run a fork function in C where in the child section of the code,
I am trying to execute a command using exacvp, but before the execution I am trying a printf function which never executes. I ran this in debug and I have noticed that the pid is never assigned 0. I did try a simple fork example on a separate project and it worked smoothly. Does anyone have an idea why the child section never executes?
int startProcesses(int background) {
int i = 0;
while(*(lineArray+i) != NULL) {
int pid;
int status;
char *processName;
pid = fork();
if (pid == 0) {
printf("I am child");
// Child Process
processName = strtok(lineArray[i], " ");
execvp(processName, lineArray[i]);
i++;
continue;
} else if (!background) {
// Parent Process
waitpid(pid, &status, 0);
i++;
if(WEXITSTATUS(status)) {
printf(CANNOT_RUN_ERROR);
return 1;
}
} else {
i++;
continue;
}
}
return 0;
}
stdio files are flushed on program's exit, but execvp directly replaces the process with another image, bypassing the flush-at-exit mechanism and leaving the I am child message in memory never to be sent to the screen. Add an explicit fflush(stdout) before execvp, or end your string with \n so that it is automatically flushed when running on a TTY.
Note that execvp never exits, and if it does, it is because it has failed to execute the new process. At that point, the only thing the child can do is to report an error and call _exit(127) (or similar exit status). If the child continues, an incorrectly configured command name will cause it to execute the rest of the parent's loop in parallel with the parent. This process will continue for other descendants, effectively creating a fork bomb that can grind your system to a halt.

Resources