-1

I'm writing a code that mimics a shell behavior, specifically & and |.

My function receives user commands, and checks if there's an & at the end, then the child process should run in the background and the parent should not wait for it to finish and continue executing commands.

Also it's supposed to check if there's a | in the input array and run two child processes while piping their stdin and stdout.

I have implemented the behavior for &, but whenever I compile and run my code, I only get the printf sentence from the parent's process.

I would like to hear ideas how to fix this, in addition I would appreciate any suggestions regarding the implementation of | (pipes) and how to prevent zombies.

int process_arglist(int count, char** arglist) {
int pid = fork();
printf("%d", pid);
switch (pid) {
case -1:
    fprintf(stderr, "ERROR: fork failed\n");
    return 1;
    break;

case 0: // Son's proccess
    printf("I got to son");
    //check last arglist argument
    if (strcmp(arglist[count - 1], "&") == 0) {
        setpgid(0, 0);
        arglist[count - 1] = NULL;
        if (execvp(*arglist, arglist) < 0) {     //execute the command
            fprintf(stderr, "ERROR: execvp failed\n");
            exit(1);
        }
    } else { //There's no & at the end, look for pipes
        int i = 0;
        while (i < count) {
            if (strcmp(arglist[i], "|") == 0) {
                int pid2 = fork();
                if (pid2 < 0) {
                    //fork failed, handle error
                }
                if (pid2 == 0) { // Son's proccess

                } else { //Parent's code

                }
            }
        }
    }
    break;
    //in case no & and no |, call execvp

default: //Parent's code
    printf("I go to parent");
    return 1;
    break;
}
return 0;

}

The output is always "I go to parent"

alk
  • 69,737
  • 10
  • 105
  • 255
Tam211
  • 723
  • 5
  • 10
  • 27
  • 3
    Print debug output to `stderr`, as it's not buffered. Else put a `\n` at the end of every statement to print, or flush the stream by calling `fflush(stdout);`. – alk Dec 02 '17 at 08:24
  • Do not ask two questions in one post. Make the second a separate one. – Yunnosch Dec 02 '17 at 08:29
  • @Yunnosch The ouput is "I go to parent" – Tam211 Dec 02 '17 at 08:33
  • Unlikely. That does not include the number I expect from `printf("%d", pid);`. – Yunnosch Dec 02 '17 at 08:34
  • Maybe output gets more helpful with a few `\n`. (i.e. I agree with alk) – Yunnosch Dec 02 '17 at 08:36
  • "*how to prevent zombies.*" [`wait()`](http://man7.org/linux/man-pages/man2/waitpid.2.html) for the children to end. – alk Dec 02 '17 at 08:42
  • 1
    Closely related to [`printf()` anomaly after `fork()`](https://stackoverflow.com/questions/2530663/printf-anomaly-after-fork/). – Jonathan Leffler Dec 02 '17 at 08:48
  • @Yunnosch I have made the suggested changes, now it goes to both parent and son, but ls& is not working – Tam211 Dec 02 '17 at 08:49
  • 2
    Note that in English, it is conventional to use the gender-neutral term 'child' rather than 'son' for processes; and grandchild, parent, grandparent and sibling. – Jonathan Leffler Dec 02 '17 at 08:50
  • 2
    Now that the false impression is clarified that the code never ends up in child, please split the next part of your multi-question into a new separate question. Asking about the other problems under your current title is not helpful. (Do not edit this question to ask for something else than initially.) – Yunnosch Dec 02 '17 at 08:52
  • SO is not a *do-my-homework* service. – Basile Starynkevitch Dec 02 '17 at 08:52
  • @JonathanLeffler: you are right about "child" vs "son" process in English. However, in some languages (notably French) it is customary to speak of "masculine" process (in French, you'll find "processus fils" but never "processus enfant", where "fils" is son, and "enfant" is child). Perhaps OP is natively French! – Basile Starynkevitch Dec 02 '17 at 08:56
  • 2
    Do not change the code after comments/answers have been given, as this renders them to be ununderstandable. Add updates. I rolled back you last change though. – alk Dec 02 '17 at 09:05

1 Answers1

1

I assume your code is for Linux or some other POSIX system. Read some good book on Linux programming (perhaps the old Advanced Linux Programming, freely downloadable, or something newer).

stdio(3) is buffered, and stdout and printf is often (but not always) line-buffered. Buffering happens for efficiency reasons (calling write(2) very often, e.g. once per output byte, is very slow; you should prefer doing write-s on chunks of several kilobytes).

BTW you'll better handle failure of system calls (see intro(2) and syscalls(2)) by using errno(3) thru perror(3) (or strerror(3) on errno). You (and the user of your shell) needs to be informed of the failure reason (and your current code don't show it).

I recommend to often end your printf format control strings with \n (this works when stdout is line-buffered) or to call fflush(3) at appropriate places.

As a rule of thumb, I suggest doing fflush(NULL); before every call to fork(2).

The behavior you observe is consistent with the hypothesis that some printf-ed data is staying in buffers (e.g. of stdout).

You could use strace(1) on your program (or on other ones, e.g. some existing shell process) to understand what system calls are done.

You should compile with all warnings and debug info (e.g. gcc -Wall -Wextra -g with GCC), improve your code to get no warnings, and use the debugger gdb (with care, it can be used on forking processes).

I'm writing a code that mimics a shell behavior

You probably are coding some shell. Then study for inspiration the source code of existing free software shells (most -probably all- Linux shells are free software).

I would appreciate any suggestions regarding the implementation of | (pipes) and how to prevent zombies.

Explaining all that requires a lot of space (several chapters of a book, or perhaps, an entire book) and don't fit here or on any other forum. So read a good Linux or POSIX programming book. Regarding pipes, read pipe(7) (it should be created with pipe(2) before the fork). Regarding avoiding zombie processes, you need to carefully call waitpid(2) or some similar call.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547