Edit: The issue is that echo does not read from stdin apparently. Thanks @Jonathan Leffler
I have a programming exercise, and my code is below:
int processProgram(char **tokens, int requireWait) {
char *cmd = tokens[0];
if (access(cmd, R_OK) == -1) {
printf("%s not found\n", cmd);
return -1;
}
int index = 1;
char *iterator = tokens[index];
int inputTokenIndex = 0;
// Look for a < to figure out where the redirection is
while (iterator != NULL) {
if (strcmp(iterator, "<") == 0) { // <---- THIS IS WHERE I ATTEMPT TO FIND THE INDEX OF "<"
if (access(tokens[index + 1], R_OK) == -1) {
printf("%s does not exist\n", tokens[index + 1]);
return -1;
}
// set null at <
tokens[index] = NULL;
inputTokenIndex = index + 1;
break;
}
index++;
iterator = tokens[index];
}
// basically create a struct to store pids and stuff....
processList *process = addNewProcess();
int childPid = fork();
if (childPid == 0) {
// is the child
if (inputTokenIndex > 0) {
// if previously strcmp "<" is true
// set redirection for input....
int fd = open(tokens[inputTokenIndex], O_RDONLY); // <----- THIS IS WHERE I DO THE REDIRECTING FOR STDIN!
dup2(fd, STDIN_FILENO);
close(fd);
}
// start from where inputTokenIndex could have left off
// since > is always at least after < in our test cases
index = inputTokenIndex + 1;
iterator = tokens[index];
while (iterator != NULL) { // <--- LOOKING FOR ">" and "2>", CURRENTLY THIS WORKS FINE
// look for output redirection FROM previous while loop onwards
int out = 0;
if (strcmp(iterator, ">") == 0) {
// stdout
out = STDOUT_FILENO;
} else if (strcmp(iterator, "2>") == 0) {
// stderr
out = STDERR_FILENO;
}
if (out != 0) {
int fd = open(tokens[index + 1], O_WRONLY | O_TRUNC | O_CREAT, 0777);
dup2(fd, out);
tokens[index] = NULL;
close(fd);
}
index++;
iterator = tokens[index];
}
int value = execv(cmd, tokens); // <----- EXEC IS HERE!!
if (value == -1) {
exit(errno);
}
exit(0);
} else {
int status;
if (requireWait == 1) {
// wait for process to finish
process->pid = childPid;
wait(&status);
process->running = 0;
process->status = status;
if (status != 0) {
printf("%s failed", cmd);
}
} else {
process->pid = childPid;
printf("Child[%d] in background\n", childPid);
// no return should be expected
status = 0;
}
return status;
}
}
The idea is to simulate linux redirection using < and >
tokens is the array of strings provided into the shell.
Example call to write hello to "a.txt": /bin/echo hello > ./a.txt
The problem
It does not work for redirecting in, i.e "/bin/echo < ./a.txt" would echo as if there was no arguments passed in, which is an empty line. "/bin/sleep < ./a.txt" would say no arguments passed in when the file is not empty.
The file a.txt is created using this program. So full example would be
/bin/echo hellooooo > ./a.txt
/bin/echo < ./a.txt
in which the first command successfully creates and writes a.txt, but the second command produces only an empty line
How can you help
Assume that tokens is correct, and that the filename exists, why doesn't the execv() call take in input from the filename given that I redirected it????
Thank you for reading this!!
As I noted in a comment, the echo
command does not read standard input, so you won't be able to tell whether your input redirection was successful with echo
(or with sleep
).
Use a command which does read standard input — cat
is the easiest example, but tr
and sed
could be sensible alternatives.