Advertisement
drankinatty

C - minimal shell using fork and execvp

May 21st, 2017
325
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.39 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <limits.h>     /* for PATH_MAX */
  6. #include <signal.h>
  7. #include <sys/types.h>
  8. #include <sys/wait.h>
  9. #include <unistd.h>
  10.  
  11. enum {BASE = 10, ARGSIZE = 20, BUF_SIZE = 1024};    /* constants */
  12.  
  13. void execute (char **args);
  14. void cd (char *directory);
  15. int killpid (char *pitstr, int sig);
  16.  
  17. int main (void) {
  18.    
  19.     char line[BUF_SIZE] = "",
  20.         *args[ARGSIZE],
  21.         *delim = " \n",
  22.         *token;
  23.     int argIndex;
  24.  
  25.     while (1) {
  26.  
  27.         argIndex = 0;                   /* reinitialize variables */
  28.         for (int i = 0; i < ARGSIZE; i++)
  29.             args[i] = NULL;
  30.  
  31.         printf ("shell> ");             /* prompt */
  32.  
  33.         if (!fgets (line, BUF_SIZE, stdin)) {
  34.             fprintf (stderr, "Input canceled - EOF received.\n");
  35.             return 0;
  36.         }
  37.         if (*line == '\n')              /* Enter alone - empty line */
  38.             continue;
  39.  
  40.         for (token = strtok (line, delim); token; token = strtok (NULL, delim))
  41.             args[argIndex++] = token;
  42.  
  43.         if (!argIndex) continue;        /* validate at least 1 arg */
  44.  
  45.         if (strcmp (args[0], "quit") == 0 || strcmp (args[0], "exit") == 0)
  46.             break;
  47.  
  48.         /* handle 'cd' or 'kill' separately */
  49.         if ((strcmp (args[0], "cd") == 0))
  50.             cd (args[1]);
  51.         else if ((strcmp (args[0], "kill") == 0)) {
  52.             if (args[1]) killpid (args[1], SIGTERM);
  53.         }
  54.         else
  55.             execute (args);
  56.  
  57.     }
  58.     return 0;
  59. }
  60.  
  61. void execute (char **args)
  62. {
  63.     pid_t pid, status;
  64.     pid = fork ();
  65.  
  66.     if (pid < 0) {
  67.         perror ("fork");
  68.         return;
  69.     }
  70.     else if (pid > 0) {
  71.         while (wait (&status) != pid)
  72.             continue;
  73.     }
  74.     else if (pid == 0) {
  75.         if (execvp (args[0], args) == -1) {
  76.             perror ("execvp");
  77.         }
  78.         _exit (EXIT_FAILURE);   /* must _exit after execvp return */
  79.     }
  80. }
  81.  
  82. void cd (char *directory)
  83. {
  84.     char dir[PATH_MAX] = "";
  85.  
  86.     if (!directory) {           /* handle 'cd' alone */
  87.         directory = getenv ("HOME");
  88.         if (chdir (directory))
  89.             fprintf (stderr, "error: chdir (%s)\n", directory);
  90.         else
  91.             printf ("%s\n", directory);
  92.         return;
  93.     }
  94.  
  95.     if (*directory == '~') {    /* handle cd ~/stuff */
  96.         strcpy (dir, getenv ("HOME"));
  97.         strcat (dir, "/");
  98.         strcat (dir, directory + 2);
  99.         if (chdir (dir))
  100.             fprintf (stderr, "error: chdir (%s)\n", dir);
  101.         else
  102.             printf ("%s\n", dir);
  103.         return;
  104.     }
  105.  
  106.     if (chdir (directory))      /* handle given directory */
  107.         fprintf (stderr, "Failed to enter directory: %s\n", directory);
  108.     else
  109.         printf ("%s\n", directory);
  110. }
  111.  
  112. int killpid (char *pidstr, int sig)
  113. {
  114.     errno = 0;  /* set errno to validate strtol conversion */
  115.     pid_t pid = (pid_t)strtol (pidstr, NULL, BASE);
  116.    
  117.     if (errno) {
  118.         perror ("strtol");
  119.         return -1;
  120.     }
  121.     else if (pid < 1) { /* validate pid */
  122.         fprintf (stderr, "warning: requested pid < 1, ignoring\n");
  123.         return (int)pid;
  124.     }
  125.    
  126.     /* temporary print of what would be done */
  127.     printf (" killing pid '%d' with signal '%d'\n", (int)pid, sig);
  128.     // return kill (pid, sig);  /* uncomment for actual use */
  129.    
  130.     return 0;
  131. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement