#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
/* The array below will hold the arguments: args[0] is the command. */
static char* args[512];
/* Modify this function to run commands.
* 'first' and 'last' are useful when connecting pipes.
*
* input: return value from previous command (useful for pipe file descriptor)
* first: 1 if first command in pipe-sequence (no input from previous pipe)
* last: 1 if last command in pipe-sequence (no input from previous pipe)
*
* EXAMPLE: If you type "ls | grep shell | wc" in your shell:
* fd1 = command(0, 1, 0), with args[0] = "ls"
* fd2 = command(fd1, 0, 0), with args[0] = "grep" and args[1] = "shell"
* fd3 = command(fd2, 0, 1), with args[0] = "wc"
*
* So if 'command' returns a file descriptor, the next 'command' has this
* descriptor as its 'input'.
*/
static int command(int input, int first, int last)
{
/* Be careful when using 'fork': make sure the child terminates
(call 'exit' if 'execvp' fails). */
int i, commands = 0;
pid_t pid;
char *env[] = { "HOME=/usr/home/", "LOGNAME=home", (char *)0 };
char loc[35] = "";
int pd[2];
/* Initialize the pipe */
if(last == 0) {
fprintf(stderr,"Pipe created.\n");
if(pipe(pd) < 0) {
perror("Creating pipe");
exit(EXIT_FAILURE);
}
}
pid = fork();
if(pid == 0) { /* Child */
/* Redirection and closing of pipes */
if(first == 1 && last == 0) {
dup2(pd[1],1);
close(pd[1]);
}
else if(first == 0 && last == 1) {
dup2(input,0);
close(input);
close(pd[0]);
close(pd[1]);
}
else if(first == 0 && last == 0) {
dup2(pd[1],1);
close(pd[1]);
dup2(input,0);
close(input);
}
/* Construct the command */
strcat(loc,"/bin/");
strcat(loc,args[0]);
fprintf(stderr,"command: %s\n", args[0]);
for (i = 1; args[i] != NULL; i++) {
commands++;
fprintf(stderr,"argument %d: %s\n", i, args[i]);
}
char *cmd[commands+1];
for(i = 0; args[i] != NULL; i++) {
cmd[i] = args[i];
}
cmd[commands+1] = (char *)0;
/* Call the constructed command */
execve(loc, cmd, env);
exit(EXIT_SUCCESS);
}
else { /* Parent */
wait(NULL);
/* IF one single command, return 0 */
if(first == 1 && last == 1) {
return 0;
}
close(pd[1]);
if(last == 1) {
close(input);
close(pd[0]);
return 0;
}
}
return pd[0];
}
/* Here you can do some final cleanup, such as 'wait' for
* processes to terminate.
*
* n : Number of times 'command' was invoked.
*/
static void cleanup(int n)
{
/* something like this, perhaps: */
int i;
for(i = 0; i < n; i++) wait(NULL);
}
/*
* NOTHING need to be changed below here...
*/
static int run(char* cmd, int input, int first, int last);
static char line[1024];
static int n = 0; /* number of calls to 'command' */
int main()
{
printf("SIMPLE SHELL: Type 'exit' or send EOF to exit.\n");
while (1) {
/* Print the command prompt */
printf("$> ");
fflush(NULL);
/* Read a command line */
if (!fgets(line, 1024, stdin))
return 0;
int input = 0;
int first = 1;
char* cmd = line;
char* next = strchr(cmd, '|'); /* Find first '|' */
while (next != NULL) {
/* 'next' points to '|' */
*next = '\0';
input = run(cmd, input, first, 0);
cmd = next + 1;
next = strchr(cmd, '|'); /* Find next '|' */
first = 0;
}
input = run(cmd, input, first, 1);
cleanup(n);
n = 0;
}
return 0;
}
static void split(char* cmd);
static int run(char* cmd, int input, int first, int last)
{
split(cmd);
if (args[0] != NULL) {
if (strcmp(args[0], "exit") == 0)
exit(0);
n += 1;
return command(input, first, last);
}
return 0;
}
static char* skipwhite(char* s)
{
while (isspace(*s)) ++s;
return s;
}
static void split(char* cmd)
{
cmd = skipwhite(cmd);
char* next = strchr(cmd, ' ');
int i = 0;
while(next != NULL) {
next[0] = '\0';
args[i] = cmd;
++i;
cmd = skipwhite(next + 1);
next = strchr(cmd, ' ');
}
if (cmd[0] != '\0') {
args[i] = cmd;
next = strchr(cmd, '\n');
next[0] = '\0';
++i;
}
args[i] = NULL;
}