shortspecialbus icon

shell.c

shortspecialbus | PRO | 05/19/21 08:46:31 PM UTC | 0 ⭐ | 1441 👁️ | Never ⏰ | []
C |

5.33 KB

|

None

|

0 👍

/

0 👎

/*
 * cs537 Project 1 - Shell
 *
 * Written by Stefan Strandberg ([email protected])
 * $Id: shell.c,v 1.10 2004/09/23 22:00:27 stefan Exp $
 *
 */
 
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shell.h"
#include "job.h"
 
#define MAX_INPUT_SIZE 512
#define MAX_JOBS 32766
 
 
///////////////////////
//
// create_shell()
// 
//   * creates a shell and returns it
//
///////////////////////
 
shell_t *create_shell(void) {
    shell_t *shell = (shell_t*)malloc(MAX_INPUT_SIZE);
    if(shell == NULL) {
        fprintf(stderr, "Unable to malloc() in create_shell!!\n");
        exit(1);
    }
    shell->prompt = "turtle > ";
    
    return shell;
}
 
 
 
/////////////////////////
//
// do_jobcmd()
//
//   * executes what's needed for the 'j' shell command
//
//   * FIXME: pid/waitpid problems, although it works.
//
/////////////////////////
 
void do_jobcmd(job_t *job[], int jobnums) {
    int c, result, status;
    for (c = 0 ; c < jobnums - 1 ; c++) {
        result = waitpid(job[c]->pid, &status, WNOHANG);
        // the below shouldn't really work, but it seems to.  I don't care.
        switch (result) {
            case (0): // still running
                print_job(job[c]);
            case (-1):  // who cares, as long as it's not running.  Probably
                        // got reaped weird or something.
            default: // being reaped.
            break;
        }
    }
    return;
}
 
 
 
//////////////////////////
//
// do_waitcmd()
//
//   * does what's needed for the 'w' shell command
//
//////////////////////////
 
void do_waitcmd(job_t *job) {
    int status;
    waitpid(job->pid, &status, 0);
    printf("Job %d terminated\n", job->jid);
    
}
 
 
 
////////////////////////////
//
// run_shell()
//
//   * runs the shell, pretty much does everything.  lots going on here
//   
//   *FIXME:  Memory leak stuff
//   *FIXME:  Extra code here, but I'm out of time
//
///////////////////////////
 
int run_shell(shell_t *shell, int interactive, int *jobnum, job_t *job, 
              FILE *inbuffer) {
    action_t retval = NORMAL;
    char *exitcmd = "exit";
    char *backgroundcmd = "&";
    char *jobcmd = "j";
    char *waitcmd = "w";
    char *command;
    char *args[MAX_INPUT_SIZE];
    char *lastarg = NULL;
    int arg_counter = 0;
    int background = 0;
    int status;
    
    char buffer[2 * MAX_INPUT_SIZE];
    char *input = malloc(2 * MAX_INPUT_SIZE); 
    if (input == NULL) {
        fprintf(stderr, "Unable to malloc() in run_shell()!!\n\n");
        exit(1);
    }
    if (interactive) 
        printf("%s", shell->prompt);
    input = fgets(buffer, MAX_INPUT_SIZE + 1, inbuffer);
    // what the heck do we do with the rest of the line if more than 512??
    if (input == NULL)  { // EOF or Ctrl-D
        return EXITVAL;
    }
    //printf("%s\n", inbuffer);
    if ((strlen(input)) >= MAX_INPUT_SIZE) {
        fprintf(stderr, "Error: Command too long!!\n");
        if (!interactive) { // echo it
            printf("%s\n", input);
            //fflush(stdout);
        }
        while ((strlen(input)) >= MAX_INPUT_SIZE) { // flush it
            // reallocate the pointer
//          free(input);
//          char *input = malloc(2 * MAX_INPUT_SIZE); 
//          if (input == NULL) {
//              fprintf(stderr, "Unable to malloc() in run_shell()!!\n\n");
//              exit(1);
//          }
            input = fgets(buffer, MAX_INPUT_SIZE + 1, inbuffer);
            // reset input
            fflush(inbuffer);
        }
        // flush it one more time
        input = fgets(buffer, MAX_INPUT_SIZE + 1, inbuffer);
        *jobnum += 1; // inc the job counter
        return (NORMAL);
 
    }
    
    if (input == NULL)  { // EOF or Ctrl-D
        retval = EXITVAL;
    }
    else
        if (!interactive) {
            printf("%s", input);
            //fflush(stdout); // add this back if i turn buffering back on
        }
 
    char *token = strtok(input, " \n\t");
    if (token == NULL) {// just ignore an all whitespace string
        return retval;
    }
 
    // ignore a single &
    if ((!retval) && !(strcmp(token, backgroundcmd) == 0)){
        command = token;
        args[arg_counter++] = token; // first arg should be program
        // check for the wait command
        while((token != NULL) && (retval < 1) && (retval != WAITERROR)) { // we don't want a jid retval
            lastarg = token;
            args[arg_counter++] = token = strtok(NULL, " \n\t");
        }
        if (lastarg[strlen(lastarg) - 1] == '&') {
            background = 1;
            if (strcmp(lastarg, backgroundcmd) == 0)
                // remove the last arg, it's a single &
                args[--arg_counter] = NULL;
            else {
                // erase the last character
                args[arg_counter - 2] = strtok(lastarg, "&"); 
            }
        }
        // check to see if we had a shell command
        if (strcmp(command, waitcmd) == 0) {
            // check to see if we had right number of args
            if (arg_counter != 3)
                retval = WAITERROR;
            else {
                retval = atoi(args[arg_counter - 2]);
                // check for 0 retval, it's bad
                if (retval == 0)
                    retval = WAITERROR; // treat it as a bad arg, no jid of 0
            }
        }
        if(strcmp(command, exitcmd) == 0) {
            retval = EXITVAL;
        }
        if(strcmp(command, jobcmd) == 0)
            retval = JOBVAL;
        // create a job
        if (retval == 0) {
            create_job(*jobnum, 0, command, --arg_counter, args, 
                             background, job);
            *jobnum += 1;
            
            //// DO THE JOB!!
            job->pid = fork();
            if (job->pid == -1) {
                fprintf(stderr, "UNABLE TO FORK!! DYING!!\n");
                exit(1);
            }
    
            if (job->pid > 1) { // we are the parent...deal with stuff
                if (!job->background) { // just wait for it to die
                    waitpid(job->pid, &status, 0);
                }
            } else { // we are the child!!
                if ((execv(job->command, job->args)) < 0) {
                    fprintf(stderr, "Unable to exececute your command\n");
                    retval = CHILDEXIT; // 1 makes it exit...
 
                }
            }
        }
    }
    
    return retval;          
}
 
 
 

Comments