Linux Shell Pipeline Execution - c

I am trying to implement a basic linux shell with support for pipelining. However, my code seems to hang or just not execute programs and I can't figure out why.
if (list_empty(&job_list))
job_index = 1;
bool dopipe = false;
if (list_size(&pipeline->commands) > 1)
dopipe = true;
esh_signal_sethandler(SIGCHLD, signal_handler);
esh_signal_block(SIGCHLD);
setpgid(0, 0);
pipeline->pgrp = getpgid(0);
pipeline->jid = job_index++;
list_push_back(&job_list, &pipeline->elem);
bool background = pipeline->bg_job;
pid_t pid;
if ( (pid = fork()) == 0)
{
//Child
if (pipeline->bg_job)
setpgid(0, 0);
int oldpipe[2];
int newpipe[2];
int count = 0;
int size = list_size(&pipeline->commands);
struct list_elem * current_job;
printf("SIZE: %zu\n", list_size(&pipeline->commands));
for (current_job = list_begin(&pipeline->commands); current_job != list_tail(&pipeline->commands); current_job = list_next(current_job))
{
if (count < size)
pipe(newpipe);
pid_t fpid = fork();
printf("fpid: %d\n", (int)fpid);
if (fpid == 0)
{
//Child
printf("Executing Child\n");
if (count > 0)
{
//prev command exists
dup2(oldpipe[0], 0);
close(oldpipe[0]);
close(oldpipe[1]);
}
if (count < size - 1)
{
//next command exists
close(newpipe[0]);
dup2(newpipe[1], 1);
close(newpipe[1]);
}
esh_command* cmd = list_entry(current_job, struct esh_command, elem);
printf("Running: %s %s\n", cmd->argv[0], cmd->argv[1]);
if (execvp(cmd->argv[0], cmd->argv) < 0)
esh_sys_fatal_error("Program Does Not Exist\n");
}
else
{
//Parent
//*
int status = 0;
if (waitpid(fpid, &status, 0) < 0)
esh_sys_fatal_error("Could not fork pipe\n");
//*/
printf("Parent\n");
if (count > 0)
{
//prev command exists
close(oldpipe[0]);
close(oldpipe[1]);
}
if (count < size - 1)
{
//next command exists
oldpipe[0] = newpipe[0];
oldpipe[1] = newpipe[1];
}
printf("End of Parent\n");
}
count++;
}
if (size > 1)
{
close(oldpipe[0]);
close(oldpipe[1]);
}
printf("Finished Pipeline\n");
exit(3);
}
else
{
//*
int status = 0;
commands->pid = pid;
//Parent
if (!background)
{
pipeline->status = FOREGROUND;
if (waitpid(pid, &status, 0) < 0)
printf("waitpid ERROR\n");
list_remove(&pipeline->elem);
}
else
pipeline->status = BACKGROUND;
//*/
}
esh_signal_unblock(SIGCHLD);
I am fairly certain the error has to do with either the piping, or the forking of child processes in the loop.

Related

Changing directories in a shell. Writing my own shell in C

