1.0.2 2026-04-13 10:42 2026-04-20 10:42 submit-* (limit: 3 per practical) archi-* (limit: 2 per hour) epita-prepa-computer-science-prog-104-p-04-2030-firstname.lastname
├── AnimalProcessing
│ ├── Fundamentals
│ │ ├── exec.c
│ │ ├── exec_file.c
│ │ ├── forky.c
│ │ ├── pipe.c
│ │ └── wait.c
│ └── Proficiencies
│ ├── double_pipe.c
│ ├── dup.c
│ └── project.c
├── .gitignore
└── README
firstname.lastname with your login. .gitignore file is mandatory. Tests folder. .gitignore file:*.a
*.lib
*.o
*.obj
*.out
.idea/
*~
*.DotSettings.user
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#include <err.h>
exit function.forky.c fork(), one employee becomes two.forky() function, which will display "I am the parent!\n" in the parent and "I am the child!\n" in the child. The function will return 0 and -1 in case of error.fork function works, you can use man 3 fork or refer to the course material.int forky();
int res = forky();
printf("%d\n", res);
I am the parent!
I am the child!
0
wait.c x, and return it (if x is negative, the child must exit with -1)."My child knows how to count the Fibonacci sequence. He found <number> for <x>!\n".fork() or waitpid(), the function should return -1 otherwise, it should return 0.waitpid(2) to wait for the child process.wait() or waitpid(), it receives a raw status integer. You must use macros to decode it:WIFEXITED(status): Returns true if the child terminated normally (by calling exit() or returning from main()), rather than being killed by a signal.WEXITSTATUS(status): Extracts the actual return code (e.g., the N in exit(N)). Warning: You should only use this if WIFEXITED returned true!WIFEXITED asks "Did it exit cleanly?", and WEXITSTATUS asks "What was its exit code?".man 2 wait for more information.int wait_child(int x);
int res = wait_child(-1);
printf("%d\n", res); // -1
res = wait_child(7); // 13
printf("%d\n", res); // 0
exec.c execvp() command on her NookPhone.execvp might be very usefull...execvp(3). This function replaces the current process with a new one based on the command provided.execvp completely takes over the process, you must use fork(2) to create a child process. This prevents your main program from being terminated. execvp inside that child.-1 only if an error occurs during fork, execvp, or wait.fork(2) is that it returns a code between 0 and 255 (because the return code is stored in a single byte which limits the possible values to the range 0-255).int execute_me(char *cmd, char **argv);
char *argv[] = {"ls", "-l", NULL};
int r1 = execute_me("ls", argv);
printf("%d\n", r1);
char *argv[] = {"ls", "-l", NULL};
int r2 = execute_me("wrong", argv);
printf("%d\n", r2);
# should be the same as doing "ls -l" in the shell
0
255
exec_file.c execlp() to directly launch the file of the requested sheet music.execvp but in a different way. We let you take a look at the man page of exec(3).execlp.execlp with 2 arguments in the array args.int execute_me2(char *file, char **args);
char *argv[] = {"ls", "-l", NULL};
execute_me2("ls", argv); // should be the same as doing "ls -l" in the shell
char *argv[] = {"ls", "-l", NULL};
execute_me2("wrong", argv); // should return 255
pipe.c pipe(2) is a function that allows interprocess communication. You can have a better explanation using man pipe."Hello from your child !\n" and gives it to the parent process. Then the parent will display "My child sends me : <the message of the child>" on the stdout."an error occured\n" in the stdout and stop everything.FILE*.FILE* as interacting at the post office counter with Pelly or Phyllis: it's high-level, the text is nicely formatted, and it's easy to read.fd).fd is a simple integer that identifies a resource opened by your process (by default: 0 for stdin, 1 for stdout, 2 for stderr).FILE* but a function requires an fd (like read), you can easily ask for the cubbyhole number using the fileno(my_file) function.pipe(int fd[2]) function, the system "plumbs" a tube and gives you two ends (two File Descriptors): fd[1] is used exclusively for writing (the tube's input) and fd[0] is used exclusively for reading (the tube's output).fd[1] slot, and the other process waits at the other end at the fd[0] opening to catch the message.fd), how do you use it?write(fd, message, size).read(fd, buffer, size) is the act of reaching into the other end to grab the message and stuff it into your pockets (the buffer).close(fd).close(fd[1]), the villager at the output will wait forever with read, thinking another letter is on the way.fd is the only way to signal: "That's it, I'm done writing, you can go home!".void piped();
piped();
My child sends me : Hello from your child !
dup.c fork(2), you must open the file specified by output with fopen(3) in write mode.STDOUT_FILENO before calling execvp(3) to run the command."Something went wrong in duper.\n" and return 1."My child send me <return code>.\n" and return 0.fd)?printf or execvp, it always drops its output into cubbyhole number 1 (the public plaza, meaning stdout).dup2(oldfd, newfd) function comes in.newfd to become an exact clone of the oldfd.dup2(my_file_fd, STDOUT_FILENO), you are replacing the public cubbyhole (stdout) with your own file.stdout), its message will actually be diverted and quietly tucked away inside your file!FILE* and the int file descriptor required by dup2, you might find the fileno(3) function very useful.int duper(char **argv, char *output)
int main(int argc, char **argv)
{
duper(argv + 2, argv[1]);
}
$ ./duper test.txt echo toto
My child send me 0.
$ cat test.txt
toto
project.c \n), and tabs (\t) as delimiters.NULL-terminated array of strings.char** split(char* line);
char input[] = "run ls -l -h ";
char** res = split(input);
// res[0] = "run"
// res[1] = "ls"
// res[2] = "-l"
// res[3] = "-h"
// res[4] = NULL
exec_cmd function is responsible for launching external programs. To prevent the main program from closing when a command is executed, you must isolate the execution within a dedicated process. This follows the standard Unix process lifecycle.-1 if an error occurs during execution.int exec_cmd(char** args);
char* cmd1[] = {"ls", "-l", NULL};
int res = exec_cmd(cmd1);
// res = 0
// execute ls -l and return the exit code
"exit", it should quit the program with a return code n. If n is not specified, the default is 0"run", it should invoke exec_cmd with the subsequent tokens as arguments."?", it should print the exit status of the last executed command or 0 if no command has been run yet."Unknown command\n".int execution_loop();
int main() {
return execution_loop();
}
$ ./project
run ls -l
# (output of ls -l)
run echo Hello World
Hello World
?
0
exit 42
$ echo $?
42
> or $ ) to stdout before reading input only when a real user is interacting with the program.int is_terminal()
{
return isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
}
$ ./project
21sh$ run ls -l
# (output of ls -l)
21sh$ run echo Hello World
Hello World
21sh$ ?
0
21sh$ exit 42
$ echo $?
42
double_pipe.c n from stdin.n through Pipe A.Pipe B."The Oracle says the square is: [result]".-1, the parent closes the pipes and terminates.Pipe A.n, computes the square: .Pipe B.Pipe A is closed (EOF), the child exits cleanly.fork() must be called only once. [ Keyboard / stdin ]
|
| 1. Inputs the number 'n'
v
+-----------------------+ +-----------------------+
| | 2. Sends 'n' (write) | |
| PARENT Process | ---------------------------> | CHILD Process |
| (The Villager) | PIPE A (pipe1) | (The Oracle) |
| | | |
| - pipe1[1] : Write | | - pipe1[0] : Read |
| - pipe2[0] : Read | | - pipe2[1] : Write |
| | | |
| | | 3. Computes: n * n |
| | 4. Returns 'n²' (write) | |
| | <--------------------------- | |
+-----------------------+ PIPE B (pipe2) +-----------------------+
|
| 5. Displays "The Oracle says..."
v
[ Screen / stdout ]
$ ./oracle
5
The Oracle says the square is: 25
10
The Oracle says the square is: 100
-1
$ echo $?
0
1.0.2 ] 2026-04-14 16:15:00 forky.c > forky: remove space before ! in exemple 1.0.1 ] 2026-04-13 18:00:00 project.c > split: clarify memory management