Reputation: 7
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;
}
Upvotes: 0
Views: 384
Reputation: 18420
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)":"");
Upvotes: 1