I am writing a simple shell in C. Right now when I run the command cd only work in the current environment that I am. So for example if I am in the Desktop folder I can only cd for a folder inside Desktop, I can't go to other folders in my computer.
How do I control this change of directories?
Thant's my cd function right now. Please let me know if you need more information.
int cmd_cd(char **args)
{
if (args[1] == NULL) {
fprintf(stderr, "expected argument to \"cd\"\n");
} else {
if (chdir(args[1]) != 0) {
fprintf(stderr, args[1],strerror(errno));;
}
}
return 1;
}
Here is my exec function that calls cd
char* builtCommandList[] = {"cd", "exit"};
int builtinSize = sizeof(builtCommandList) / sizeof(char *);
int (*builtin_func[]) (char **) = {
&cmd_cd,
&cmd_exit
};
int execute(char **args){
if(args[0] == NULL)
return 1;
for(int i =0; i<builtinSize;i++){
if (strcmp(args[0], builtCommandList[i]) == 0) {
printf("function is here");
return (*builtin_func[i])(args);
}
}
pid_t pid, wpid;
int status;
pid = fork();
if (pid == 0) {
// Child process
if (execvp(args[0], args) == -1) {
fprintf(stderr, "error in child process");
}
exit(EXIT_FAILURE);
} else if (pid < 0) {
// Error forking
fprintf(stderr, "error forking");
} else {
// Parent process
do {
wpid = waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
return 1;
}

Removing empty strings in an array of strings and other strange data in C

I'm creating a shell in C and have implemented piping. This involves dividing the argument on the left side and right side of the pipe into two separate array of strings to be executed separately with execvp. For some reason, the array of strings pcmd2 contains data other than the argument I entered in the shell.
For example, I enter ls | sort into the shell after running the program and it outputs the following: sort: open failed: : No such file or directory
Seeing this, I suspected that the array of strings pcmd2 containing the sort command may have empty strings and other things that are being processed.
I print out pcmd2 with a for-loop (with a new line after each string) and I find the following printed onto the screen:
sort
UJ
There clearly seems to be extra stuff in there. Seems like empty strings but I have no clue where the UJ is coming from (this gets consistenly printed out).
I've tried setting the index in pcmd2 that's right after where sort is stored in the array to NULL. Like so, pcmd2[1] = NULL and that seemed to "fix" it since the weird extra data would no longer be processed by the execvp function. However, that means that I can't pipe commands with multiple arguments like grep myshell as it would only be able to take in the grep part.
I will show the full code below because I'm unsure how much context is needed in this case.
I know there's some very broken piping implementation here (I've tried some weird solution to get it work with two pipes) but I'm working to just get one pipe to work. I'm not asking for help piping in particular.
The most relevant part, I believe, is in the splitPipeCommands function.
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#define MAX_ARGS 20
#define MAX_PIPE_ARGS 3
#define BUFSIZE 1024
int input, output, append, usePipe;
char *inputFile;
char *outputFile;
FILE *fp1;
FILE *fp2;
int get_args(char* cmdline, char* args[])
{
int i = 0;
/* if no args */
if((args[0] = strtok(cmdline, "\n\t ")) == NULL)
return 0;
while((args[++i] = strtok(NULL, "\n\t ")) != NULL) {
if(i >= MAX_ARGS) {
printf("Too many arguments!\n");
exit(1);
}
}
/* the last one is always NULL */
return i;
}
void checkIORedirect(char* args[])
{
input = 0;
output = 0;
append = 0;
int i;
for(i = 0; args[i] != NULL; i++)
{
if(!strcmp(args[i], ">"))
{
output = 1;
outputFile = args[i+1];
args[i] = NULL;
}
else if(!strcmp(args[i], "<"))
{
input = 1;
inputFile = args[i+1];
args[i] = NULL;
//printf("inputFile: %s\n", inputFile);
}
else if(!strcmp(args[i], ">>"))
{
append = 1;
outputFile = args[i+1];
args[i] = NULL;
}
}
}
int getPipeIndexes(char* args[], int* pIndex1, int* pIndex2)
{
*pIndex1 = -1;
*pIndex2 = -1;
int i = 0;
int pcount = 0;
usePipe = 0;
for(i = 0; args[i] != NULL; i++)
{
if(!strcmp(args[i], "|") && pcount == 0)
{
//printf("First pipe!\n");
*pIndex1 = i;
args[i] = NULL;
pcount++;
usePipe = 1;
}
else if(!strcmp(args[i], "|") && pcount == 1)
{
//printf("Second pipe!\n");
*pIndex2 = i;
args[i] = NULL;
pcount++;
}
else if(!strcmp(args[i], "|") && pcount > 1)
{
printf("Too many pipes, only accepting first two!\n");
args[i] = NULL;
}
}
return pcount;
}
void splitPipeCommands(char* args[], int* pIndex1, int* pIndex2, int pcount, char* pcmd1[], char* pcmd2[], char* pcmd3[])
{
if(pcount == 1)
{
int i;
int cmdIndex = 0;
for(i = 0; i < *pIndex1; i++)
{
pcmd1[cmdIndex] = args[i];
cmdIndex++;
}
cmdIndex = 0;
//printf("2nd half of args: \n");
for(i = *pIndex1 + 1; args[i] != NULL; i++)
{
pcmd2[cmdIndex] = args[i];
//printf("%s\n", args[i]);
cmdIndex++;
}
//pcmd2[1] = NULL;
//*pcmd1 = args[0];
//*pcmd2 = args[*pIndex1 + 1];
/*TODO: del when you finish debugging*/
//printf("pcmd1=%s,%s,%s\n", pcmd1[0], pcmd1[1], pcmd1[2]);
//printf("pcmd2=%s\n", pcmd2[0]);
}
else if(pcount == 2)
{
int i;
int cmdIndex = 0;
for(i = 0; i < *pIndex1; i++)
{
pcmd1[cmdIndex] = args[i];
cmdIndex++;
}
cmdIndex = 0;
for(i = *pIndex1 + 1; i < *pIndex2; i++)
{
pcmd2[cmdIndex] = args[i];
cmdIndex++;
}
//pcmd2[1] = NULL;
cmdIndex = 0;
for(i = *pIndex2 + 1; args[i] != NULL; i++)
{
pcmd3[cmdIndex] = args[i];
cmdIndex++;
}
/*
*pcmd1 = args[0];
*pcmd2 = args[*pIndex1 + 1];
*pcmd3 = args[*pIndex2 + 1];
*/
/*TODO: del when you finish debugging*/
//printf("pcmd1=%s,", *pcmd1);
//printf("pcdm2=%s,", *pcmd2);
//printf("pcmd3=%s\n", *pcmd3);
}
}
void closeFiles()
{
if(fp1 != NULL)
{
fclose(fp1);
}
if(fp2 != NULL)
{
fclose(fp2);
}
}
void execute(char* cmdline)
{
int pid, pid2, async;
char* args[MAX_ARGS];
int nargs = get_args(cmdline, args);
if(nargs <= 0) return;
if(!strcmp(args[0], "quit") || !strcmp(args[0], "exit")) {
exit(0);
}
/* check if async call */
if(!strcmp(args[nargs-1], "&")) { async = 1; args[--nargs] = 0; }
else async = 0;
/*Pipe related*/
int pIndex1, pIndex2;
char* pcmd1[30];
char* pcmd2[30];
char* pcmd3[30];
int pcount = getPipeIndexes(args, &pIndex1, &pIndex2);
if(usePipe)
{
splitPipeCommands(args, &pIndex1, &pIndex2, pcount, pcmd1, pcmd2, pcmd3);
if(pcount == 1)
{
checkIORedirect(pcmd1);
checkIORedirect(pcmd2);
}
else if(pcount == 2)
{
checkIORedirect(pcmd1);
checkIORedirect(pcmd2);
checkIORedirect(pcmd3);
}
}
else
{
checkIORedirect(args);
}
/*TODO: del when finished debugging*/
//printf("pIndex1=%d,pIndex2=%d,pcount=%d\n", pIndex1, pIndex2, pcount);
//checkIORedirect(args);
if(output)
{
if((fp1 = fopen(outputFile, "w")) == NULL)
{
printf("Output to file failed!\n");
}
}
else if(append)
{
if((fp1 = fopen(outputFile, "a")) == NULL)
{
printf("Append to file failed!\n");
}
}
if(input)
{
if((fp2 = fopen(inputFile, "r")) == NULL)
{
printf("Input from file failed!\n");
}
}
int fd[2];
int fd2[2];
if(usePipe)
{
if(pipe(fd) == -1)
{
perror("pipe failed");
exit(1);
}
}
pid = fork();
if(pid == 0) { /* child process */
if(input)
{
//printf("Input\n");
dup2(fileno(fp2), STDIN_FILENO);
fclose(fp2);
input = 0;
}
if(output || append)
{
dup2(fileno(fp1), STDOUT_FILENO);
fclose(fp1);
output = 0;
append = 0;
//printf("Output or append\n");
}
if(usePipe)
{
//TODO: Make case for one pipe and two pipes
if(pcount == 2)
{
if(pipe(fd2) == -1)
{
perror("pipe failed");
exit(1);
}
pid2 = fork();
if(pid2 == -1)
{
perror("fork 2 failed");
exit(1);
}
if(pid2 == 0) //Child 2
{
close(fd[1]);
close(fd[0]);
close(fd2[1]);
dup2(fd2[0], 0);
close(fd2[0]);
execvp(pcmd2[0], pcmd2);
perror("exec second child failed");
exit(-1);
}
else //Child 1
{
close(fd[1]);
dup2(fd[0], 0);
close(fd[0]);
close(fd2[0]);
dup2(fd2[1], 1);
close(fd2[1]);
execvp(pcmd3[0], pcmd3);
perror("exec first child failed");
exit(-1);
}
}
else if(pcount == 1)
{
//TODO: pipe for one pipe
//close(fd[1]);
//dup2(fd[0], 0);
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
printf("pcmd1=%s\n", pcmd1[0]);
execvp(pcmd1[0], pcmd1);
perror("exec child failed");
exit(-1);
}
}
else
{
execvp(args[0], args);
/* return only when exec fails */
perror("exec failed");
exit(-1);
}
/*
execvp(args[0], args);
// return only when exec fails
perror("exec failed");
exit(-1);
*/
} else if(pid > 0) { /* parent process */
if(usePipe)
{
pid=fork();
if(pid==0)
{
dup2(fd[0], STDIN_FILENO);
close(fd[1]);
close(fd[0]);
printf("pcmd2 contents: \n");
int j;
for(j = 0; pcmd2[j] != NULL; j++)
{
printf("%s\n", pcmd2[j]);
}
//FIXME: Something's wrong with pcmd2
execvp(pcmd2[0], pcmd2);
//execlp("sort", "sort", (char*)NULL);
perror("exec second command failed");
}
else
{
int status;
close(fd[0]);
close(fd[1]);
waitpid(pid, &status, 0);
}
//wait(NULL);
/*
close(fd[0]);
dup2(fd[1], 1);
printf("pcmd1=%s\n", pcmd1[0]);
execvp(pcmd1[0], pcmd1);
perror("exec parent failed");
*/
}
if(!async)
{
waitpid(pid, NULL, 0);
}
else
{
printf("this is an async call\n");
}
} else { /* error occurred */
perror("fork failed");
exit(1);
}
}
int main (int argc, char* argv [])
{
char cmdline[BUFSIZE];
for(;;) {
printf("COP4338$ ");
if(fgets(cmdline, BUFSIZE, stdin) == NULL) {
perror("fgets failed");
exit(1);
}
execute(cmdline);
usePipe = 0;
//closeFiles();
fflush(stdout);
}
return 0;
}

Creating shared memory in C

I created following method in C to create a shared memory segment to store counter value. But I can't store data in this segment.When I try to print the value of the counter it gives me a garbage value.Whats wrong with this code?
CreateCounter()
{
key = ftok(".",'B');
shmCntid = shmget(key,COUNTER_SIZE,IPC_CREAT|0666);
if(shmCntid == -1 )
{
perror("shmget");
exit(1);
}
else
{
printf("Creating new Sahred memory sement\n");
cntPtr = shmat(shmCntid,0,0);
if(cntPtr == -1 )
{
perror("shmat");
exit(1);
}
}
}
This method is called inside the main method as follows.
int *cntPtr;
int rowCnt;
sem_t s;
sem_t c;
sem_t r;
int main(int argc, int *argv[])
{
int pid, pid2, pid3, i;
CreateBuf1();
CreateBuf2();
CreateCounter();
GetInput(argv[1],*buf1Ptr);
sem_init(&c, 0, 1);
sem_init(&r, 0, 1);
sem_init(&s, 0, 1);
for( i = 0 ; i < 9; i++)
{
pid = fork();
if(pid < 0)
{
printf("Fork error !\n");
}
else if (pid == 0)
break;
}
if(pid < 0)
{
printf("Fork error !\n");
}
else if (pid == 0)
{
sem_wait(&r);
Grp1 (i,i);
cntPtr+=rowCnt;
sleep(1);
sem_post(&r);
sem_post(&c);
exit(0);
}
else
{
wait(NULL);
}
pid2 = fork();
if(pid2 < 0)
{
printf("Fork error !\n");
}
else if (pid2 == 0)
{
sem_wait(&c);
Grp2(9);
cntPtr+=colCnt;
sleep(1);
sem_post(&c);
exit(0);
}
else
{
wait(NULL);
}
// This space is to print the values..............
shmctl(shmBuf1id,IPC_RMID,0);
shmctl(shmBuf2id,IPC_RMID,0);
shmctl(shmCntid,IPC_RMID,0);
return 0;
}

Multiple Pipe Recursive Handing in c

I want to handle multiple pipes in c via a recursive function. I could not figure it what is wrong. Whether I did not hook up the pipes properly or I left some process hanging. Please give some advice.
Assume: token[0] = "ls"; token[1] = "|"; token[2] = "sort"; token[3] = "|"; token[4] = "more";
int pipeExecution(char *token[]) {
int isPipe = 0;
int fds[2] = {0};
pid_t pid;
for (int i = 0; token[i] != NULL; i++) {
if (strcmp(token[i], "|") == 0) {
isPipe = 1;
token[i] = NULL;
if (pipe(fds) < 0) {
perror("Can not pipe\n");
exit(EXIT_FAILURE);
}
pid = fork();
if (pid < 0) {
perror("Can not fork() **1\n");
exit(EXIT_FAILURE);
} else {
if (pid > 0) {
pid = fork();
if (pid < 0) {
perror("Can not fork() **2\n");
exit(EXIT_FAILURE);
} else {
if (pid > 0) { // parent
wait(NULL);
} else { // child 2 - excuse the command after a "|"
close(fds[1]); // does not write to pipe
if (dup2(fds[0], STDIN_FILENO) < 0) {
perror("Can not dup2()\n");
exit(EXIT_FAILURE);
}
printf("execute tokens after |\n");
pipeExecution(token + (i + 1));
}
}
} else { // child 1 - excuse the command before a "|"
printf("execute tokens before |\n");
close(fds[0]); // does not read from pipe
if (dup2(fds[1], STDOUT_FILENO) < 0) {
perror("Can not dup2()\n");
exit(EXIT_FAILURE);
}
execvp(token[0], token);
}
}
break;
}
}
if (isPipe == 0) {
perror(token[0]);
pid = fork();
if (pid < 0) {
perror("Can not fork()\n");
exit(EXIT_FAILURE);
}
if (pid > 0) {
wait(NULL);
} else {
execvp(token[0], token);
}
}
return 0;
}

Redirection/Piping in C Bugs

Ok, in this code I have 2 primary problems.
1: The parent doesn't wait for the child to print before returning to main and printing. I included a waitpid() but it doesn't seem to be working how I expected.
When I redirect, I create the file fine, but nano and vim don't "see" the file, Gedit however can (so I know my output is being sent correctly)
The flow of this function:
A string is input, the string is checked for a trailing & (if it exists, it is removed and the background flag is updated).
Then the string is tokenized on '|'
Each token is tokenized on '<' and '>'
Then each string from that is tokenized on ' '
The resulting char ** is executed with the output/input being redirected based off the results of the above tokenizations.
void execute_command(char * s)
{
printf("\n");
int fd[3][2]; // since we are guaranteed each type of redirection will be used only once, I only need 3 pipes: < > and |
//int fd[2];
int res;
pid_t pid;
int status;
int stdin_c = dup(0);
int stdout_c = dup(1);
int i;
int background = 0;
for(i = 0; s[i] != '\0'; i++);
if(s[i-1] == '&')
{
background = 1;
s[i-1] = '\0';
}
char ** piped = token_pipe(s);
char ** left_a;
char ** right_a;
int output = 0;
int input = 0;
for(i = 0; piped[i] != NULL; i++)
{
left_a = token_leftarrow(piped[i]);
right_a = token_rightarrow(piped[i]);
if(left_a[1] != NULL)
{
free(piped[i]);
piped[i] = calloc(strlen(left_a[0]) + 1, sizeof(char));
strcpy(piped[i], left_a[0]);
fd[0][0] = open(left_a[1], O_RDONLY);
input = i;
}
if(right_a[1] != NULL)
{
free(piped[i]);
piped[i] = calloc(strlen(left_a[0]) + 1, sizeof(char));
strcpy(piped[i], right_a[0]);
fd[1][1] = open(right_a[1], O_WRONLY | O_CREAT, 0666);
output = i;
}
}
char ** spaced = token_space(piped[0]);
char ** spaced2 = NULL;
if(piped[1] != NULL)
{
spaced2 = token_space(piped[1]);
res = pipe(fd[2]);
if(res < 0)
{
printf("Pipe Failure\n");
exit(-1);
}// end if
}
if(fork() == 0)
{
if(background == 1)
setpgid(0, 0);
if(piped[1] != NULL)
{
close(fd[2][1]);
close(0);
dup(fd[2][0]);
if(output == 1 && right_a[1] != NULL)
{
dup2(fd[1][1], 1);
close(fd[1][1]);
}
execvp(spaced2[0], spaced2);
perror("Invalid Command");
exit(-1);
}
else
{
if(input == 0 || output == 0)
{
if(right_a[1] != NULL)
{
dup2(fd[1][1], 1);
close(fd[1][1]);
}
if(left_a[1] != NULL)
{
dup2(fd[0][0], 0);
close(fd[0][0]);
}
}
execvp(spaced[0], spaced);
perror("Invalid command\n");
exit(-1);
}
}
else
{
if(piped[1] != NULL)
{
if((pid = fork()) == 0)
{
close(fd[2][0]);
close(1);
dup(fd[2][1]);
if(input == 0 && left_a[1] != NULL)
{
dup2(fd[0][0], 0);
close(fd[0][0]);
}
execvp(spaced[0], spaced);
perror("Invalid Command");
exit(-1);
}
else
if(background == 0)
waitpid(pid, &status, WNOHANG);
}
else
if(background == 0)
wait(NULL);
close(fd[2][0]);
close(fd[2][1]);
close(fd[0][0]);
close(fd[1][1]);
dup2(stdin_c, 0);
dup2(stdout_c, 1);
}
}

Resources