So I am pretty new to the linux environment, and I am trying to create a shell that uses multiple pipes, and I read online that piping using shared memory space is more efficient than using regular piping. However, I have zero clue how to use shared memory space with pipes. Has anyone done this already or can someone tinker with my current code to enable shared memory space? I'd like to implement this in other projects in the future so learning it would be helpful, and if you could provide an explanation of your function uses, that would be fantastic. Here is my piping code so far:
void launchProg(char **args, int background){
int err = -1;
if((pid=fork())==-1){
printf("Child process could not be created\n");
return;
}
// pid == 0 implies the following code is related to the child process
if(pid==0){
// We set the child to ignore SIGINT signals (we want the parent
// process to handle them with signalHandler_int)
signal(SIGINT, SIG_IGN);
// We set parent=<pathname>/simple-c-shell as an environment variable
// for the child
setenv("parent",getcwd(currentDirectory, 1024),1);
// If we launch non-existing commands we end the process
if (execvp(args[0],args)==err){
printf("Command not found");
kill(getpid(),SIGTERM);
}
}
if (background == 0){
waitpid(pid,NULL,0);
}else{
printf("Process created with PID: %d\n",pid);
}
}
void fileIO(char * args[], char* inputFile, char* outputFile, int option){
int err = -1;
int fileDescriptor; // between 0 and 19, describing the output or input file
if((pid=fork())==-1){
printf("Child process could not be created\n");
return;
}
if(pid==0){
// Option 0: output redirection
if (option == 0){
// We open (create) the file truncating it at 0, for write only
fileDescriptor = open(outputFile, O_CREAT | O_TRUNC | O_WRONLY, 0600);
// We replace de standard output with the appropriate file
dup2(fileDescriptor, STDOUT_FILENO);
close(fileDescriptor);
// Option 1: input and output redirection
}else if (option == 1){
// We open file for read only (it's STDIN)
fileDescriptor = open(inputFile, O_RDONLY, 0600);
// We replace de standard input with the appropriate file
dup2(fileDescriptor, STDIN_FILENO);
close(fileDescriptor);
// Same as before for the output file
fileDescriptor = open(outputFile, O_CREAT | O_TRUNC | O_WRONLY, 0600);
dup2(fileDescriptor, STDOUT_FILENO);
close(fileDescriptor);
}
setenv("parent",getcwd(currentDirectory, 1024),1);
if (execvp(args[0],args)==err){
printf("err");
kill(getpid(),SIGTERM);
}
}
waitpid(pid,NULL,0);
}
void pipeHandler(char * args[]){
// File descriptors
int filedes[2]; // pos. 0 output, pos. 1 input of the pipe
int filedes2[2];
int num_cmds = 0;
char *command[256];
pid_t pid;
int err = -1;
int end = 0;
// Variables used for the different loops
int i = 0;
int j = 0;
int k = 0;
int l = 0;
// First we calculate the number of commands (they are separated
// by '|')
while (args[l] != NULL){
if (strcmp(args[l],"|") == 0){
num_cmds++;
}
l++;
}
num_cmds++;
while (args[j] != NULL && end != 1){
k = 0;
while (strcmp(args[j],"|") != 0){
command[k] = args[j];
j++;
if (args[j] == NULL){
end = 1;
k++;
break;
}
k++;
}
command[k] = NULL;
j++;
if (i % 2 != 0){
pipe(filedes); // for odd i
}else{
pipe(filedes2); // for even i
}
pid=fork();
if(pid==-1){
if (i != num_cmds - 1){
if (i % 2 != 0){
close(filedes[1]); // for odd i
}else{
close(filedes2[1]); // for even i
}
}
printf("Child process could not be created\n");
return;
}
if(pid==0){
if (i == 0){
dup2(filedes2[1], STDOUT_FILENO);
}
else if (i == num_cmds - 1){
if (num_cmds % 2 != 0){ // for odd number of commands
dup2(filedes[0],STDIN_FILENO);
}else{ // for even number of commands
dup2(filedes2[0],STDIN_FILENO);
}
}else{ // for odd i
if (i % 2 != 0){
dup2(filedes2[0],STDIN_FILENO);
dup2(filedes[1],STDOUT_FILENO);
}else{ // for even i
dup2(filedes[0],STDIN_FILENO);
dup2(filedes2[1],STDOUT_FILENO);
}
}
if (execvp(command[0],command)==err){
kill(getpid(),SIGTERM);
}
}
if (i == 0){
close(filedes2[1]);
}
else if (i == num_cmds - 1){
if (num_cmds % 2 != 0){
close(filedes[0]);
}else{
close(filedes2[0]);
}
}else{
if (i % 2 != 0){
close(filedes2[0]);
close(filedes[1]);
}else{
close(filedes[0]);
close(filedes2[1]);
}
}
waitpid(pid,NULL,0);
i++;
}
}
int commandHandler(char * args[]){
int i = 0;
int j = 0;
int fileDescriptor;
int standardOut;
int aux;
int background = 0;
char *args_aux[256];
while ( args[j] != NULL){
if ( (strcmp(args[j],">") == 0) || (strcmp(args[j],"<") == 0) || (strcmp(args[j],"&") == 0)){
break;
}
args_aux[j] = args[j];
j++;
}
// 'exit' command quits the shell
if(strcmp(args[0],"exit") == 0) exit(0);
// 'pwd' command prints the current directory
else if (strcmp(args[0],"pwd") == 0){
if (args[j] != NULL){
// If we want file output
if ( (strcmp(args[j],">") == 0) && (args[j+1] != NULL) ){
fileDescriptor = open(args[j+1], O_CREAT | O_TRUNC | O_WRONLY, 0600);
// We replace de standard output with the appropriate file
standardOut = dup(STDOUT_FILENO);
dup2(fileDescriptor, STDOUT_FILENO);
close(fileDescriptor);
printf("%s\n", getcwd(currentDirectory, 1024));
dup2(standardOut, STDOUT_FILENO);
}
}else{
printf("%s\n", getcwd(currentDirectory, 1024));
}
}
// 'clear' command clears the screen
else if (strcmp(args[0],"clear") == 0) system("clear");
// 'cd' command to change directory
else if (strcmp(args[0],"cd") == 0) changeDirectory(args);
// 'environ' command to list the environment variables
else if (strcmp(args[0],"environ") == 0){
if (args[j] != NULL){
// If we want file output
if ( (strcmp(args[j],">") == 0) && (args[j+1] != NULL) ){
fileDescriptor = open(args[j+1], O_CREAT | O_TRUNC | O_WRONLY, 0600);
// We replace de standard output with the appropriate file
standardOut = dup(STDOUT_FILENO);
dup2(fileDescriptor, STDOUT_FILENO);
close(fileDescriptor);
manageEnviron(args,0);
dup2(standardOut, STDOUT_FILENO);
}
}else{
manageEnviron(args,0);
}
}
// 'setenv' command to set environment variables
else if (strcmp(args[0],"setenv") == 0) manageEnviron(args,1);
// 'unsetenv' command to undefine environment variables
else if (strcmp(args[0],"unsetenv") == 0) manageEnviron(args,2);
else{
while (args != NULL && background == 0){
if (strcmp(args,"&") == 0){
background = 1;
}else if (strcmp(args,"|") == 0){
pipeHandler(args);
return 1;
}else if (strcmp(args,"<") == 0){
aux = i+1;
if (args[aux] == NULL || args[aux+1] == NULL || args[aux+2] == NULL ){
printf("Not enough input arguments\n");
return -1;
}else{
if (strcmp(args[aux+1],">") != 0){
printf("Usage: Expected '>' and found %s\n",args[aux+1]);
return -2;
}
}
fileIO(args_aux,args[i+1],args[i+3],1);
return 1;
}
else if (strcmp(args,">") == 0){
if (args[i+1] == NULL){
printf("Not enough input arguments\n");
return -1;
}
fileIO(args_aux,NULL,args[i+1],0);
return 1;
}
i++;
}
launchProg(args_aux,background);
}
return 1;
}