+1 (315) 557-6473 

Unix command-line shell with pipe support and I/O redirection using C programming homework help

The assignment deals with implementing a simple Unix command-line shell called nsh. Our C programming homework help experts design a program that supports shell scripts, runs arbitrary commands with arguments, implements the internal cd command, and uses pipes for executing commands and I/O redirection. The program is written in C. the shell implements a subset of the Bourne shell. The program is based on a command-line parser
Table Of Contents
  • Parsing Command-Line Shells for UNIX

Parsing Command-Line Shells for UNIX

#include "parse.h" /* Removes the initial and trailing spaces in the given string */ char *trim(char *string) { char *p=string; while(*p && isspace(*p)) p++; if(!*p) return p; while(isspace(p[strlen(p)-1])) p[strlen(p)-1]=0; return p; } /* Splits a string using the given delimiter, returns a list of string pointers to the split parts, the last element in the list is NULL, n is updated to the number of elements in the list */ char **split(char *string,char *delim,int *n) { char **parts=NULL; char *token; (*n)=0; token = strtok(string,delim); while(token!=NULL) { if(parts==NULL) parts = (char **)malloc(2*sizeof(char*)); else parts=(char **)realloc(parts,((*n)+2)*sizeof(char*)); parts[(*n)++] = token; token = strtok(NULL,delim); } if((*n)>0) parts[(*n)] = NULL; return parts; } /* Splits a command string using spaces, returns a list of string pointers to the split parts, the last element in the list is NULL, n is updated to the number of elements in the list leaves strings ' ' unchanged */ char **split_args(char *string,int *n) { char **parts=NULL; char *p,*token; (*n)=0; p = string; while(*p && isspace(*p)) p++; if(!*p) return NULL; token = p; while(token!=NULL) { if(parts==NULL) parts = (char **)malloc(2*sizeof(char*)); else parts=(char **)realloc(parts,((*n)+2)*sizeof(char*)); parts[(*n)++] = token; if(*p=='\'') { p++; parts[(*n)-1] = p; while(*p && *p!='\'') p++; if(!*p) /* unclosed quote */ { free(parts); return NULL; } } else while(*p && !isspace(*p)) p++; if(*p) *(p++)=0; while(*p && isspace(*p)) p++; if(!*p) token=NULL; else token=p; } parts[(*n)] = NULL; return parts; } /* Retrieves the redirection files for the given command and the clean command string without redirections, the results are saved in a dynamically allocated command_t structure */ command_t *split_redirections(char *command) { char *p=command; char redir[3]; char *file = NULL; command_t *cmd; int i; cmd = (command_t*) malloc(sizeof(command_t)); cmd->in_file = NULL; cmd->out_file = NULL; cmd->cat_file = NULL; while(*p && *p!='<' && *p!='>') p++; cmd->command = (char *)malloc(p-command+1); strncpy(cmd->command,command,p-command); cmd->command[p-command]=0; if(!*p) return cmd; p=command; while(1) { while(*p && *p!='<' && *p!='>') p++; if(!*p) return cmd; redir[0] = *p; redir[1] = 0; if(*(p+1)=='>') { p++; redir[1]=*p; redir[2] = 0; } p++; while(*p && isspace(*p)) p++; if(!*p) return cmd; file = p; while(*p && !isspace(*p)) p++; if(*p) *(p++) =0; if(redir[0]=='<') cmd->in_file=strdup(file); else if(redir[0]=='>' && redir[1]==0) cmd->out_file=strdup(file); else cmd->cat_file=strdup(file); } return cmd; } /* Frees all the allocated memory used by a command_t structure */ void free_command(command_t *cmd) { if(cmd->args) free(cmd->args); free(cmd->command); if(cmd->in_file!=NULL) free(cmd->in_file); if(cmd->out_file!=NULL) free(cmd->out_file); if(cmd->cat_file!=NULL) free(cmd->cat_file); free(cmd); } /* Frees the allocated memory for the command list given in cmd of size n */ void free_commands(command_t **cmd,int n) { int i; for(i=0; iargs = split_args(cmd[i]->command,&m); // split(cmd[i]->command," ",&m); if(cmd[i]->args==NULL) { fprintf(stderr,"Error: invalid command: '%s'\n",commands[i]); for(;i>=0; i--) free_command(cmd[i]); free(cmd); cmd=NULL; break; } } free(commands); return cmd; } #ifndef PARSE_H #define PARSE_H #include #include #include #include typedef struct { char *in_file; char *out_file; char *cat_file; char *command; char **args; }command_t; command_t **parse(char *line,int *n); char *trim(char *string); char **split(char *string,char *delim,int *n); command_t *split_redirections(char *command); void free_command(command_t *cmd); void free_commands(command_t **cmd,int n); #endif /* PARSE_H*/ #include #include #include #include #include #include "parse.h" int last_status = 0; /* Executes a single command using the given pipes for redirection */ int execute_command(command_t *cmd,int pipe_in,int pipe_out,int *status) { pid_t pid; int in_fd,out_fd; *status = 0; if(!strcmp(cmd->args[0],"exit")) { if(cmd->args[1]!=NULL) last_status = atoi(cmd->args[1]); return 1; } pid = fork(); if(pid<0) { fprintf(stderr,"Error: unable to fork(). Exiting...\n"); exit(1); } else if(pid ==0) { if(cmd->in_file!=NULL) /* if the command has an input redirection*/ { if((in_fd=open(cmd->in_file,O_RDONLY))==-1) { fprintf(stderr,"Error: Unable to open file: '%s'\n",cmd->in_file); exit(1); } dup2(in_fd,STDIN_FILENO); /* use file as stdin */ close(in_fd); /* close duplicate */ if(pipe_in!=-1) /* if there was an input pipe, close it*/ close(pipe_in); } else if(pipe_in!=-1) /* else, if connected to an input pipe */ dup2(pipe_in,STDIN_FILENO); if(cmd->out_file!=NULL || cmd->cat_file!=NULL) /* if the command has an output redirection*/ { if(cmd->out_file!=NULL) /* create file */ { if((out_fd=open(cmd->out_file,O_WRONLY|O_CREAT|O_TRUNC,0666))==-1) /* create new file */ { fprintf(stderr,"Error: Unable to open file: '%s'\n",cmd->out_file); exit(1); } } else { if((out_fd=open(cmd->cat_file,O_WRONLY|O_CREAT|O_APPEND,0666))==-1) /* append to file */ { fprintf(stderr,"Error: Unable to open file: '%s'\n",cmd->cat_file); exit(1); } } dup2(out_fd,STDOUT_FILENO); /* use file as stdout */ close(out_fd); /* close duplicate */ if(pipe_out!=-1) /* if there was an output pipe, close it*/ close(pipe_out); } else if(pipe_out!=-1) /* else, if connected to an output pipe */ dup2(pipe_out,STDOUT_FILENO); execvp(cmd->args[0],cmd->args); fprintf(stderr,"Error: Invalid command: '%s'\n",cmd->args[0]); exit(1); } wait(status); *status = WEXITSTATUS(*status); return 0; } /* Executes all the commands in the command list */ int execute_all_commands(command_t **commands,int n) { int i; int **pipe_fd; int pipe_in,pipe_out; int exit_shell = 0; int status; if(i==1) /* if only 1 command, execute it directly */ { exit_shell=execute_command(commands[0],-1,-1,&status); if(!exit_shell) last_status = status; } else { pipe_fd = (int**) malloc((n-1)*sizeof(int*)); for(i=0; i1) { input = fopen(argv[1],"rt"); if(input==NULL) { fprintf(stderr,"Unable to open file: '%s'\n",argv[1]); exit(1); } interactive = 0; } else { input = stdin; interactive = 1; } while(!quit) { if(interactive) { printf("? "); fflush(stdout); } if(getline(&line,&linesize,input)!=-1) { commands = parse(line,&ncommands); if(commands!=NULL) { quit = execute_all_commands(commands,ncommands); free_commands(commands,ncommands); } } else quit = 1; } free(line); exit(last_status); }