/***********************************************************
* Program 3 -- Shell
* cs451, Fall 1999
* Sergei Barbotko
************************************************************/
#ifndef __USH_H__
#define __USH_H__
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
#include <limits.h>
#define STDMODE 0600
#define DELIMITERSET " ><|&"
#ifndef MAX_CANON
#define MAX_CANON 256
#endif
#define TRUE 1
#define FALSE 0
#define BLANK_STRING " "
#define PROMPT_STRING ">>"
#define QUIT_STRING "q"
#define BACK_STRING "&"
#define PIPE_STRING "|"
#define NEWLINE_STRING "\n"
#define IN_REDIRECT_SYMBOL '<'
#define OUT_REDIRECT_SYMBOL '>'
#define NULL_SYMBOL '\0'
#define PIPE_SYMBOL '|'
#define BACK_SYMBOL '&'
#define NEWLINE_SYMBOL '\n'
int makeargv(char *s, char *delimiters, char ***argvp);
int parseFile(char *inbuf, char delimiter, char **v);
int redirect(char *inFileName, char *outFileName);
void executecmdline(char *cmd);
int connectPipeLine(char *cmd, int frontfd[], int backfd[]);
#endif
/***********************************************************
* Program 3 -- Shell
* cs451, Fall 1999
* Sergei Barbotko
************************************************************/
#include "ush.h"
#include <signal.h>
#include <setjmp.h>
static void jumphand(int);
static sigjmp_buf jump_to_prompt;
static volatile sig_atomic_t okaytojump = 0;
/*********************************************************
* function clears end of string str (delete NEWLINE_SYMBOL,
* as well as spaces. Returns last symbol in the string.
*/
char* clearStrEnd(char* str)
{
char* strEnd;
if (strlen(str) == 0)
return str;
strEnd = str + strlen(str) - 1;
if (*strEnd == NEWLINE_SYMBOL)
*strEnd = ' ';
while (strEnd != str && *strEnd == ' ')
{
*strEnd = 0;
--strEnd;
}
return strEnd;
}
/*********************************************************
* Function checks if command in string str is 'cd' or not.
* Executes cd command (including simple 'cd' -- home) and
* returns 1. If command is not 'cd' returns 0.
*/
int checkCD(char* str)
{
char* dir;
char copy[MAX_CANON];
if (strlen(str) == 0 || strcmp(str, " ") == 0)
return -1;
strcpy(copy, str);
if (parseFile(copy, ' ', &dir) == -1)
{
perror("Error of checking command line");
exit(1);
}
if (strcmp(copy, "cd") == 0)
{
if (dir == 0 || strlen(dir) == 0)
chdir(getenv("HOME"));
else
chdir(dir);
return 1;
}
return 0;
}
/*********************************************************
* Very simple handler for parent. Does long jump to the
* prompt place.
*/
static void jumphand(int signalnum)
{
if (!okaytojump) return;
okaytojump = 0;
siglongjmp(jump_to_prompt, 1);
}
/*********************************************************
* Main implements general functionality.
*/
int main (void)
{
char inbuf[MAX_CANON];
char* strEnd;
pid_t child_pid;
pid_t wait_pid;
pid_t bkgrnd_pid;
int inBackground;
struct sigaction jumphd;
struct sigaction defaulthd;
sigset_t blockmask;
/* Set up a mask to block SIGINT and SIGQUIT */
sigemptyset(&blockmask);
sigaddset(&blockmask, SIGINT);
sigaddset(&blockmask, SIGQUIT);
/* Set up the handlers for prompt and default */
jumphd.sa_handler = jumphand;
jumphd.sa_mask=blockmask;
jumphd.sa_flags = 0;
defaulthd.sa_handler = SIG_DFL;
sigemptyset(&defaulthd.sa_mask);
defaulthd.sa_flags = 0;
/* Set up to handle jump to prompt */
if ((sigaction(SIGINT, &jumphd, NULL) < 0) ||
(sigaction(SIGQUIT, &jumphd, NULL) < 0))
{
perror("shell failed to install signal handlers");
exit(1);
}
for(;;)
{
if (sigsetjmp(jump_to_prompt, 1))
{
/* Redisplay prompt on a new line if return from signal */
fputs(NEWLINE_STRING, stdout);
}
okaytojump = 1;
fputs(PROMPT_STRING, stdout);
if (!fgets(inbuf, MAX_CANON, stdin))
break;
strEnd = clearStrEnd(inbuf);
if (checkCD(inbuf) == 1)
continue;
inBackground = FALSE;
if (*strEnd == BACK_SYMBOL)
{
*strEnd = 0;
inBackground = TRUE;
}
if (strcmp(inbuf, QUIT_STRING) == 0)
break;
sigprocmask(SIG_BLOCK, &blockmask, NULL);
if ((child_pid = fork()) > 0)
{
waitpid(child_pid, NULL, 0);
}
else
if (child_pid < 0)
{
perror("Error of command execution");
exit(1);
}
else
{
if ((sigaction(SIGINT, &defaulthd, NULL) < 0) ||
(sigaction(SIGQUIT, &defaulthd, NULL) < 0))
{
perror("Child could not restore default handlers");
exit(1);
}
if (inBackground)
{
if ((bkgrnd_pid = fork()) < 0)
{
perror("Error of background execution");
exit(1);
}
else
{
if (bkgrnd_pid > 0)
exit(0);
}
if (setpgid(getpid(), getpid())== -1)
exit(1);
}
sigprocmask(SIG_UNBLOCK, &blockmask, NULL);
executeCmdLine(inbuf);
exit(1);
}
sigprocmask(SIG_UNBLOCK, &blockmask, NULL);
}
return 0;
}