Reputation:
I wrote this simple shell so far. But I got some trouble with my shell. For example, when I try to open a pdf file via the command "evince pdffile.pdf", the actual pdfile does not get opened. The pdf viewer runs but the actual file with the whole content never appears. Or another example is the command "ls -l". I don't get the files and folders listed as it should be, but "ls" is working. Another example is gedit, and so on. Also, I should mention. I am not using "system()", because system() would do everything and I would not have something to do. Instead, I am using "execvp()". Here is the code. I hope, you may find the problem, because I have no clue what the problem is causing.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
#define MAX_LENGTH 1024
#define DELIMS " \t\r\n"
void exec_cmd (char *buf);
int main() {
char line[MAX_LENGTH];
char * cmd;
char curDir[100];
while (1) {
getcwd(curDir, 100);
printf("%s@%s$ ", getlogin(), curDir);
if (!fgets(line, MAX_LENGTH, stdin))
break;
if ((cmd = strtok(line, DELIMS))) {
errno = 0;
if (strcmp(cmd, "cd") == 0) {
char *arg = strtok(0, DELIMS);
if (!arg)
fprintf(stderr, "cd: argument is missing.\n");
else chdir(arg);
} else if (strcmp(cmd, "exit") == 0) {
exit(0);
} else exec_cmd(line);
if (errno) perror("Error. Command failure");
}
}
return 0;
}
void exec_cmd (char *buf) {
int status = 0;
char *argv[MAX_LENGTH];
int j=0;
pid_t pid;
argv[j++] = strtok (buf, DELIMS);
while (j<MAX_LENGTH && (argv[j++]=strtok(NULL,DELIMS))!=NULL); // EDIT: " " replaced by DELIMS
pid = fork();
if(pid < 0) {
printf("Error occured");
exit(-1);
} else if(pid == 0) {
execvp(argv[0],argv);
} else if( pid > 0) {
wait(&status);
}
}
Upvotes: 0
Views: 489
Reputation: 881793
Check the arguments (eg, print them out, each enclosed in []
) before you call fork/exec
, there's a good chance they're not what you think.
While your first call to strtok
uses your full delimiter set, subsequent calls do not. They instead just use a space. That means that the final argument will probably have the newline left on the string by fgets
. I'd be using the same delimiter set in the subsequent calls. In other words:
while (j<MAX_LENGTH && (argv[j++]=strtok(NULL,DELIMS))!=NULL);
Having entered your code and done that debugging, I find that the string passed to the function only ever has one word in it. It turns out that's because of the strtok
that happened in main
to check for cd/exit
. That left the nul character at the end of the first word, an effect inherent in the way strtok
works.
Probably the quickest fix is to make a copy of the string before the initial strtok
in main, then pass that to the function. In other words, use strdup
(and, later, free
). Now glibc has a strdup
but, if you're in an environment that doesn't (it's POSIX rather than ISO), see here.
Upvotes: 1
Reputation: 120001
The bug is in main()
.
You are using strtok
to find the first word of the line. But strtok
modifies the line, making it actually contain just that word (a NUL terminator is written to the string right after it).
You need to make a copy of the line, or use strtok_s
, or do something else to avoid modifying the line.
Upvotes: 1