MediumPipex 42. Pipex, the magical 42 project where we… | by abkabex | Medium
Sitemap

Pipex 42

5 min readJan 15, 2024

--

How Our Program supposed to work.

Pipex, the magical 42 project where we teach pipes in the shell — because even computers need plumbing lessons! 🚽💻 Get ready to connect commands like a pro and make your shell pipelines flow smoother than a water slide at a summer party! 😄🌊.

Before We Dive Into This Project, Let’s Begin By Familiarizing Ourselves With The Functions That Will Be Of Assistance.

Press enter or click to view image in full size
This Is The Allowed Functions.

These functions — ‘read,’ ‘write,’ ‘open,’ ‘close’, ‘malloc’ and ‘free’ — are widely recognized, even by those not in the developer circle, so there’s no need for extensive explanations.

What About The Access();

#include <unistd.h>
int access(const char *pathname, int mode);
// return: 0 if OK, −1 on error
All Modes Of access();

The ‘access’ function is a powerful tool in programming that checks whether a specified user can perform specific actions on a file. It evaluates permissions for read, write, and execute operations, providing essential security and control in file handling.

Dup2();

An existing file descriptor is duplicated by either of the following functions:

#include <unistd.h>
int dup2(int fd, int fd2);
// return: new file descriptor if OK, −1 on error

‘Dup2’ is like making a photocopy of a key to a locked room; you now have two keys that can open the same door, making it handy for managing access to a resource.

Exemple :

#include <unistd.h>
#include <fcntl.h>

int main() {
int fd = open("output.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

// Check if the file opened successfully
if (fd == -1) {
exit(1);

// Redirect stdout (file descriptor 1) to the file
if (dup2(fd, 1) == -1)
{j
perror("dup2");
return 1;
}

// Now, anything written to stdout will be written to "output.txt"
printf("This will be written to 'output.txt'\n");

// Close the file descriptor when done
close(fd);

return 0;
}

Execve();

execve is like a portal that lets your program transform into another one. It replaces your code with the specified program, transferring control and execution to it, effectively running a different software within your own.

#include <unistd.h>
int execve(const char *pathname, char *const argv[], char *const envp[]);
// return: −1 on error, no return on succes

Get abkabex’s stories in your inbox

Join Medium for free to get updates from this writer.

Exemple :

#include <stdio.h>
#include <unistd.h>

int main() {
char *args[] = {"/bin/ls", "-l", NULL};
char *env[] = {NULL}; // Environment variables (usually NULL)

if (execve("/bin/ls", args, env) == -1) {
perror("execve");
return 1;
}

// This code will only be executed if execve fails.
printf("This line won't be reached because execve replaces the current process.\n");

return 0;
}

Fork();

The fork function is like creating a clone of your program; it spawns a new identical process, like a twin, allowing both the original and the new process to run concurrently and independently, each with its own set of resources and memory space.

#include <unistd.h>
pid_t fork(void);
// Returns: 0 in child, process ID of child in parent, −1 on error

Exemple :

#include <stdio.h>
#include <unistd.h>

int main() {
pid_t child_pid; // Process ID variable

child_pid = fork(); // Create a new process (child)

if (child_pid == -1) {
perror("fork");
return 1;
}

if (child_pid == 0) {
// This code runs in the child process
printf("Hello from the child process!\n");
} else {
// This code runs in the parent process
printf("Hello from the parent process! Child's PID: %d\n", child_pid);
}

return 0;
}

pipe();

The pipe function is like a communication channel between two processes, resembling a physical pipe. It allows one process to send data to another, creating a connection for seamless information exchange, much like talking through a secret conduit.

#include <unistd.h>
int pipe(int fd[2]);
// Returns: 0 if OK, −1 on error

Exemple :

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main() {
int pipe_fd[2]; // File descriptors for the pipe

// Create a pipe
if (pipe(pipe_fd) == -1) {
perror("pipe");
return 1;
}

pid_t child_pid = fork(); // Create a child process

if (child_pid == -1) {
perror("fork");
return 1;
}

if (child_pid == 0) {
// This code runs in the child process
close(pipe_fd[1]); // Close the write end of the pipe in the child

char buffer[100];
ssize_t bytes_read = read(pipe_fd[0], buffer, sizeof(buffer));
if (bytes_read > 0) {
printf("Child received: %.*s\n", (int)bytes_read, buffer);
}

close(pipe_fd[0]); // Close the read end of the pipe in the child
} else {
// This code runs in the parent process
close(pipe_fd[0]); // Close the read end of the pipe in the parent

char message[] = "Hello, Child!";
ssize_t bytes_written = write(pipe_fd[1], message, strlen(message));
if (bytes_written > 0) {
printf("Parent sent a message to the child.\n");
}

close(pipe_fd[1]); // Close the write end of the pipe in the parent
}

return 0;
}

wait();

The wait function is like a guardian at the exit of a funhouse, ensuring that the parent process patiently waits for its child process to complete its performance. It allows for orderly synchronization, making sure the parent doesn't rush ahead until the child is done with its act, ensuring a smooth circus of program execution.

#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);

//Both return: process ID if OK, 0 (see later), or −1 on error

Exemple :

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
pid_t child_pid;
int status;

child_pid = fork(); // Create a child process

if (child_pid == -1) {
perror("fork");
return 1;
}

if (child_pid == 0) {
// This code runs in the child process
printf("Child process executing...\n");
sleep(3); // Simulate some work in the child process
exit(42); // Exit with a status code
} else {
// This code runs in the parent process
printf("Parent waiting for the child...\n");
wait(&status); // Wait for the child process to complete

printf("Child process has finished.\n");

if (WIFEXITED(status)) {
printf("Child exited with status: %d\n", WEXITSTATUS(status));
}
}

return 0;
}

With the explanations complete, let’s move on to how I implemented my program.

--

--