/* * cs537 Project 1 - Shell * * Written by Stefan Strandberg (stefan@cs.wisc.edu) * $Id: shell.c,v 1.10 2004/09/23 22:00:27 stefan Exp $ * */ #include #include #include #include #include #include #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; }