473 lines
10 KiB
C
473 lines
10 KiB
C
#include <print.h>
|
|
#include <syscall.h>
|
|
#include <launcher.h>
|
|
#include <defs.h>
|
|
#include <bug.h>
|
|
#include <fs_defs.h>
|
|
#include <ipc.h>
|
|
#include <string.h>
|
|
#include <proc.h>
|
|
#include "malloc.h"
|
|
|
|
#define SERVER_READY_FLAG(vaddr) (*(int *)(vaddr))
|
|
#define SERVER_EXIT_FLAG(vaddr) (*(int *)((u64)vaddr+ 4))
|
|
|
|
extern ipc_struct_t *tmpfs_ipc_struct;
|
|
static ipc_struct_t ipc_struct;
|
|
static int tmpfs_scan_pmo_cap;
|
|
static int tmpfs_read_pmo_cap;
|
|
|
|
/* fs_server_cap in current process; can be copied to others */
|
|
int fs_server_cap;
|
|
|
|
#define BUFLEN 4096
|
|
|
|
static int do_complement(char *buf, char *complement, int complement_time)
|
|
{
|
|
int r = -1;
|
|
// TODO: your code here
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
extern char getch();
|
|
|
|
// read a command from stdin leading by `prompt`
|
|
// put the commond in `buf` and return `buf`
|
|
// What you typed should be displayed on the screen
|
|
char *readline(const char *prompt)
|
|
{
|
|
static char buf[BUFLEN];
|
|
|
|
int i = 0, j = 0;
|
|
signed char c = 0;
|
|
int ret = 0;
|
|
char complement[BUFLEN];
|
|
int complement_time = 0;
|
|
|
|
if (prompt != NULL) {
|
|
printf("%s", prompt);
|
|
}
|
|
|
|
while (1) {
|
|
c = getch();
|
|
if (c < 0)
|
|
return NULL;
|
|
if (c == '\r') {
|
|
// 回车
|
|
usys_putc('\n');
|
|
break;
|
|
} else if (c == '\b' || c == 127) {
|
|
// 退格
|
|
if (i > 0) {
|
|
i--;
|
|
usys_putc('\b');
|
|
usys_putc(' ');
|
|
usys_putc('\b');
|
|
}
|
|
continue;
|
|
} else {
|
|
usys_putc(c);
|
|
}
|
|
buf[i++] = c;
|
|
}
|
|
buf[i] = '\0';
|
|
return buf;
|
|
}
|
|
|
|
int do_cd(char *cmdline)
|
|
{
|
|
cmdline += 2;
|
|
while (*cmdline == ' ')
|
|
cmdline++;
|
|
if (*cmdline == '\0')
|
|
return 0;
|
|
if (*cmdline != '/') {
|
|
}
|
|
printf("Build-in command cd %s: Not implemented!\n", cmdline);
|
|
return 0;
|
|
}
|
|
|
|
int do_top()
|
|
{
|
|
usys_top();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 转为绝对路径
|
|
*/
|
|
void path_to_absolute(char *path) {
|
|
char pathbuf[BUFLEN];
|
|
strcpy(pathbuf + 1, path);
|
|
pathbuf[0] = '/';
|
|
strcpy(path, pathbuf);
|
|
}
|
|
|
|
/**
|
|
* 路径连接
|
|
*/
|
|
void path_append(char *path, char *sub) {
|
|
size_t path_len = strlen(path);
|
|
// path 末尾应该有 '/'
|
|
if (path[path_len - 1] == '/') {
|
|
path += path_len;
|
|
} else {
|
|
path[path_len] = '/';
|
|
path += path_len + 1;
|
|
}
|
|
// sub 之前没有 '/'
|
|
while (*sub == '/') sub++;
|
|
// 连接路径
|
|
strcpy(path, sub);
|
|
}
|
|
|
|
/**
|
|
* 扫描目录
|
|
*/
|
|
int fs_scan(char *path)
|
|
{
|
|
int count = 4096/2;
|
|
struct fs_request fr;
|
|
int ret;
|
|
|
|
// 拼接请求
|
|
fr.req = FS_REQ_SCAN;
|
|
fr.buff = (char *) TMPFS_SCAN_BUF_VADDR;
|
|
strcpy(fr.path, path);
|
|
fr.offset = 0;
|
|
fr.count = count;
|
|
|
|
// 发送
|
|
printf("Send ls: %s\n", path);
|
|
ipc_msg_t *ipc_msg = ipc_create_msg(tmpfs_ipc_struct, sizeof(fr), 1);
|
|
ipc_set_msg_data(ipc_msg, (void *)&fr, 0, sizeof(fr));
|
|
ipc_set_msg_cap(ipc_msg, 0, tmpfs_scan_pmo_cap);
|
|
ret = ipc_call(tmpfs_ipc_struct, ipc_msg);
|
|
printf("Return ls: %d\n", ret);
|
|
ipc_destroy_msg(ipc_msg);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* 获得文件大小
|
|
*/
|
|
int fs_get_size(char *path)
|
|
{
|
|
struct fs_request fr;
|
|
int ret;
|
|
|
|
// 拼接请求
|
|
fr.req = FS_REQ_GET_SIZE;
|
|
strcpy(fr.path, path);
|
|
|
|
// 发送
|
|
ipc_msg_t *ipc_msg = ipc_create_msg(tmpfs_ipc_struct, sizeof(fr), 1);
|
|
ipc_set_msg_data(ipc_msg, (void *)&fr, 0, sizeof(fr));
|
|
ipc_set_msg_cap(ipc_msg, 0, tmpfs_scan_pmo_cap);
|
|
ret = ipc_call(tmpfs_ipc_struct, ipc_msg);
|
|
ipc_destroy_msg(ipc_msg);
|
|
return ret;
|
|
}
|
|
|
|
int fs_read(char *path, off_t offset, ssize_t count) {
|
|
struct fs_request fr;
|
|
int ret;
|
|
|
|
fail_cond(count > PAGE_SIZE,
|
|
"read size should smaller than %d, now %d", PAGE_SIZE, count);
|
|
|
|
// 拼接请求
|
|
fr.req = FS_REQ_READ;
|
|
fr.buff = (char *) TMPFS_READ_BUF_VADDR;
|
|
strcpy(fr.path, path);
|
|
fr.offset = offset;
|
|
fr.count = count;
|
|
|
|
// 发送
|
|
ipc_msg_t *ipc_msg = ipc_create_msg(tmpfs_ipc_struct, sizeof(fr), 1);
|
|
ipc_set_msg_data(ipc_msg, (void *)&fr, 0, sizeof(fr));
|
|
ipc_set_msg_cap(ipc_msg, 0, tmpfs_read_pmo_cap);
|
|
ret = ipc_call(tmpfs_ipc_struct, ipc_msg);
|
|
ipc_destroy_msg(ipc_msg);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* 读入文件并返回长度
|
|
*/
|
|
int fs_read_all(char *path, void **ret_buf)
|
|
{
|
|
int ret;
|
|
|
|
// 获得文件长度
|
|
int size = fs_get_size(path);
|
|
if (size < 0) {
|
|
return size;
|
|
}
|
|
|
|
// 映射读文件区
|
|
ret = usys_map_pmo(SELF_CAP,
|
|
tmpfs_read_pmo_cap,
|
|
TMPFS_READ_BUF_VADDR, VM_READ | VM_WRITE);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
// 申请缓冲
|
|
unsigned char *buf = malloc(size);
|
|
if (!buf) {
|
|
return -1;
|
|
}
|
|
*ret_buf = buf;
|
|
|
|
// 读入文件
|
|
int pos = 0;
|
|
while (size - pos > 0) {
|
|
int cur = fs_read(path, pos, PAGE_SIZE);
|
|
if (cur < 0) {
|
|
return cur;
|
|
}
|
|
memcpy(buf, (const void *) TMPFS_READ_BUF_VADDR, cur);
|
|
pos += cur;
|
|
buf += cur;
|
|
}
|
|
|
|
// 释放
|
|
usys_unmap_pmo(SELF_CAP, tmpfs_read_pmo_cap, TMPFS_READ_BUF_VADDR);
|
|
|
|
return size;
|
|
}
|
|
|
|
int do_ls(char *cmdline, bool detail)
|
|
{
|
|
char pathbuf[BUFLEN];
|
|
char fpathbuf[BUFLEN];
|
|
int ret;
|
|
|
|
pathbuf[0] = '\0';
|
|
cmdline += 2;
|
|
while (*cmdline == ' ')
|
|
cmdline++;
|
|
// 路径格式化
|
|
strcat(pathbuf, cmdline);
|
|
path_to_absolute(pathbuf);
|
|
// 请求 fs
|
|
ret = fs_scan(pathbuf);
|
|
if (ret >= 0) {
|
|
char *print_ptr;
|
|
struct dirent *dirat;
|
|
print_ptr = (char *) TMPFS_SCAN_BUF_VADDR;
|
|
|
|
for (int i = 0; i < ret; i++) {
|
|
dirat = (struct dirent *) print_ptr;
|
|
if (detail) {
|
|
// 文件类型
|
|
char type = 'f';
|
|
if (dirat->d_type == 2) {
|
|
type = 'd'; // 目录
|
|
}
|
|
// 文件大小
|
|
strcpy(fpathbuf, pathbuf);
|
|
path_append(fpathbuf, dirat->d_name);
|
|
int size = fs_get_size(fpathbuf);
|
|
// 输出
|
|
printf("%c %10d %s\n", type, size, dirat->d_name);
|
|
} else {
|
|
printf("%s\n", dirat->d_name);
|
|
}
|
|
print_ptr += dirat->d_reclen;
|
|
}
|
|
} else {
|
|
printf("ls returns code %d\n", ret);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int do_cat(char *cmdline)
|
|
{
|
|
char pathbuf[BUFLEN];
|
|
|
|
pathbuf[0] = '\0';
|
|
cmdline += 3;
|
|
while (*cmdline == ' ')
|
|
cmdline++;
|
|
// 路径格式化
|
|
strcat(pathbuf, cmdline);
|
|
path_to_absolute(pathbuf);
|
|
// 读入文件
|
|
char *buf;
|
|
int ret = fs_read_all(pathbuf, (void **) &buf);
|
|
if (ret < 0) {
|
|
printf("cannot cat file, code %d\n", ret);
|
|
return ret;
|
|
}
|
|
// 打印
|
|
for (int i = 0; i < ret; i++) {
|
|
usys_putc(buf[i]);
|
|
}
|
|
free(buf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int do_echo(char *cmdline)
|
|
{
|
|
cmdline += 4;
|
|
while (*cmdline == ' ')
|
|
cmdline++;
|
|
printf("%s", cmdline);
|
|
return 0;
|
|
}
|
|
|
|
void do_clear(void)
|
|
{
|
|
usys_putc(12);
|
|
usys_putc(27);
|
|
usys_putc('[');
|
|
usys_putc('2');
|
|
usys_putc('J');
|
|
}
|
|
|
|
int builtin_cmd(char *cmdline)
|
|
{
|
|
int ret, i;
|
|
char cmd[BUFLEN];
|
|
for (i = 0; cmdline[i] != ' ' && cmdline[i] != '\0'; i++)
|
|
cmd[i] = cmdline[i];
|
|
cmd[i] = '\0';
|
|
if (!strcmp(cmd, "quit") || !strcmp(cmd, "exit"))
|
|
usys_exit(0);
|
|
if (!strcmp(cmd, "cd")) {
|
|
ret = do_cd(cmdline);
|
|
return !ret ? 1 : -1;
|
|
}
|
|
if (!strcmp(cmd, "ls")) {
|
|
ret = do_ls(cmdline, false);
|
|
return !ret ? 1 : -1;
|
|
}
|
|
if (!strcmp(cmd, "ll")) {
|
|
ret = do_ls(cmdline, true);
|
|
return !ret ? 1 : -1;
|
|
}
|
|
if (!strcmp(cmd, "echo")) {
|
|
ret = do_echo(cmdline);
|
|
return !ret ? 1 : -1;
|
|
}
|
|
if (!strcmp(cmd, "cat")) {
|
|
ret = do_cat(cmdline);
|
|
return !ret ? 1 : -1;
|
|
}
|
|
if (!strcmp(cmd, "clear")) {
|
|
do_clear();
|
|
return 1;
|
|
}
|
|
if (!strcmp(cmd, "top")) {
|
|
ret = do_top();
|
|
return !ret ? 1 : -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int run_cmd(char *cmdline)
|
|
{
|
|
char pathbuf[BUFLEN];
|
|
struct user_elf user_elf;
|
|
int ret;
|
|
int caps[1];
|
|
|
|
pathbuf[0] = '\0';
|
|
while (*cmdline == ' ')
|
|
cmdline++;
|
|
if (*cmdline == '\0') {
|
|
return -1;
|
|
} else if (*cmdline != '/') {
|
|
strcpy(pathbuf, "/");
|
|
}
|
|
strcat(pathbuf, cmdline);
|
|
|
|
ret = readelf_from_fs(pathbuf, &user_elf);
|
|
if (ret < 0) {
|
|
printf("[Shell] No such binary\n");
|
|
return ret;
|
|
}
|
|
|
|
caps[0] = fs_server_cap;
|
|
return launch_process_with_pmos_caps(&user_elf, NULL, NULL,
|
|
NULL, 0, caps, 1, 0);
|
|
}
|
|
|
|
static int
|
|
run_cmd_from_kernel_cpio(const char *filename, int *new_thread_cap,
|
|
struct pmo_map_request *pmo_map_reqs,
|
|
int nr_pmo_map_reqs)
|
|
{
|
|
struct user_elf user_elf;
|
|
int ret;
|
|
|
|
ret = readelf_from_kernel_cpio(filename, &user_elf);
|
|
if (ret < 0) {
|
|
printf("[Shell] No such binary in kernel cpio\n");
|
|
return ret;
|
|
}
|
|
return launch_process_with_pmos_caps(&user_elf, NULL, new_thread_cap,
|
|
pmo_map_reqs, nr_pmo_map_reqs,
|
|
NULL, 0, 0);
|
|
}
|
|
|
|
void boot_fs(void)
|
|
{
|
|
int ret = 0;
|
|
int info_pmo_cap;
|
|
int tmpfs_main_thread_cap;
|
|
struct pmo_map_request pmo_map_requests[1];
|
|
|
|
/* create a new process */
|
|
printf("Booting fs...\n");
|
|
/* prepare the info_page (transfer init info) for the new process */
|
|
info_pmo_cap = usys_create_pmo(PAGE_SIZE, PMO_DATA);
|
|
fail_cond(info_pmo_cap < 0, "usys_create_ret ret %d\n", info_pmo_cap);
|
|
|
|
ret = usys_map_pmo(SELF_CAP,
|
|
info_pmo_cap, TMPFS_INFO_VADDR, VM_READ | VM_WRITE);
|
|
fail_cond(ret < 0, "usys_map_pmo ret %d\n", ret);
|
|
|
|
SERVER_READY_FLAG(TMPFS_INFO_VADDR) = 0;
|
|
SERVER_EXIT_FLAG(TMPFS_INFO_VADDR) = 0;
|
|
|
|
/* We also pass the info page to the new process */
|
|
pmo_map_requests[0].pmo_cap = info_pmo_cap;
|
|
pmo_map_requests[0].addr = TMPFS_INFO_VADDR;
|
|
pmo_map_requests[0].perm = VM_READ | VM_WRITE;
|
|
ret = run_cmd_from_kernel_cpio("/tmpfs.srv", &tmpfs_main_thread_cap,
|
|
pmo_map_requests, 1);
|
|
fail_cond(ret != 0, "create_process returns %d\n", ret);
|
|
|
|
fs_server_cap = tmpfs_main_thread_cap;
|
|
|
|
while (SERVER_READY_FLAG(TMPFS_INFO_VADDR) != 1)
|
|
usys_yield();
|
|
|
|
/* register IPC client */
|
|
tmpfs_ipc_struct = &ipc_struct;
|
|
ret = ipc_register_client(tmpfs_main_thread_cap, tmpfs_ipc_struct);
|
|
fail_cond(ret < 0, "ipc_register_client failed\n");
|
|
|
|
tmpfs_scan_pmo_cap = usys_create_pmo(PAGE_SIZE, PMO_DATA);
|
|
fail_cond(tmpfs_scan_pmo_cap < 0, "usys create_ret ret %d\n",
|
|
tmpfs_scan_pmo_cap);
|
|
|
|
ret = usys_map_pmo(SELF_CAP,
|
|
tmpfs_scan_pmo_cap,
|
|
TMPFS_SCAN_BUF_VADDR, VM_READ | VM_WRITE);
|
|
fail_cond(ret < 0, "usys_map_pmo ret %d\n", ret);
|
|
|
|
// 创建读文件 pmo
|
|
tmpfs_read_pmo_cap = usys_create_pmo(PAGE_SIZE, PMO_DATA);
|
|
fail_cond(tmpfs_read_pmo_cap < 0, "usys create_ret ret %d\n",
|
|
tmpfs_read_pmo_cap);
|
|
|
|
printf("fs is UP.\n");
|
|
}
|