CS 3423 Assignment 7 Forks Execs and Interprocess Communica

CS 3423 Assignment 7 : Forks, Execs and Interprocess Communication Due midnight Friday, December 2, 2016 This project is to write a C program that works like a simple shell. It should continuously read user input, and execute commands/programs based on the user input. It should also handle redirection, piping and backgrounding. 1. Develop your program in a directory named assign7!!! 2. The program should be named hsh. 3. The shell should terminate on the command “exit”. 4. The program should handle stdin, stdout and append redirection ( <, > and >> ). It should be able to handle scripts being redirected to stdin, i.e. non-interactive input. 5. The program should handle backgrounding (i.e. the program creates child process to execute a command, and will not wait for that particular child process to terminate). However zombies should be reasonably handled. Check out Figure 8.8 from the textbook ”Advanced Programming in the Unix Environment” to see how zombies can be avoided by forking twice. 6. The program should handle one level of piping with possible redirection. Thus the most complicated command would have a form similar to: prog1 arg1 arg2 | prog2 arg3 < infile > outfile & 7. A command-line parser is in /usr/local/courses/cs3423/assign8 and is called cmdscan.c. This function should be LINKED with hsh and MUST be kept as a separate file, cmdscan.c and may NOT be included in hsh.c. The function cmdscan should be passed the command line and cmdscan will parse the command line and fill out a structure as follows: struct cmd { int redirect_in; /* Any stdin redirection? */ int redirect_out; /* Any stdout redirection? */ int redirect_append; /* Append stdout redirection? */ int background; /* Put process in background? */ int piping; /* Pipe prog1 into prog2? */ char *infile; /* Name of stdin redirect file */ char *outfile; /* Name of stdout redirect file */ char *argv1[10]; /* First program to execute */ char *argv2[10]; /* Second program in pipe */ } 1 There are 5 flags, all of which will be set, indicating whether there is any redirection and, if so, the name of the file associated with the redirection, whether the process is to be placed in the background, and whether the stdout of prog1 (argv1[0]) is to be piped into the stdin of another program, prog2 (argv2[0]). The arrays argv1[ ] and argv2[ ] are standard NULL terminated argv arrays for the first command and the second command in the pipe. 8. In order to do the backgrounding, the shell program should not wait for the process. If backgrounding is not required, the shell should wait for that process to complete. In the case of a piped command, it is sufficient to wait for the second process in the pipe to complete. Notice that it is not sufficient to merely wait for any child to die but that the shell must wait for a particular process to die. 9. Notice that, in the case of piping, the stdin redirection affects the stdin of the first program while the stdout redirection affects the stdout of the second program. 10. Software packages need to execute on many different UNIX systems and, unfortunately, there are differences between system calls and libraries on different systems. Rather than have the user try to configure a package for his system, if different from the developer’s, the developer configures his software via ifdefs in the code for the various flavors of unix and then he uses programs, autoconf and automake, to create a configure program which, when run by the installer, will check all aspects of the system so that the software can be installed correctly. You are going to make a simple configure distribution for “your software package”, hsh.c. The steps are simple: (a) Make the following files in your assign7 directory (add any additional source/header files to hsh SOURCES): Makefile.am bin_PROGRAMS = hsh hsh_SOURCES = hsh.c cmdscan.c configure.in AC_INIT(hsh.c) AM_INIT_AUTOMAKE(hsh,1.0) AC_PROG_CC AC_PROG_INSTALL AC_OUTPUT(Makefile) (b) Execute the following commands: aclocal autoconf touch README AUTHORS NEWS ChangeLog automake -a configure make 2 (c) Now you can make the distribution: make distcheck (d) Now copy hsh-1.0.tar.gz, which is your distribution into your assign7 directory. This is the only file that should be in your assign7 directory! (e) To check your distribution, copy hsh-1.0.tar.gz into a different directory and untar, configure and make it: tar -xzvf hsh-1.0.tar.gz cd hsh-1.0 ./configure make Now you can execute your program. 11. Remember, the assignment must be turned in by the due time. No late projects allowed. 3 4

