Value modification inside child doesn't update - c

Im trying to modify an int inside a child process when fork(); but I cant get the program to update it more than once, my idea is to add a counter that displays to screen that shows how many bg where (when & is at the end of the line), but I don't know why it's not working. Now I'm trying this but it doesn't work either, maybe I should modify the value in the parent process? This it the code:
void execute(char **tokens, int token_Size, int *blk){
pid_t pid, wpid;
int status;
int result;
int flag;
int isPipe;
int output;
int input;
int isAmper;
pid = fork();
if (pid == -1)
{
perror("Fork:");
exit(1);
}
else if (pid == 0)
{
isAmper = needs_amper(tokens, token_Size);
output = needs_out_redir(tokens, token_Size);
input = needs_in_redir(tokens, token_Size);
isPipe = needs_pipe(tokens, token_Size);
static int bloq = 1;
if (isAmper != -1)
{
*blk +=1;
printf("[%d] %d \n", *blk, getppid()); //-> [blk] is the job number asigned to the job
tokens[isAmper] = NULL;
}
if (strcmp(tokens[0], "echo") == 0)
{
for (int i = 1; tokens[i]; i++)
{
printf("%s ", tokens[i]);
}
}
flag = 0;
if (output != -1)
{
redirect_output(tokens, output);
tokens[output] = NULL;
flag = 1;
}
if (input != -1)
{
redirect_input(tokens, input);
tokens[input] = NULL;
flag = 1;
}
if (isPipe != -1)
{
create_pipe(tokens, output, input, isPipe);
}
if (flag || isPipe == -1)
{
execvp(tokens[0], tokens);
perror("Unkown Command:");
exit(1);
}
// exit(0);
}
else // Main (parent) process after fork succeeds
{
while ((wpid = wait(&status)) > 0)
; // this way, the father waits for all the child processes
result = waitpid(pid, &status, 0);
if (result == 1) //If the process terminated correctly, result returns 0.
{
printf("The child process terminated with an error!.\n");
}
}}
I'm trying to modify the blk value passed to the execute function, I tried using an inside value also, but doesnt work either.
To make my self clearer. I want that when I type in my custom shell something with an '&' at the end it return something like this:
ivo#ivo-Surface-Pro-6:/home/ivo/Documents/SO1/soi-myshell-Ivoo25$ echo hola &
[1] 10853
hola
And the next time I type something with the & at the end..
[2] 10853
main.c main.o Makefile myshell myShell.c myShell.h myShell.o README.md
I think that what Im trying to do cant be done because the pid is the same in every execution, maybe is that?

I managed to get it, I added the same function
needs_amper(tokens, token_Size)
but outside the child process, before the fork inside an if function veryfing that it returns a value higher than 0

Related

waitpid hangs even though child process is dead

i have the following function:
int run_func(command history[MAX_INPUT_SIZE], char** args, int capacity) {
int need_to_wait = 1;
int i = 0;
char* arg = args[0];
int status;
while (arg != NULL) {
if (strcmp(arg, "&") == 0) {
need_to_wait = 0;
break;
}
arg = args[i++];
}
pid_t wait_pid;
pid_t pid = fork();
int res;
if (pid == 0) {
res = execvp(args[0], args);
if (res == -1) {
printf("exec failed\n");
fflush(stdout);
return 0;
}
} else if (pid < 0) {
printf("fork failed\n");
fflush(stdout);
return 0;
} else {
if (need_to_wait){
do {
wait_pid = waitpid(pid, &status, 0);
} while(!WIFEXITED(status) && !WIFSIGNALED(status));
}
history[capacity - 1].pid = pid;
}
return 1;
}
the issue I have is that the bottom while loop, hangs and doesn't stop whenever I get an invalid command such as 'hello' from the user from the terminal until I press enter again.
this function is being called from another function that receives input from the user.
Copying comment into an answer.
Side issues:
Error messages should be printed to stderr, not stdout.
There's no need to save or test the return value from execvp() — if it returns, it failed; if it succeeds, it does not return.
Main observation:
You should almost certainly have an exit() or _exit() instead of return 0; in the error handling code after execvp(). When the command fails (hello?), then you end up with two processes running — one from the failed execvp() and one is the parent process. This is apt to confuse everything as you have two processes trying to read the terminal at the same time.

Pipe's related arguments to pass to a function?

