Compare commits
No commits in common. "c68d040484c89ba121ebdb88ab44b47c7a65999c" and "e58aa361c86248be68b0f98b13ac42e8cc9a755b" have entirely different histories.
c68d040484
...
e58aa361c8
179
apps/src/sh.c
179
apps/src/sh.c
@ -16,8 +16,7 @@ typedef struct
|
|||||||
char* buffer;
|
char* buffer;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
int interactive;
|
} command;
|
||||||
} command_t;
|
|
||||||
|
|
||||||
char** split_command_into_argv(const char* cmd)
|
char** split_command_into_argv(const char* cmd)
|
||||||
{
|
{
|
||||||
@ -79,19 +78,30 @@ void shell_execvp(char* pathname, char* const argv[])
|
|||||||
|
|
||||||
void show_prompt()
|
void show_prompt()
|
||||||
{
|
{
|
||||||
|
if (!username)
|
||||||
|
{
|
||||||
|
struct passwd* user = getpwuid(getuid());
|
||||||
|
if (!user)
|
||||||
|
{
|
||||||
|
if (errno) perror("getpwuid");
|
||||||
|
username = "??";
|
||||||
|
}
|
||||||
|
else { username = user->pw_name; }
|
||||||
|
atexit(endpwent);
|
||||||
|
}
|
||||||
if (WEXITSTATUS(status)) { printf("%d [%s]> ", WEXITSTATUS(status), username); }
|
if (WEXITSTATUS(status)) { printf("%d [%s]> ", WEXITSTATUS(status), username); }
|
||||||
else
|
else
|
||||||
printf("[%s]> ", username);
|
printf("[%s]> ", username);
|
||||||
}
|
}
|
||||||
|
|
||||||
int command_matches(command_t* cmd, const char* string)
|
int command_matches(command* cmd, const char* string)
|
||||||
{
|
{
|
||||||
if (cmd->size <= strlen(string)) // cmd->size includes null terminator
|
if (cmd->size <= strlen(string)) // cmd->size includes null terminator
|
||||||
return 0;
|
return 0;
|
||||||
return strncmp(cmd->buffer, string, strlen(string)) == 0;
|
return strncmp(cmd->buffer, string, strlen(string)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int command_matches_exactly(command_t* cmd, const char* string)
|
int command_matches_exactly(command* cmd, const char* string)
|
||||||
{
|
{
|
||||||
if (cmd->size <= strlen(string)) // cmd->size includes null terminator
|
if (cmd->size <= strlen(string)) // cmd->size includes null terminator
|
||||||
return 0;
|
return 0;
|
||||||
@ -99,7 +109,7 @@ int command_matches_exactly(command_t* cmd, const char* string)
|
|||||||
return strncmp(cmd->buffer, string, strlen(string)) == 0;
|
return strncmp(cmd->buffer, string, strlen(string)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int command_match_builtins(command_t* cmd)
|
int command_match_builtins(command* cmd)
|
||||||
{
|
{
|
||||||
if (command_matches(cmd, "exit ")) { exit(atoi(cmd->buffer + 5)); }
|
if (command_matches(cmd, "exit ")) { exit(atoi(cmd->buffer + 5)); }
|
||||||
if (command_matches_exactly(cmd, "exit")) { exit(0); }
|
if (command_matches_exactly(cmd, "exit")) { exit(0); }
|
||||||
@ -116,7 +126,7 @@ int command_match_builtins(command_t* cmd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_expand(command_t* cmd, long new_capacity)
|
void command_expand(command* cmd, long new_capacity)
|
||||||
{
|
{
|
||||||
char* buffer = realloc(cmd->buffer, new_capacity);
|
char* buffer = realloc(cmd->buffer, new_capacity);
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
@ -128,46 +138,38 @@ void command_expand(command_t* cmd, long new_capacity)
|
|||||||
cmd->capacity = new_capacity;
|
cmd->capacity = new_capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_push(command_t* cmd, char c)
|
void command_push(command* cmd, char c)
|
||||||
{
|
{
|
||||||
if (cmd->size == cmd->capacity) command_expand(cmd, cmd->capacity + 8);
|
if (cmd->size == cmd->capacity) command_expand(cmd, cmd->capacity + 8);
|
||||||
cmd->buffer[cmd->size] = c;
|
cmd->buffer[cmd->size] = c;
|
||||||
cmd->size++;
|
cmd->size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_pop(command_t* cmd)
|
void command_pop(command* cmd)
|
||||||
{
|
{
|
||||||
cmd->size--;
|
cmd->size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_init(command_t* cmd)
|
void command_init(command* cmd)
|
||||||
{
|
{
|
||||||
cmd->buffer = malloc(5);
|
cmd->buffer = malloc(5);
|
||||||
cmd->capacity = 5;
|
cmd->capacity = 5;
|
||||||
cmd->size = 0;
|
cmd->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_clear(command_t* cmd)
|
void command_clear(command* cmd)
|
||||||
{
|
{
|
||||||
free(cmd->buffer);
|
free(cmd->buffer);
|
||||||
return command_init(cmd);
|
return command_init(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_execute_command(const char* command)
|
void command_execute(command* cmd)
|
||||||
{
|
|
||||||
char** argv = split_command_into_argv(command);
|
|
||||||
shell_execvp(argv[0], argv);
|
|
||||||
perror(argv[0]);
|
|
||||||
exit(127);
|
|
||||||
}
|
|
||||||
|
|
||||||
void command_execute(command_t* cmd)
|
|
||||||
{
|
{
|
||||||
command_push(cmd, '\0');
|
command_push(cmd, '\0');
|
||||||
if (command_match_builtins(cmd))
|
if (command_match_builtins(cmd))
|
||||||
{
|
{
|
||||||
command_clear(cmd);
|
command_clear(cmd);
|
||||||
if (cmd->interactive) show_prompt();
|
show_prompt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pid_t child = fork();
|
pid_t child = fork();
|
||||||
@ -175,54 +177,60 @@ void command_execute(command_t* cmd)
|
|||||||
{
|
{
|
||||||
perror("fork");
|
perror("fork");
|
||||||
command_clear(cmd);
|
command_clear(cmd);
|
||||||
if (cmd->interactive) show_prompt();
|
show_prompt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (child == 0) process_execute_command(cmd->buffer);
|
if (child == 0)
|
||||||
|
{
|
||||||
|
char** argv = split_command_into_argv(cmd->buffer);
|
||||||
|
shell_execvp(argv[0], argv);
|
||||||
|
perror(argv[0]);
|
||||||
|
exit(127);
|
||||||
|
}
|
||||||
pid_t result = waitpid(child, &status, 0);
|
pid_t result = waitpid(child, &status, 0);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
{
|
{
|
||||||
perror("waitpid");
|
perror("waitpid");
|
||||||
command_clear(cmd);
|
command_clear(cmd);
|
||||||
if (cmd->interactive) show_prompt();
|
show_prompt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int exit_status = WEXITSTATUS(status);
|
int exit_status = WEXITSTATUS(status);
|
||||||
if (exit_status == -2 || exit_status == -3) printf("(PID %ld) Segmentation fault\n", result);
|
if (exit_status == -2 || exit_status == -3) printf("(PID %ld) Segmentation fault\n", result);
|
||||||
if (exit_status == -1) printf("(PID %ld) Aborted\n", result);
|
if (exit_status == -1) printf("(PID %ld) Aborted\n", result);
|
||||||
command_clear(cmd);
|
command_clear(cmd);
|
||||||
if (cmd->interactive) show_prompt();
|
show_prompt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_concat_char(command_t* cmd, char c)
|
void command_concat_char(command* cmd, char c)
|
||||||
{
|
{
|
||||||
if (c == '\b')
|
if (c == '\b')
|
||||||
{
|
{
|
||||||
if (cmd->size != 0)
|
if (cmd->size != 0)
|
||||||
{
|
{
|
||||||
if (cmd->interactive) putchar(c);
|
putchar(c);
|
||||||
command_pop(cmd);
|
command_pop(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (c == '\n')
|
else if (c == '\n')
|
||||||
{
|
{
|
||||||
if (cmd->interactive) putchar(c);
|
putchar(c);
|
||||||
if (cmd->size == 0)
|
if (cmd->size == 0)
|
||||||
{
|
{
|
||||||
status = 0;
|
status = 0;
|
||||||
if (cmd->interactive) show_prompt();
|
show_prompt();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
command_execute(cmd);
|
command_execute(cmd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (cmd->interactive) putchar(c);
|
putchar(c);
|
||||||
command_push(cmd, c);
|
command_push(cmd, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_concat(command_t* cmd, const char* str)
|
void command_concat(command* cmd, const char* str)
|
||||||
{
|
{
|
||||||
while (*str)
|
while (*str)
|
||||||
{
|
{
|
||||||
@ -231,15 +239,13 @@ void command_concat(command_t* cmd, const char* str)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void shell_interactive()
|
int main()
|
||||||
{
|
{
|
||||||
show_prompt();
|
show_prompt();
|
||||||
|
|
||||||
command_t shell_command;
|
command shell_command;
|
||||||
command_init(&shell_command);
|
command_init(&shell_command);
|
||||||
|
|
||||||
shell_command.interactive = 1;
|
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
int c = getchar();
|
int c = getchar();
|
||||||
@ -248,112 +254,11 @@ void shell_interactive()
|
|||||||
if (ferror(stdin))
|
if (ferror(stdin))
|
||||||
{
|
{
|
||||||
perror("getchar");
|
perror("getchar");
|
||||||
exit(EXIT_FAILURE);
|
return 1;
|
||||||
}
|
}
|
||||||
if (feof(stdin)) exit(EXIT_SUCCESS);
|
if (feof(stdin)) return 0;
|
||||||
assert(false); // we should never get here
|
assert(false); // we should never get here
|
||||||
}
|
}
|
||||||
command_concat_char(&shell_command, (char)c);
|
command_concat_char(&shell_command, (char)c);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void shell_read_from_file(const char* pathname)
|
|
||||||
{
|
|
||||||
FILE* fp = fopen(pathname, "r");
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
perror("sh");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
command_t file_command;
|
|
||||||
command_init(&file_command);
|
|
||||||
|
|
||||||
file_command.interactive = 0;
|
|
||||||
|
|
||||||
char buffer[BUFSIZ];
|
|
||||||
while (fgets(buffer, BUFSIZ, fp))
|
|
||||||
{
|
|
||||||
command_concat(&file_command, buffer);
|
|
||||||
if (feof(fp)) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_command.size > 0) // last line of file, does not end with newline
|
|
||||||
{
|
|
||||||
command_execute(&file_command);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void shell_execute_command(const char* command)
|
|
||||||
{
|
|
||||||
command_t cmd;
|
|
||||||
cmd.buffer = strdup(command);
|
|
||||||
cmd.size = strlen(command) + 1;
|
|
||||||
if (command_match_builtins(&cmd)) return;
|
|
||||||
command_clear(&cmd);
|
|
||||||
process_execute_command(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fetch_username()
|
|
||||||
{
|
|
||||||
struct passwd* user = getpwuid(getuid());
|
|
||||||
if (!user)
|
|
||||||
{
|
|
||||||
perror("getpwuid");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
username = user->pw_name;
|
|
||||||
endpwent();
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
fetch_username();
|
|
||||||
|
|
||||||
if (argc == 1) shell_interactive();
|
|
||||||
else if (argc == 2)
|
|
||||||
{
|
|
||||||
if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version"))
|
|
||||||
{
|
|
||||||
puts("Luna sh version 0.1"); // FIXME: Store the version somewhere, or use the kernel's version.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
|
|
||||||
{
|
|
||||||
printf("To use interactively: %s\n", argv[0]);
|
|
||||||
printf("To run a script: %s [script-name]\n", argv[0]);
|
|
||||||
printf("To get help: %s --help\n", argv[0]);
|
|
||||||
printf("To show the version: %s --version\n", argv[0]);
|
|
||||||
printf("To run a command: %s -c [command]\n", argv[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(argv[1], "-c") || !strcmp(argv[1], "--command"))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Usage: %s %s [command]\n", argv[0], argv[1]);
|
|
||||||
fprintf(stderr, "Use the --help flag for more help.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
shell_read_from_file(argv[1]);
|
|
||||||
}
|
|
||||||
else if (argc == 3)
|
|
||||||
{
|
|
||||||
if (!strcmp(argv[1], "-c") || !strcmp(argv[1], "--command")) shell_execute_command(argv[2]);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s: too many arguments\n", argv[0]);
|
|
||||||
fprintf(stderr, "Use the --help flag for more help.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s: too many arguments\n", argv[0]);
|
|
||||||
fprintf(stderr, "Use the --help flag for more help.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -74,7 +74,11 @@ bool Task::has_died()
|
|||||||
|
|
||||||
void Task::resume_read()
|
void Task::resume_read()
|
||||||
{
|
{
|
||||||
|
VMM::switch_back_to_kernel_address_space();
|
||||||
|
VMM::apply_address_space();
|
||||||
|
VMM::switch_to_previous_user_address_space();
|
||||||
regs.rax = files[blocking_read_info.fd].read(blocking_read_info.size, blocking_read_info.buf);
|
regs.rax = files[blocking_read_info.fd].read(blocking_read_info.size, blocking_read_info.buf);
|
||||||
|
VMM::apply_address_space();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Task::is_read_still_blocking()
|
bool Task::is_read_still_blocking()
|
||||||
@ -84,9 +88,6 @@ bool Task::is_read_still_blocking()
|
|||||||
|
|
||||||
void Task::resume()
|
void Task::resume()
|
||||||
{
|
{
|
||||||
VMM::switch_back_to_kernel_address_space();
|
|
||||||
VMM::apply_address_space();
|
|
||||||
VMM::switch_to_previous_user_address_space();
|
|
||||||
switch (block_reason)
|
switch (block_reason)
|
||||||
{
|
{
|
||||||
case BlockReason::None: ASSERT(false);
|
case BlockReason::None: ASSERT(false);
|
||||||
@ -95,7 +96,6 @@ void Task::resume()
|
|||||||
|
|
||||||
default: ASSERT(false);
|
default: ASSERT(false);
|
||||||
}
|
}
|
||||||
VMM::apply_address_space();
|
|
||||||
block_reason = BlockReason::None;
|
block_reason = BlockReason::None;
|
||||||
state = Running;
|
state = Running;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user