Solution

hsh.c

#include <stdio.h>     // Standard IO for printf and perror
#include <stdlib.h>    // Standard library for base functions.
#include <string.h>    // String library for string manipulation.
#include <unistd.h>    // Low level IO and forking functions.
#include <sys/types.h> // Includes type definitions for extended vocab
#include <sys/stat.h> // Defines variables for stat, ftstat, lstat and chmod.
#include <sys/fcntl.h> // Includes definitions for file control, read & write permissions and extended definitions
#define BUFSZ 1024

struct cmd
{
    int redirect_in; /* Any stdin redirection? */
    int redirect_out; /* Any stdout redirection? */
    int redirect_append; /* Append stdout redirection? */
    int background; /* Put process in background? */
    int piping; /* Pipe prog1 into prog2? */
    char *infile; /* Name of stdin redirect file */
    char *outfile; /* Name of stdout redirect file */
    char *argv1[10]; /* First program to execute */
    char *argv2[10]; /* Second program in pipe */
}command;

int main(void){
    char buf[BUFSZ];
    int fd[2];
    int fd_file_in;
    int fd_file_out;
    int writePermissions;    // Stores the permissions for file creation
    pid_t pid;               // Stores the pid
    while(fgets(buf, BUFSZ, stdin))
    {
        if(strcmp(buf, \"exit\ \") == 0) // Base exit case
            exit(0);
        if(cmdscan(buf, &command) == -1)
        {
            printf(\"Illegal Format: \ \");
            continue;
        }
        switch(pid = fork())
        {
            case -1:
                perror(\"An error occured while forking.\");
                exit(-1);
            case 0:
                if(command.background)
                {
                    switch(fork())
                    {
                        case -1:
                            perror(\"An error occured while forking.\");
                            exit(-1);
                        case 0:
                            break;
                        default:
                            exit(0);
                    }
                }
                break;
            default:
                waitpid(pid, NULL, 0);
        }

        // Check for child / grandchild
        if(pid == 0)
        {
            if(command.redirect_in)
            {
                if((fd_file_in = open(command.infile, O_RDONLY, 0600)) == -1)
                {
                    perror(\"An open error occured.\");
                    exit(-1);
                }

                if((dup2(fd_file_in, STDIN_FILENO)) == -1)
                {
                    perror(\"An error occured with dup2.\");
                    exit(-1);
                }
                close(fd_file_in);
            }
            if(command.redirect_out)
            {
                if(command.redirect_append)
                    writePermissions = O_WRONLY | O_CREAT | O_APPEND;
                else
                    writePermissions = O_WRONLY | O_CREAT | O_TRUNC;

                if((fd_file_out = open(command.outfile, writePermissions, 0666)) == -1)
                {
                    perror(\"An open error occured.\");
                    exit(-1);
                }
                dup2(fd_file_out, STDOUT_FILENO);
                close(fd_file_out);
            }
            // If the piping is turned on, we want to pipe, dup the fd
            // for the appropriate redirection, and execute the cmd
            if(command.piping)
            {
                if(pipe(fd) == -1)
                {
                    perror(\"An error occured while opening the pipe.\");
                    exit(-1);
                }

                switch(fork())
                {
                    case -1:
                        perror(\"An error occured while forking.\");
                        exit(-1);
                    case 0: // Child
                        dup2(fd[1], STDOUT_FILENO);
                        close(fd[1]);
                        close(fd[0]);
                        execvp(command.argv1[0], command.argv1);
                        perror(\"Exec Error\");
                        exit(-1);
                    default: // Parent
                        dup2(fd[0], STDIN_FILENO);
                        close(fd[0]);
                        close(fd[1]);
                        execvp(command.argv2[0], command.argv2);
                        perror(\"An error occured during execution.\");
                        exit(-1);
                }
            }
            execvp(command.argv1[0], command.argv1);
            perror(\"An error occured during execution.\");
            exit(-1);
        }
    }
    //Never reached.
}


cmdscan.c

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>

struct cmd
{
    int redirect_in;     /* Any stdin redirection?         */
    int redirect_out;    /* Any stdout redirection?        */
    int redirect_append; /* Append stdout redirection?     */
    int background;      /* Put process in background?     */
    int piping;          /* Pipe prog1 into prog2?         */
    char *infile;        /* Name of stdin redirect file    */
    char *outfile;       /* Name of stdout redirect file   */
    char *argv1[10];     /* First program to execute       */
    char *argv2[10];     /* Second program in pipe         */
};

#define TRUE 1
#define FALSE 0

int
cmdscan(char *cmdbuf, struct cmd *com)
{
char *token;
char *curcmd;        /* pointer to current command string */
char swtch[256];    /* buffer to hold copy of switch */
char *separators = \" \\t\ \";
int i;

com->redirect_in = FALSE;
com->redirect_out = FALSE;
com->redirect_append = FALSE;
com->background = FALSE;
com->piping = FALSE;

if ( (com->argv1[0] = strtok(cmdbuf,separators) ) == NULL)
    return(-1);
i = 1;
while( (com->argv1[i++] = (token = strtok(NULL,separators))) != NULL && strcmp(token,\">\") &&
        strcmp(token,\"<\") && strcmp(token,\">>\") && strcmp(token,\"&\") && strcmp(token,\"|\") );
com->argv1[i-1] = NULL;

if ( token != NULL && strcmp(token,\"|\") == 0 )
    {
      com->piping = TRUE;
      i = 0;
      while( (com->argv2[i++] = (token = strtok(NULL,separators))) != NULL && strcmp(token,\">\") &&
        strcmp(token,\"<\") && strcmp(token,\">>\") && strcmp(token,\"&\") && strcmp(token,\"|\") );
      com->argv2[i-1] = NULL;
      if ( com->argv2[0] == NULL )
        return(-1);
    }

while ( token != NULL ){

    if ( !strcmp(token,\">\") || !strcmp(token,\">>\") )
      {
        if ( com->redirect_out )
          return(-1);
        com->redirect_out = TRUE;
        if ( !strcmp(token,\">>\") )
          com->redirect_append = TRUE;
        if ( (com->outfile = strtok(NULL,separators)) == NULL )
          return(-1);
      }
    else if ( !strcmp(token,\"<\") )
      {
        if ( com->redirect_in )
          return(-1);
        com->redirect_in = TRUE;
        if ( (com->infile = strtok(NULL,separators)) == NULL )
          return(-1);
      }
    else if ( !strcmp(token,\"|\") )
      {
        if ( com->piping )
          return(-1);
      }
    else if ( !strcmp(token,\"&\") )
      {
        if ( com->background )
          return(-1);
        com->background = TRUE;
        if ( (token = strtok(NULL,separators)) != NULL )
          return(-1);
        break;
      }
    else
      return(-1);

    token = strtok(NULL,separators);
}

return(0);
}

CS 3423 Assignment 7 : Forks, Execs and Interprocess Communication Due midnight Friday, December 2, 2016 This project is to write a C program that works like a
CS 3423 Assignment 7 : Forks, Execs and Interprocess Communication Due midnight Friday, December 2, 2016 This project is to write a C program that works like a
CS 3423 Assignment 7 : Forks, Execs and Interprocess Communication Due midnight Friday, December 2, 2016 This project is to write a C program that works like a
CS 3423 Assignment 7 : Forks, Execs and Interprocess Communication Due midnight Friday, December 2, 2016 This project is to write a C program that works like a
CS 3423 Assignment 7 : Forks, Execs and Interprocess Communication Due midnight Friday, December 2, 2016 This project is to write a C program that works like a

Get Help Now

Submit a Take Down Notice

Tutor
Tutor: Dr Jack
Most rated tutor on our site