You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
minsh/minsh.c

170 lines
4.9 KiB

/*
* =====================================================================================
*
* Filename: minsh.c
*
* Description: A simple shell
*
* Version: 1.8.6
* Created: 08/31/2017 03:14:02 PM
* Revision: none
* Compiler: gcc
*
* Author: David Muckle,
* Organization:
*
* =====================================================================================
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <dirent.h>
#include "hashmap.h"
#include <pwd.h>
#include <sys/types.h>
typedef int bool;
#define true 1
#define false 0
char* user;
char host[32];
bool verbose = false;
char homedir[64];
char* aliascommands[256];
char* aliasnames[256];
int aliascount = 0;
int alias(char* aliasname, char* aliascommand){
strcpy(aliasname, aliasnames[aliascount]);
strcpy(aliascommand, aliascommands[aliascount]);
aliascount++;
return 0;
}
int main(int argc, char** argv)
{
//Help stuff and verbose mode
int should_run = 1;
for(int i = 0; i < argc; i++){
if(strcmp(argv[i], "-v") != 0 && strcmp(argv[i], "--help") != 0 && i>=1){
fprintf(stderr, "Invalid flag, use --help for more information\n");
exit(1);
}
if(strcmp(argv[i], "-v") == 0){
verbose = true;
printf("Running in verbose mode\n");
}
if(strcmp(argv[i], "--help") == 0) {
printf("Minsh - a simple shell\n-v - Start in verbose mode\nMinsh is a simple shell that supports commands and stdout redirection\n");
exit(0);
}
}
if(verbose){
printf("Getting user and hostname for custom prompt\n");
}
struct passwd *userinfo = getpwuid(getuid());
user = userinfo->pw_name;
gethostname(host, 32);
sprintf(homedir, "/home/%s", user);
char dir[128];
while (should_run){
getcwd(dir, 128);
printf("%s@%s:%s> ", user, host, dir);
fflush(stdout);
char command[256];
//Actuall take the command input. Since we have to give fgets a buffer, this determines our command string size too
if(fgets(command, 256, stdin) == NULL){
//If we were just piped input, don't loop on the input, just run whatever command was fed
printf("\n");
break;
}
//If user only hit return, skip all this and just loop back
if(strcmp(command, "\n") == 0){
continue;
}
//Remove the newline at the tail of the command
strtok(command, "\n");
//Exit if we need to
if(strcmp(command, "exit") == 0){
if(verbose){
printf("Alright, we're exiting\n");
}
exit(0);
}
//Chop up the command into the command itself and the arguments
char *cmdArgs[256];
char initialCommand[256];
//Preserve our initial command so we can print it out later if verbose, or if the command is invalid
strcpy(initialCommand, command);
//Start putting flags into cmdArgs
//Running strtok with an arg of NULL just picks up where the last strtok left off
//This also gives us a nifty value in i, the length of the array of args
//We don't have to set the last value to NULL for execvp since strtok does that when it can't find any more strings
int i=0;
cmdArgs[i] = strtok(command, " ");
while(cmdArgs[i] != NULL){
cmdArgs[++i] = strtok(NULL, " ");
}
//Check if we just want to cd
if(strcmp(command, "cd") == 0){
if(i == 1){
if(verbose){
printf("No directory supplied, changing to \"%s\n\"", homedir);
}
chdir(homedir);
continue;
} else {
if(chdir(cmdArgs[1]) == 0){
if(verbose){
printf("Changing directory to \"%s\"\n", cmdArgs[1]);
}
}else{
printf("Error: no such file or directory\n");
}
continue;
}
}
//Perform the actual command
int rc = fork();
if(rc<0){
perror("fork");
exit(1);
}
else if(rc == 0){
//Check if we're redirecting to a file
//We have to check if i is greater than one, because the next conditional subtracts 2 from i
//If i isn't greater than one, we get a bad array access and our command just doesn't run
if(i > 1){
if(strcmp(cmdArgs[i-2], ">") == 0){
if(verbose){
printf("Fork with redirect successful, running \"%s\" with pid %d\n", initialCommand, (int) getpid());
}
close(STDOUT_FILENO);
open(cmdArgs[i-1], O_CREAT|O_WRONLY|O_TRUNC, 0644);
//Set where our > was so execvp won't read past it
cmdArgs[i-2]=NULL;
execvp(command, cmdArgs);
//Execvp will only return if it fails to run a command, thus...
fprintf(stderr, "Command \"%s\" not found...\n", initialCommand);
exit(1);
}
}
if(verbose){
printf("Fork successful, running \"%s\" with pid %d\n", initialCommand, (int) getpid());
}
execvp(command, cmdArgs);
//Execvp will only return if it fails to run a command, thus...
fprintf(stderr, "Command \"%s\" not found...\n", initialCommand);
exit(1);
}
else{
wait(NULL);
if(verbose){
printf("Child process %d (parent pid: %d) done waiting\n", rc, (int) getpid());
}
}
}
return 0;
}