2022-10-22 09:38:16 +00:00
|
|
|
#include <assert.h>
|
2022-10-20 17:12:17 +00:00
|
|
|
#include <errno.h>
|
2022-10-19 17:42:05 +00:00
|
|
|
#include <luna.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2022-10-19 18:34:10 +00:00
|
|
|
#include <string.h>
|
2022-10-19 17:42:05 +00:00
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2022-10-20 06:21:18 +00:00
|
|
|
static int status = 0;
|
2022-10-19 18:16:21 +00:00
|
|
|
|
2022-10-19 17:42:05 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
char* buffer;
|
2022-10-19 18:34:10 +00:00
|
|
|
size_t size;
|
|
|
|
size_t capacity;
|
2022-10-19 17:42:05 +00:00
|
|
|
} command;
|
|
|
|
|
2022-10-26 17:36:09 +00:00
|
|
|
char* shell_concat_path(const char* dirname, const char* basename)
|
|
|
|
{
|
|
|
|
char* buf = malloc(strlen(basename) + strlen(dirname) + 6);
|
|
|
|
strlcpy(buf, dirname, strlen(dirname) + 1);
|
|
|
|
strncat(buf, basename, strlen(basename));
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void shell_execvp(char* pathname, char* const argv[])
|
|
|
|
{
|
|
|
|
char* new_path;
|
|
|
|
if (access(pathname, F_OK) == 0)
|
|
|
|
{
|
|
|
|
execv(pathname, argv);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (pathname[0] == '/') return; // We do not want to lookup absolute paths
|
|
|
|
new_path = shell_concat_path("/bin/", pathname);
|
|
|
|
if (access(new_path, F_OK) == 0)
|
|
|
|
{
|
|
|
|
execv(new_path, argv);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
free(new_path);
|
|
|
|
new_path = shell_concat_path("/usr/bin/", pathname);
|
|
|
|
execv(new_path, argv);
|
|
|
|
int saved = errno;
|
|
|
|
free(new_path);
|
|
|
|
errno = saved;
|
|
|
|
}
|
|
|
|
|
2022-10-19 17:42:05 +00:00
|
|
|
void show_prompt()
|
|
|
|
{
|
2022-10-22 13:09:09 +00:00
|
|
|
if (WEXITSTATUS(status)) { printf("%d [%ld]> ", WEXITSTATUS(status), getpid()); }
|
2022-10-20 06:21:18 +00:00
|
|
|
else
|
|
|
|
printf("[%ld]> ", getpid());
|
2022-10-19 17:42:05 +00:00
|
|
|
}
|
|
|
|
|
2022-10-19 18:34:10 +00:00
|
|
|
int command_matches(command* cmd, const char* string)
|
|
|
|
{
|
|
|
|
if (cmd->size <= strlen(string)) // cmd->size includes null terminator
|
|
|
|
return 0;
|
|
|
|
return strncmp(cmd->buffer, string, strlen(string)) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int command_matches_exactly(command* cmd, const char* string)
|
|
|
|
{
|
|
|
|
if (cmd->size <= strlen(string)) // cmd->size includes null terminator
|
|
|
|
return 0;
|
|
|
|
if (cmd->size > (strlen(string) + 1)) return 0;
|
|
|
|
return strncmp(cmd->buffer, string, strlen(string)) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int command_match_builtins(command* cmd)
|
|
|
|
{
|
|
|
|
if (command_matches(cmd, "exit ")) { exit(atoi(cmd->buffer + 5)); }
|
|
|
|
if (command_matches_exactly(cmd, "exit")) { exit(0); }
|
|
|
|
if (command_matches_exactly(cmd, "pid"))
|
|
|
|
{
|
|
|
|
printf("pid %ld, ppid %ld\n", getpid(), getppid());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-10-19 17:42:05 +00:00
|
|
|
void command_expand(command* cmd, long new_capacity)
|
|
|
|
{
|
|
|
|
char* buffer = realloc(cmd->buffer, new_capacity);
|
|
|
|
if (!buffer)
|
|
|
|
{
|
|
|
|
perror("realloc");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
cmd->buffer = buffer;
|
|
|
|
cmd->capacity = new_capacity;
|
|
|
|
}
|
|
|
|
|
|
|
|
void command_push(command* cmd, char c)
|
|
|
|
{
|
|
|
|
if (cmd->size == cmd->capacity) command_expand(cmd, cmd->capacity + 8);
|
|
|
|
cmd->buffer[cmd->size] = c;
|
|
|
|
cmd->size++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void command_pop(command* cmd)
|
|
|
|
{
|
|
|
|
cmd->size--;
|
|
|
|
}
|
|
|
|
|
|
|
|
void command_init(command* cmd)
|
|
|
|
{
|
|
|
|
cmd->buffer = malloc(5);
|
|
|
|
cmd->capacity = 5;
|
|
|
|
cmd->size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void command_clear(command* cmd)
|
|
|
|
{
|
|
|
|
free(cmd->buffer);
|
|
|
|
return command_init(cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void command_execute(command* cmd)
|
|
|
|
{
|
|
|
|
command_push(cmd, '\0');
|
2022-10-19 18:34:10 +00:00
|
|
|
if (command_match_builtins(cmd))
|
|
|
|
{
|
|
|
|
command_clear(cmd);
|
|
|
|
show_prompt();
|
|
|
|
return;
|
|
|
|
}
|
2022-10-19 17:42:05 +00:00
|
|
|
pid_t child = fork();
|
|
|
|
if (child < 0)
|
|
|
|
{
|
2022-10-26 15:13:47 +00:00
|
|
|
perror("fork");
|
2022-10-19 17:42:05 +00:00
|
|
|
command_clear(cmd);
|
|
|
|
show_prompt();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (child == 0)
|
|
|
|
{
|
2022-10-26 17:36:09 +00:00
|
|
|
char* argv[] = {cmd->buffer, NULL};
|
|
|
|
shell_execvp(argv[0], argv);
|
2022-10-19 17:42:05 +00:00
|
|
|
perror(cmd->buffer);
|
|
|
|
exit(127);
|
|
|
|
}
|
|
|
|
pid_t result;
|
|
|
|
while ((result = waitpid(child, &status, 0)) == 0) { msleep(20); }
|
|
|
|
if (result < 0)
|
|
|
|
{
|
|
|
|
perror("waitpid");
|
|
|
|
command_clear(cmd);
|
|
|
|
show_prompt();
|
|
|
|
return;
|
|
|
|
}
|
2022-10-19 18:16:21 +00:00
|
|
|
int exit_status = WEXITSTATUS(status);
|
|
|
|
if (exit_status == -2 || exit_status == -3) printf("(PID %ld) Segmentation fault\n", result);
|
2022-10-19 17:42:05 +00:00
|
|
|
command_clear(cmd);
|
|
|
|
show_prompt();
|
|
|
|
}
|
|
|
|
|
2022-10-22 09:38:16 +00:00
|
|
|
void command_concat_char(command* cmd, char c)
|
2022-10-19 17:42:05 +00:00
|
|
|
{
|
2022-10-22 09:38:16 +00:00
|
|
|
if (c == '\b')
|
2022-10-19 17:42:05 +00:00
|
|
|
{
|
2022-10-22 09:38:16 +00:00
|
|
|
if (cmd->size != 0)
|
2022-10-20 17:32:32 +00:00
|
|
|
{
|
2022-10-22 09:38:16 +00:00
|
|
|
putchar(c);
|
2022-10-20 17:32:32 +00:00
|
|
|
command_pop(cmd);
|
|
|
|
}
|
2022-10-22 09:38:16 +00:00
|
|
|
}
|
|
|
|
else if (c == '\n')
|
|
|
|
{
|
2022-10-22 13:08:27 +00:00
|
|
|
putchar(c);
|
|
|
|
if (cmd->size == 0) show_prompt();
|
2022-10-19 17:42:05 +00:00
|
|
|
else
|
2022-10-22 09:38:16 +00:00
|
|
|
command_execute(cmd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
putchar(c);
|
|
|
|
command_push(cmd, c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void command_concat(command* cmd, const char* str)
|
|
|
|
{
|
|
|
|
while (*str)
|
|
|
|
{
|
|
|
|
command_concat_char(cmd, *str);
|
2022-10-19 17:42:05 +00:00
|
|
|
str++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
show_prompt();
|
|
|
|
|
|
|
|
command shell_command;
|
|
|
|
command_init(&shell_command);
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
2022-10-22 09:38:16 +00:00
|
|
|
int c = getchar();
|
|
|
|
if (c == EOF)
|
2022-10-19 17:42:05 +00:00
|
|
|
{
|
2022-10-22 09:38:16 +00:00
|
|
|
if (ferror(stdin))
|
|
|
|
{
|
|
|
|
perror("getchar");
|
|
|
|
return 1;
|
|
|
|
}
|
2022-10-25 16:58:06 +00:00
|
|
|
if (feof(stdin)) return 0;
|
2022-10-22 09:38:16 +00:00
|
|
|
assert(false); // we should never get here
|
2022-10-19 17:42:05 +00:00
|
|
|
}
|
2022-10-22 09:38:16 +00:00
|
|
|
command_concat_char(&shell_command, (char)c);
|
2022-10-19 17:42:05 +00:00
|
|
|
}
|
|
|
|
}
|