smmalmansoori
August 22nd, 2010, 11:24 PM
I was recently introduced to programming in C using multiple processes.
These are the conditions of the program I am making:
If "exit" is entered quit the program
Process arbitrary commands as shell commands by using execl()
Implement your own "cd" (change directory) command
If commands are passed normally make a fork() and let the parent wait for it using wait()
If commands are appended by "&" (i.e. "ls &")don't let the parent wait, and avoid zombie processes by using "signal(SIGCHLD, SIG_IGN)"
I'm halfway through implementing my "cd" command so I did some testing and found out when running the program everything works except when using the "cd" command without appending "&" (i.e. "cd /tmp") it would output fine but then the program won't quit if I type "exit" after that.
Any advice or explanation is greatly appreciated. here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
char *getLine(FILE *in);
int my_system(char *line);
void my_cd(char *line);
int main(int argv, char *args[])
{
char *exitLine = "exit\n";
int status = EXIT_SUCCESS;
for(;;)
{
char *line = getLine(stdin);
if(strcmp(line, exitLine) == 0)
{
break;
}
status = my_system(line);
}
return status;
}
char *getLine(FILE *in)
{
int c = 0;
unsigned long i = 0;
size_t line_size = 80;
char *line = malloc(line_size);
if(ferror(in) == 0)
{
while(line != NULL && c != EOF)
{
while(i < line_size - 1)
{
if((c = getc(in)) == EOF)
{
break;
}
line[i++] = c;
if(c == '\n' || c == '\0')
{
c = EOF;
break;
}
}
if(i >= line_size - i)
{
line_size *= 2;
line = realloc(line, line_size);
}
}
if(line != NULL)
{
line[i] = '\0';
}
}
else
{
free(line);
exit(EXIT_FAILURE);
}
return line;
}
int my_system(char *line)
{
int status;
int size;
if(line == NULL)
{
perror("Line is NULL");
status = EXIT_FAILURE;
}
else
{
size = strlen(line);
if(line[size-2] == '&')
{
signal(SIGCHLD, SIG_IGN);
line[size-3] = '\0';
}
else
{
line[size-1] = '\0';
}
pid_t pid = fork();
switch(pid)
{
case -1:
perror("fork failed");
status = EXIT_FAILURE;
break;
case 0:
if( (line[0] == 'c') && (line[1] == 'd') )
{
my_cd(line);
}
else
{
execl("/bin/sh", "sh", "-c", line, NULL);
}
break;
default:
if(line[size-2] != '&')
{
wait(&status);
}
}
}
return status;
}
void my_cd(char *line)
{
char *dirPath;
char *delim = " ";
dirPath = strtok(line, delim);
dirPath = strtok(NULL, delim);
printf("dirPath is: %s", dirPath);
}
These are the conditions of the program I am making:
If "exit" is entered quit the program
Process arbitrary commands as shell commands by using execl()
Implement your own "cd" (change directory) command
If commands are passed normally make a fork() and let the parent wait for it using wait()
If commands are appended by "&" (i.e. "ls &")don't let the parent wait, and avoid zombie processes by using "signal(SIGCHLD, SIG_IGN)"
I'm halfway through implementing my "cd" command so I did some testing and found out when running the program everything works except when using the "cd" command without appending "&" (i.e. "cd /tmp") it would output fine but then the program won't quit if I type "exit" after that.
Any advice or explanation is greatly appreciated. here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
char *getLine(FILE *in);
int my_system(char *line);
void my_cd(char *line);
int main(int argv, char *args[])
{
char *exitLine = "exit\n";
int status = EXIT_SUCCESS;
for(;;)
{
char *line = getLine(stdin);
if(strcmp(line, exitLine) == 0)
{
break;
}
status = my_system(line);
}
return status;
}
char *getLine(FILE *in)
{
int c = 0;
unsigned long i = 0;
size_t line_size = 80;
char *line = malloc(line_size);
if(ferror(in) == 0)
{
while(line != NULL && c != EOF)
{
while(i < line_size - 1)
{
if((c = getc(in)) == EOF)
{
break;
}
line[i++] = c;
if(c == '\n' || c == '\0')
{
c = EOF;
break;
}
}
if(i >= line_size - i)
{
line_size *= 2;
line = realloc(line, line_size);
}
}
if(line != NULL)
{
line[i] = '\0';
}
}
else
{
free(line);
exit(EXIT_FAILURE);
}
return line;
}
int my_system(char *line)
{
int status;
int size;
if(line == NULL)
{
perror("Line is NULL");
status = EXIT_FAILURE;
}
else
{
size = strlen(line);
if(line[size-2] == '&')
{
signal(SIGCHLD, SIG_IGN);
line[size-3] = '\0';
}
else
{
line[size-1] = '\0';
}
pid_t pid = fork();
switch(pid)
{
case -1:
perror("fork failed");
status = EXIT_FAILURE;
break;
case 0:
if( (line[0] == 'c') && (line[1] == 'd') )
{
my_cd(line);
}
else
{
execl("/bin/sh", "sh", "-c", line, NULL);
}
break;
default:
if(line[size-2] != '&')
{
wait(&status);
}
}
}
return status;
}
void my_cd(char *line)
{
char *dirPath;
char *delim = " ";
dirPath = strtok(line, delim);
dirPath = strtok(NULL, delim);
printf("dirPath is: %s", dirPath);
}