I am trying to make a program that uses shell commands for a school project. I am able to compile and run the code without errors, but when I input a command such as ls, noting happens. I think I am missing something with the execvp.
I have been trying to use various configurations of inputs.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <wait.h>
#include <stdlib.h>
#define MAX_LINE 80 /* Maximum length of a command */
int main(void) {
char args[MAX_LINE / 2 + 1]; /* command line arguments */
int should_run = 1; /* Flag to determine when to exit the program */
pid_t pid;
char *myCmd;
char *tokens[40];
pid = fork();
while (should_run) {
printf("osh>");
fflush(stdout);
scanf("%s", myCmd);
int i = 0;
char *token = strtok(myCmd, " ");
while (token != NULL) {
tokens[i] = token;
i++;
token = strtok(NULL, " ");
}
if (pid < 0) {
printf("Fork Failed\n");
//exit(1);
} else
if (pid == 0) {
execvp(tokens[0], tokens);
//exit(1);
} else {
if (strcmp(tokens[i - 1], "&")) {
waitpid(pid, NULL, 0);
}
}
}
return 0;
}
Writing to unallocated memory:
only allocates memory for the pointer. The pointer has an indeterminate value i.e. it may be pointing to anything and any attempt to dereference a pointer with a bad value would result in undefined behaviour.
The subsequent call to
scanf()then invokes undefined behaviour, because no memory was ever allocated for the string.Possible fix:
If no command is ever going to exceed 80 characters, as stated in this comment:
You can allocate an
array[80]ofcharand then pass it toscanf().And to limit input, you could specify a width specifier like so:
Note:
Don't use
scanf(). Usefgets(). Withscanf(), it will only grab the first whitespace separated token (e.g. for input of Hello World,scanf()will only return Hello). — @Craig EsteyThe array of pointers to
execvpshall be null-terminated:Code is missing:
after the
whileloop.Aside: A shell in C - Tutorial and Beej's guide to UNIX Interprocess Communication might help to elaborate on what @John pointed out in his answer.