As promised…

Now on my introduction I promised I’d be posting code samples of my work through school to help out students and I’m here to deliver. I’ve done a few things but this one I’m actually sort of proud of. Hardcore coders can find little issues with it (such as error correction) but it works very well. The code posted below is a custom script that you can use (almost) to replace bash on a linux system. I’ve dubbed it GShell and it should be able to handle almost all commands save the “cd” command. It currently doesn’t have any form of memory but we’ll be adding that in a future release.

What I really want to highlight here is the use of the pipe() function which allows us to pipe output from child processes to the parent in/out streams. I fought this one for a good while before correcting my error to get a working release. Take a look and let me know what you think.


#include
#include
#include //strcmp(), strtok(), strlen()
#include //fork(), execvp(), pipe(), dup2()
#include //wait()
//
const int MAX_SIZE = 255; //Maximum Size of call string currently allowed
const int MAX_ARGS = 8; //We allow up to 8 arguements
//
void main(int argc, char* argv[])
{
//Loop infinitely
while(1)
{
//Variables
char input_buffer[MAX_SIZE]; //Buffer for user input to our command line
char *args[MAX_ARGS+1]; //The arguments we pass to the new program. Allow 1 array for NULL
char *command; //String pointing to input buffer section holding command to execute
char *user_input; //String to hold input
//
int arg_count = 0; //Number of args provided
int ampersand = 0; //Is there an ampersand?
int c_status,status; //Status values for forking
//
//Execution
printf("GShell$ "); //Basic output
fflush(stdout); //Flush out output
//
//Read from input
fgets(input_buffer,MAX_SIZE,stdin); //Get input from stdin up to MAX_SIZE bytes and place in input_buffer
//
if (feof(stdin)) {
printf("Quitting... Goodbye\n");
exit(0);
}
//
//fgets grabs \n as well. We need to remove it and place NULL in there
if (input_buffer[0] != '\n') { //Simply repeat if we receive a blank input
user_input = input_buffer;
user_input[strlen(user_input)-1] = '\0'; //Terminate with a null
//
//We need to tokenize the input now to retrieve multiple arguments
//First grab the command name
char* token;
token = strtok(user_input," ");
//
//Quit when command is received
if ((strcmp(token,"exit") == 0) || (strcmp(token,"quit") == 0) || (strcmp(token,"logout") == 0)) {
printf("\nQuitting... Goodbye\n");
exit(0);
}
else { //This creates a token
command = token;
args[arg_count] = token;
arg_count++;
}
//
while (arg_count < MAX_ARGS) { //Repeat until we have max arguments or until quit with "break" token = strtok(NULL," "); //Continues to tokenize // //If there isn't any further tokens if (token == NULL || arg_count == MAX_ARGS+1) { args[arg_count] = NULL; break; } else if (strcmp(token,"&") == 0) { ampersand = 1; //Advise that we've detected the ampersand } else { args[arg_count] = token; arg_count++; } } // // We're done tokenizing the input. Time to get to the interesting stuff //Create pipe to fetch our outputs from process int pipeval[2], err; // if (pipe(pipeval) == -1) { perror("pipe error"); exit(1); } char* val[1024]; //First attempt a fork c_status = fork(); // if (c_status > 0) {
if (ampersand == 0) {
wait(&status);
}
}
else if (c_status == 0) {
//Child process
close(pipeval[0]);
dup2(pipeval[1],STDIN_FILENO);
close(pipeval[1]);
//
execvp(command,args);
_exit(1);
}
else {
printf("Fork Error.\n");
exit(1);
}
}
}
return;
}

This entry was posted in Capn, Coding by CapnStank. Bookmark the permalink.

About CapnStank

Software Systems Engineering Graduate working in Operational Support Systems hardware/software and network fault monitoring/provisioning. I have spent the last 5 years or so working on coding projects ranging from games, to utilities to phone apps to almost anything you can imagine.