I'm a beginner in C programming and I started learning about pipes today.
I need them because my program has to run up to 4 processes at the time, so to avoid creating more processes than those required, I have to use a shared variable between all of them to keep track how may can still be created.
I tried to simplify my program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void forking(int p, int pid);
int main(int argc, char *argv[])
{
int fd[2];
int p = 4; // Max number of processes that can run at the same time
int pid;
if(pipe(fd) == -1)
{
perror("pipe: ");
return 0;
}
//It will try the function forking 10 times to execute SOME CODE that
// changes everytime something operates on it
for(int i = 0; i < 10; i++)
{
forking(p, pid);
}
return 0;
}
void forking(int p, int pid)
{
if (p > 0) //We can create another process
{
p -= 1; // update the p before creating a child process
write(fd[1], &p, (sizeof(int)*3)); //Tell everyone about the update
pid = fork();
if (pid == 0)
{
//The child process turn to elaborate SOME CODE
// SOME CODE
// Then there will be a point where
// we will need to check if the p has been modified!
read(fd[0], &p, sizeof(int)*3);
//So that forking can decide whether we can create another process
// to operate on SOME OTHER CODE
forking(p, pid);
//Once we are done, we can terminate the child
//but first we'll need to update the process n° p
p += 1;
write(fd[1], &p, (sizeof(int)*3));
exit(0);
}
else if(pid > 1) //Father time
{
// check the updated value
//the father will do nothing
// since a process it's already on it (on the SOME CODE part)
return;
}
}
else
{
//else the father does SOME CODE itself
// SOME CODE
}
return;
}
My 2 doubts is whether I should pass something else to the function "forking" (which can be recursive), like "fd", or if it is okay to just leave the code like this, and whether this will have the desired result.
Hopefully I made myself clear enough.
EDIT 1:
void forking(int p, int pid, int *fd)
{
if (p > 0) //We can create another process
{
p -= 1; // update the p before creating a child process
write(fd[1], &p, (sizeof(int)*3)); //Tell everyone about the update
pid = fork();
if (pid == 0)
{
//The child process turn to elaborate SOME CODE
// SOME CODE
// Then there will be a point where
// we will need to check if the p has been modified!
read(fd[0], &p, sizeof(int)*3);
//So that forking can decide whether we can create another process
// to operate on SOME OTHER CODE
forking(p, pid, fd);
//Once we are done, we can terminate the child
//but first we'll need to update the process n° p
p += 1;
write(fd[1], &p, (sizeof(int)*3));
exit(0);
}
else if(pid > 1) //Father time
{
// check the updated value
//the father will do nothing
// since a process it's already on it (on the SOME CODE part)
return;
}
}
else
{
//else the father does SOME CODE itself
// SOME CODE
}
return;
}
Passing fd resulted as a success, now I'm wondering whether I should add pipe(fd) at the start of the forking program like so . . .
void forking(int p, int pid, int *fd)
{
if(pipe(fd) == -1)
{
perror("pipe: ");
return;
}
//Rest of the code
}

How processes work sequentially with C pipe?

