Been working on a simple shell implementation for a for days. But I have 2 issues:
1.When you run the program and type a command like "/bin/ls -l /usr/include" and then press enter it will execute the command but if you then enter a few new lines the program will still go into execvp() and output "Permission denied", because it goes into the error handling of execvp and that's not supposed to happen. (I tried a few different things to stop it from going into the if() in main but they didn't work.)
2.If you type enter and then enter a command the command won't be executed. (I tried freeing the buff and allocating memory again but that caused more issues.)
So basically it goes in the "if(buff[offset] == '\n')" even if the line is empty when it shouldn't and it doesn't execute a command unless its the first input after starting the program.
Code:
int fd = 0;
const size_t read_size = 1;
size_t size = read_size;
char *buff = malloc(size 1);
size_t offset = 0;
size_t res = 0;
write(STDOUT_FILENO, "$ ", strlen("$ "));
while((res = read(fd, buff offset, read_size)) > 0)
{
if(buff[offset] == '\n')
{
buff[offset] = '\0';
char **result = parse_cmdline(buff); // turn string into array for execvp()
int exec;
int status;
pid_t pid = fork();
if(pid == -1) {/*error handling*/}
else if(pid == 0)
{
if((exec = execvp(result[0], result)) == -1) {/*error handling*/}
}
else
{
waitpid(pid, &status, 0);
}
offset = 0;
free(result[0]);
free(result);
result = NULL;
write(STDOUT_FILENO, "$ ", strlen("$ "));
}
offset = res;
if (offset read_size > size)
{
size *= 2;
buff = realloc(buff, size 1);
}
buff[offset] = '\0';
}
free(buff);
return 0;
UPDATE: Works with commands inputted after the first line, but with an error in every case:
"a.out: malloc.c:2379: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed. Aborted (core dumped)"
Updated code:
if(buff[offset] == '\n')
{
buff[offset] = '\0';
char **result = parse_cmdline(buff);
if(result[0] != NULL)
{
int exec;
int status;
pid_t pid = fork(); // create the child process
if(pid == -1) // check for fork() errors (no memory, etc.)
{
fork_error();
}
else if(pid == 0) // Handle child process
{
if((exec = execvp(result[0], result)) == -1) // run the command itself and check if an error will occur (invalid command, etc.)
{
file_error(result[0]);
}
}
else // Handle parent process
{
waitpid(pid, &status, 0);
}
offset = 0;
free(buff);
size = read_size;
free(result[0]);
free(result);
result = NULL;
}
write(STDOUT_FILENO, "$ ", strlen("$ "));
}
else
{
offset = res;
if (offset read_size > size)
{
size *= 2;
buff = realloc(buff, size 1);
}
buff[offset] = '\0';
}
CodePudding user response:
Your parse_cmdline()
function should test for empty lines, lines with just whote space and comment lines starting with #
and return NULL
is these cases.
The calling code should then test result
for such lines to be ignored.
The calling code should also compare result[0]
with the names of internal commands, such as cd
or chdir
and handle them locally instead of calling fork
and exec
.