Luna/apps/src/sh.c

194 lines
4.1 KiB
C
Raw Normal View History

#include <assert.h>
#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>
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;
void show_prompt()
{
2022-10-22 13:09:09 +00:00
if (WEXITSTATUS(status)) { printf("%d [%ld]> ", WEXITSTATUS(status), getpid()); }
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)
{
perror(cmd->buffer);
command_clear(cmd);
show_prompt();
return;
}
if (child == 0)
{
if (cmd->buffer[0] != '/' && access(cmd->buffer, F_OK) < 0) // FIXME: Race condition.
{
if (errno == ENOENT)
{ // Try in /bin
char* buf = malloc(cmd->size + 6);
strlcpy(buf, "/bin/", 6);
strncat(buf, cmd->buffer, cmd->size);
execv(buf, NULL);
}
}
else
execv(cmd->buffer, NULL);
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();
}
void command_concat_char(command* cmd, char c)
2022-10-19 17:42:05 +00:00
{
if (c == '\b')
2022-10-19 17:42:05 +00:00
{
if (cmd->size != 0)
{
putchar(c);
command_pop(cmd);
}
}
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
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)
{
int c = getchar();
if (c == EOF)
2022-10-19 17:42:05 +00:00
{
if (ferror(stdin))
{
perror("getchar");
return 1;
}
if (feof(stdin)) { return 0; }
assert(false); // we should never get here
2022-10-19 17:42:05 +00:00
}
command_concat_char(&shell_command, (char)c);
2022-10-19 17:42:05 +00:00
}
}