简体   繁体   中英

Unix shell's input redirection not working

I found the same question but there was no answer.

In building my own unix shell, my output redirection is working fine, but when I try the input it does not do anything. If you could help me figure out the problem that would be great. This is my exec function code:

void execute (char **args)
{
   int pid, status;
   pid = fork ();

   if (pid < 0) 
   {
      perror ("Error forking!");
      return;
   }


   else if (pid > 0) 
   {
      fflush(0);
      while (wait (&status) != pid)
         continue;
   }


   else if (pid == 0) 
   {

      int i,in=0,out=0;
      char input[BUF_SIZE],output[BUF_SIZE];

      for(i=0;args[i]!=NULL;i++)
      {
         if(strcmp(args[i],"<")==0)
         {        
            args[i]=NULL;
            strcpy(input,args[i+1]);
            in=2;           
         }               

         if(strcmp(args[i],">")==0)
         {      
            args[i]=NULL;
            strcpy(output,args[i+1]);
            out=2;
         }         
      }


      if(in)
      {   
         int fd0;
         if ((fd0 = open(input, O_RDONLY, 0)) < 0) 
         {
            perror("Couldn't open input file");
            exit(0);
         }           

         dup2(fd0, 0); 

         close(fd0); 
      }


      if (out)
      {
         int fd1;
         if ((fd1 = creat(output , 0644)) < 0) 
         {
            perror("Couldn't open the output file");
            exit(0);
         }           

         dup2(fd1, 1); 
         close(fd1);
      }

      execvp (*args, args);
      perror("execvp");
      _exit(1);
   }

Here is my whole code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

#define ARGSIZE 20
#define BUF_SIZE 1024

void execute (char **args);
void cd (char *directory);
int killpid (char *pitstr, int sig);

int main (void)
{
    char line[BUF_SIZE] = {0};
    char *args[ARGSIZE] = {NULL};
    char *token;
    int i, argIndex = 0;

    while (1) 
    {

        argIndex = 0; 

        for (i = 0; i < ARGSIZE; i++)
            args[i] = NULL;

        printf ("shell> "); 

        if (fgets (line, BUF_SIZE, stdin) == NULL) 
        {
            printf ("EOF received\n");
            return 0;
        }

        if (*line == '\n') 
        continue;

        token = strtok (line, " \n"); 

        while (token != NULL) 
        {
            args[argIndex] = token;
            token = strtok (NULL, " \n");
            argIndex++;
        }

        if (!argIndex)
            continue;  

        if (strcmp (args[0], "quit") == 0 || strcmp (args[0], "exit") == 0)
            break;

        if ((strcmp (args[0], "cd") == 0))
            cd (args[1]);
        else if ((strcmp (args[0], "kill") == 0)) 
        {
            if (args[1])
                killpid (args[1], SIGTERM);
        }


        else
            execute (args);

    }
    return 0;
}

void execute (char **args)
{
    int pid, status;
    pid = fork ();

    if (pid < 0) 
    {
        perror ("Error forking!");
        return;
    }


    else if (pid > 0) 
    {
        fflush(0);
        while (wait (&status) != pid)
            continue;
    }


    else if (pid == 0) 
    {

        int i,in=0,out=0;
        char input[BUF_SIZE],output[BUF_SIZE];

        for(i=0;args[i]!=NULL;i++)
        {
            if(strcmp(args[i],"<")==0)
            {        
                args[i]=NULL;
                strcpy(input,args[i+1]);
                in=2;           
            }               

            if(strcmp(args[i],">")==0)
            {      
                args[i]=NULL;
                strcpy(output,args[i+1]);
                out=2;
            }         
        }


        if(in)
        {   
            int fd0;
            if ((fd0 = open(input, O_RDONLY, 0)) < 0) 
            {
                perror("Couldn't open input file");
                exit(0);
            }           

            dup2(fd0, 0); 
            close(fd0); 
        }


        if (out)
        {
            int fd1;
            if ((fd1 = creat(output , 0644)) < 0) 
            {
                perror("Couldn't open the output file");
                exit(0);
            }           

            dup2(fd1, 1); 
            close(fd1);
        }

        execvp (*args, args);
        perror("execvp");
        _exit(1);
        }

}

void cd (char *directory)
{
    char dir[BUF_SIZE] = {0};

    if (!directory) 
    {  
        directory = getenv ("HOME");

        if (chdir (directory))
            fprintf (stderr, "Failed to enter directory: %s\n", directory);
        else
            printf ("%s\n", directory);

        return;
    }

    if (*directory == '~') 
    { 
        strcpy (dir, getenv ("HOME"));
        strcat (dir, "/");
        strcat (dir, directory + 2);

        if (chdir (dir))
            fprintf (stderr, "Failed to enter directory: %s\n", dir);
        else
            printf ("%s\n", dir);

        return;
    }

    if (chdir (directory)) 
        fprintf (stderr, "Failed to enter directory: %s\n", directory);
    else
        printf ("%s\n", directory);
}

int killpid (char *pidstr, int sig)
{
    pid_t pid = (pid_t)atoi (pidstr);

    if (pid < 1) 
    {
        fprintf (stderr, "warning: requested pid < 1, ignoring\n");
        return (int)pid;
    }

    printf (" killing pid '%d' with signal '%d'\n", (int)pid, sig);
    return 0;
}

When you see a < in the args array here

if(strcmp(args[i],"<")==0)

you set args[i] to NULL

    args[i]=NULL;

But then, you pass it to strcmp()

if(strcmp(args[i],">")==0)

and your child process will happily segfault. Use an if-else -construct here:

if(strcmp(args[i],"<")==0) {        
    args[i]=NULL;
    strcpy(input,args[i+1]);
    in=2;           
} else if(strcmp(args[i],">")==0) {      
    args[i]=NULL;
    strcpy(output,args[i+1]);
    out=2;
}

This should fix the error.

Furthermore, this might come in handy to detect such situations:

...
while (wait (&status) != pid)
     continue;
if (WIFSIGNALED(status))
     printf("Killed by signal %d%s\n",
            WTERMSIG(status), WCOREDUMP(status)?" (Core dumped)":"");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM