Operating Systems 2014F: Tutorial 2: Difference between revisions

From Soma-notes
No edit summary
No edit summary
 
(3 intermediate revisions by the same user not shown)
Line 3: Line 3:
In tutorial you should do the following exercises in order to better understand this code and the related operating system concepts.  This week's assignment focuses on the concepts you should be learning specifically.
In tutorial you should do the following exercises in order to better understand this code and the related operating system concepts.  This week's assignment focuses on the concepts you should be learning specifically.


# In csimpleshell, Change the prompt to be the current user (e.g., "student $"), as reported by the USER environment variable.
# In csimpleshell, change the prompt to be the current user (e.g., "student $"), as reported by the USER environment variable.
# Make csimpleshell not call <tt>wait()</tt> on the command if there is an & as the last argument to a command; instead, just return another prompt.  Can you see the zombies that are now produced?
# Make csimpleshell not call <tt>wait()</tt> on the command if there is an & as the last argument to a command; instead, just return another prompt.  Can you see the zombies that are now produced?
# Change the <tt>execp()</tt> call to [http://pubs.opengroup.org/onlinepubs/9699919799/functions/execve.html execve()].  Where do you get the extra argument?
# Change the <tt>execp()</tt> call to [http://pubs.opengroup.org/onlinepubs/9699919799/functions/execve.html execve()].  Where do you get the extra argument? (NOTE: When you switch to execve() you will have to specify the full path to commands, e.g. /bin/ls not ls.)
# Add an environment variable called LASTCOMMAND that contains the last command that was executed by csimpleshell.  This environment variable should be passed on to each new program that is run.  How can you check that your code works?
# Add an environment variable called LASTCOMMAND that contains the last command that was executed by csimpleshell.  This environment variable should be passed on to each new program that is run.  How can you check that your code works?
# Use [http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html sigaction()] and [http://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html waitpid()] to create a signal handler for SIGCHLD that prevents the creation of zombies for background commands.
# Use [http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html sigaction()] and [http://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html waitpid()] to create a signal handler for SIGCHLD that prevents the creation of zombies for background commands.

Latest revision as of 18:11, 25 September 2014

In this tutorial you will be playing with and modifying csimpleshell.c by Enrico Franchi. The source is also listed below.

In tutorial you should do the following exercises in order to better understand this code and the related operating system concepts. This week's assignment focuses on the concepts you should be learning specifically.

  1. In csimpleshell, change the prompt to be the current user (e.g., "student $"), as reported by the USER environment variable.
  2. Make csimpleshell not call wait() on the command if there is an & as the last argument to a command; instead, just return another prompt. Can you see the zombies that are now produced?
  3. Change the execp() call to execve(). Where do you get the extra argument? (NOTE: When you switch to execve() you will have to specify the full path to commands, e.g. /bin/ls not ls.)
  4. Add an environment variable called LASTCOMMAND that contains the last command that was executed by csimpleshell. This environment variable should be passed on to each new program that is run. How can you check that your code works?
  5. Use sigaction() and waitpid() to create a signal handler for SIGCHLD that prevents the creation of zombies for background commands.
  6. (Advanced) Implement I/O redirection for STDIN (<) and STDOUT (>). Do the same for arbitrary file descriptors (e.g., 2>).

Code

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#define BUFFER_SIZE 1<<16
#define ARR_SIZE 1<<16

void parse_args(char *buffer, char** args, 
                size_t args_size, size_t *nargs)
{
    char *buf_args[args_size]; /* You need C99 */
    char **cp;
    char *wbuf;
    size_t i, j;
    
    wbuf=buffer;
    buf_args[0]=buffer; 
    args[0] =buffer;
    
    for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
        if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
            break;
    }
    
    for (j=i=0; buf_args[i]!=NULL; i++){
        if(strlen(buf_args[i])>0)
            args[j++]=buf_args[i];
    }
    
    *nargs=j;
    args[j]=NULL;
}


int main(int argc, char *argv[], char *envp[]){
    char buffer[BUFFER_SIZE];
    char *args[ARR_SIZE];

    int *ret_status;
    size_t nargs;
    pid_t pid;
    
    while(1){
        printf("$ ");
        fgets(buffer, BUFFER_SIZE, stdin);
        parse_args(buffer, args, ARR_SIZE, &nargs); 

        if (nargs==0) continue;
        if (!strcmp(args[0], "exit" )) exit(0);       
        pid = fork();
        if (pid){
            printf("Waiting for child (%d)\n", pid);
            pid = wait(ret_status);
            printf("Child (%d) finished\n", pid);
        } else {
            if( execvp(args[0], args)) {
                puts(strerror(errno));
                exit(127);
            }
        }
    }    
    return 0;
}