I want to do that 2 child processes will put their names and wait until other process put his name. For instance, if there are first and second process, first will put her name and will wait for other's name in screen. So I want to work with processes and I wanna to see they are working sequentially.
Output:
first
second
first
second
first
second
I just tried something about C(linux).
int main(void)
{
pid_t child_a, child_b;
int pipe1[2], pipe2[2];
char mesazhi1[] = "first";
char mesazhi2[] = "second";
char buf[1024];
int first_pipe = pipe(pipe1);
pipe(pipe2);
if(first_pipe == -1){
perror("pipe");
exit(1);
}
child_a = fork();
if (child_a == 0)
{
/* Child A code */
int i;
for (i = 0; i < 3; i++)
{
write(pipe1[1],mesazhi1, strlen(mesazhi1) + 1);
//printf("first\n");
int a = read(pipe2[0], buf, strlen(mesazhi2) + 1);
printf("%s - %d\n", buf, a);
}
}
else
{
child_b = fork();
if (child_b == 0)
{
int i;
for (i = 0; i < 3; i++)
{
write(pipe2[1],mesazhi2, strlen(mesazhi2) + 1);
//printf("second\n");
int a = read(pipe1[0], buf, strlen(mesazhi1) + 1);
printf("%s - %d\n", buf, a);
}
}
else
{
/* Parent Code */
int returnStatusA,returnStatusB;
waitpid(child_a, &returnStatusA, 0); // Parent process waits here for child to terminate.
waitpid(child_b, &returnStatusB, 0); // Parent process waits here for child to terminate.
if (returnStatusA == 0 && returnStatusB == 0) // Verify child process terminated without error.
{
printf("%s\n", "The child processes terminated normally.\n");
}
if (returnStatusA == 1 && returnStatusB == 1)
{
printf("%s\n", "The child processes terminated with an error!. \n" );
}
}
}
}
It is putting name randomly. I mean that I think, sometimes second process works faster than first. Output like that:
first
second
second
first
second
...
So why second process doesn't wait for first one, because I think that read() function should wait until there is something in pipe1.
In the posted code, both processes write to their respective pipes, and then read. After that, it's a race to see which process gets to print first.
For a more controlled situation, have child B call read and printf before calling write. That way B has to wait for A before printing, and vice versa.
if (child_b == 0)
{
int i;
for (i = 0; i < 3; i++)
{
int a = read(pipe1[0], buf, strlen(mesazhi1) + 1);
printf("%s - %d\n", buf, a);
write(pipe2[1],mesazhi2, strlen(mesazhi2) + 1);
}
}

Why isn't my piped grep working?

I've written my own shell in C, and when I run ls | grep .c, I get nothing. Although unpiped commands are working fine, like ls. Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include "shell.h"
#include "builtins.h"
#include "makeargv.h"
void shell()
{
pid_t shell_pid;
int i;
int flag = 1;
int argc0;
int argc1;
int fdl[2];
int fdr[2];
size_t input_size;
char cwd[128]; //this is being toggled
char *delim0;
char *delim1;
char *lastarg;
char *input;
char *debugdescriptor;
char **argvp;
char **firstargs;
shell_pid = getpid();
do
{
// Retrieve PID & CWD of the parent process.
getcwd(cwd, (128 * sizeof(char)));
printf("{%i}%s$ ", shell_pid, cwd);
// Retrieve input from stdin.
input = NULL;
input_size = 0;
getline(&input, &input_size, stdin);
//seperates the input into pipe-delimited arguments("tokens")
delim1 = "|\n";
argc1 = makeargv(input, delim1, &argvp);
//got some debugging tools here
//debugdescriptor = "PIPE-SEPERATED";
//debug_args(&argvp, &argc1, debugdescriptor);
//check for quit and cd first
delim0 = " ";
argc0 = makeargv(argvp[0], delim0, &firstargs);
//more debugging tools here
//debugdescriptor = "FIRST ARGS";
//debug_args(&firstargs, &argc0, debugdescriptor);
//exit
if((i = strcmp(firstargs[0],"exit")) == 0 || (i = strcmp(firstargs[0],"quit")) == 0)
{
printf("===========SHELL TERMINATED==============\n\n");
flag = 0;
}
//cd
else if((i = strcmp(firstargs[0],"cd")) == 0)
{
chdir(firstargs[1]);
}
else // Create a child process to handle user input.
{
char **thisarg;
int childlayer = 0;
pid_t pid = fork();
wait(0);
if(pid == 0)
childlayer++;
int tokens = argc1 - 1;
if(argc1 == 1 && pid == 0)
{
makeargv(argvp[tokens], delim0, &thisarg);
execvp(thisarg[0], thisarg);
}
else //more than 1 arguement, (has pipes)
{
while(pid == 0 && childlayer < argc1){
if(childlayer == 1){ //rightmost
pipe(fdl);
pid = fork();
wait(0);
if(pid == 0)
childlayer++;
if(pid > 0){
close(fdl[1]);
dup2(fdl[0], STDIN_FILENO); //sets the final output to write to STDIN
execute(childlayer, argc1, &argvp);
}
}
else if(childlayer > 1 && childlayer < argc1-1){ //middle args
pipe(fdr);
fdr[1] = fdl[1];
fdr[0] = fdl[0];
dup2(fdr[1], STDOUT_FILENO);
pipe(fdl);
pid = fork();
wait(0);
if(pid == 0)
childlayer++;
if(pid > 0){
close(fdl[1]);
dup2(fdl[0], STDIN_FILENO);
execute(childlayer, argc1, &argvp);
}
}
else{ //leftmost
pipe(fdr);
fdr[0] = fdl[0];
fdr[1] = fdl[1];
close(fdr[0]);
dup2(fdr[1], STDOUT_FILENO);
execute(childlayer, argc1, &argvp);
}
}
}
}
}while(flag == 1);
}
I think I may be getting stuck in a child process when I use the pipes, but I haven't been able to see where. Thanks.
You are almost certainly failing to close all your file descriptors. One source of such an error is your dup2 calls.
After:
dup2(fdr[1], STDOUT_FILENO);
you should call
close(fdr[1]);
Why do you wait(0) immediately after fork()? In the child, this will return immediately with an error, but in the parent, it will block until the child exits. I'm having a hard time following how the pipeline is established because each child is forking off the next child in the pipeline. I'm guessing the wait(0) is creating a chicken-and-egg problem; the parent can't start until the child exits, but the child can't exit because it needs input from the parent. Wouldn't it be simpler if the shell process just looped over the pipeline components and forked each one itself, and then waited for them all to finish?

