ush.h source code

/***********************************************************
* 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                                          

ush.c source code
/***********************************************************
* 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;
}