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