Problems with piping for basic shell program

I've compared this to previous posts involving piping and I can't seem to find the problem. Everything in the parent seems to be closed as it should. It works fine when I type in a valid command (ex "ls | grep a) but if it is not a valid command (ex "ls | grup a) the program stops responding to user input (it keeps running but it just doesn't do anything when you enter a command)
Main function:
int main() {
int i;
char **args;
int pipeCheck = 0;
int argCount = -1;
int blank = 0;
while(1) {
args = getln();
if (args[0] != NULL){
blank = 1;
if (strcmp(args[0],"exit")==0) exit(0);
}
for(i = 0; args[i] != NULL; i++) {
if (strcmp(args[i], "|")==0){
pipeCheck = i;
}
}
if (pipeCheck != 0){
args[pipeCheck] = NULL;
directPipe(args, pipeCheck, argCount, ampCheck);
}
}
}
This is the function for piping in my program:
int directPipe(char ** args, int fileNumber, int argCount,int ampCheck){
int fd[2];
int child1,child2;
int status;
int i;
char * piped[10000];
int count = 0;
for (i = (fileNumber+1); args[i] != NULL; i++){
piped[count] = args[i];
count++;
}
piped[count] = NULL;
printf("\nPipe attempted...\n");
pipe(fd);
child1 = fork();
if (child1==0){
close(1);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
execvp(args[0], args);
printf("Unknown command, please try again.");
exit(0);
}
child2 = fork();
if (child2 ==0){
close(0);
close(fd[1]);
dup(fd[0]);
close(fd[0]);
execvp(piped[0], piped);
printf("Unknown command, please try again.");
exit(0);
}
close(fd[1]);
close(fd[0]);
if (ampCheck == 0){
while (wait(&status) != child1);
while (wait(&status) != child2);
}
else{
printf("\nampCheck = %d",ampCheck);
sigset(child2, printer());
}
return (0);
}
Your problem is the pair of wait() loops:
while (wait(&status) != child1);
while (wait(&status) != child2);
In your scenario, the second child dies before the first does, so your collect its corpse in the first loop, but ignore it. Then the second loop goes into a busy wait because there are no children left any more.
At minimum, you need to do:
int corpse;
while ((corpse = wait(&status)) != -1 && corpse != child1 && corpse != child2)
;
while ((corpse = wait(&status)) != -1 && corpse != child1 && corpse != child2)
;
This handles children dying in either order — but only the two children. For a more general pipeline (three or more processes), you have to work harder — and use a single loop. The more general form will be something like:
int corpse;
while ((corpse = wait(&status)) != -1)
{
if (record_death_of_child(corpse, status) == -1)
break;
}
where your process creation code records the PIDs of the created processes, and the record_death_of_child() code deals with that list of PIDS and returns -1 when there are no more children to wait for in the current pipeline (and 0 otherwise). Or you can have it use some other heuristic to determine when to exit the loop. Note that if you have long running jobs in the background, any of them could die and that corpse would be collected in the loop. The 'record death' function would need to deal with such processes too — they can no longer be brought into the foreground, for example, and you need to report that they exited, etc.
You might end up using waitpid(), too, since you can arrange for that to not hang while there's a background process that's still running using WNOHANG.

Resources