/** * @file usrcmd.c * @author CuBeatSystems * @author Shinichiro Nakamura * @copyright * =============================================================== * Natural Tiny Shell (NT-Shell) Version 0.3.1 * =============================================================== * Copyright (c) 2010-2016 Shinichiro Nakamura * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include "syssvc/syslog.h" #include "kernel_cfg.h" #include "main.h" #include "rza1.h" #include "ffarch.h" #include "ff.h" #include "usrcmd.h" #include "ntstdio.h" #include "ntshell.h" extern ntstdio_t ntstdio; extern int ntshell_exit; int shell_kill(int pid, int sig) { asm("bkpt #0"); return -1; } int shell_gettimeofday(struct timeval *tv, void *tzvp) { SYSTIM time; if (!tv) return 0; get_tim(&time); tv->tv_sec = time / 1000000; tv->tv_usec = time - (tv->tv_sec * 1000000); return 0; } void put_rc(const char *func, FRESULT rc) { const char *p = "OK\0DISK_ERR\0INT_ERR\0NOT_READY\0NO_FILE\0NO_PATH\0INVALID_NAME\0" "DENIED\0EXIST\0INVALID_OBJECT\0WRITE_PROTECTED\0INVALID_DRIVE\0" "NOT_ENABLED\0NO_FILE_SYSTEM\0MKFS_ABORTED\0TIMEOUT\0LOCKED\0" "NOT_ENOUGH_CORE\0TOO_MANY_OPEN_FILES\0"; FRESULT i; for (i = 0; i != rc && *p; i++) { while (*p++); } ntstdio_printf(&ntstdio, "%s() =>%u FR_%s\n", func, (UINT)rc, p); } void put_drc(const char *func, DRESULT rc) { const char *p = "Successful\0R/W Error\0Write Protected\0Not Ready\0Invalid Parameter\0"; DRESULT i; for (i = 0; i != rc && *p; i++) { while (*p++); } ntstdio_printf(&ntstdio, "%s() =>%u %s\n", func, (UINT)rc, p); } char *basename(char *s) { size_t i, j; if (!s || !*s) return "."; i = strlen(s) - 1; for (j = 0; j <= i; j++) if (s[j] == ':') { s = &s[j + 1]; i -= j; break; } for (; i&&s[i] == '/'; i--) s[i] = 0; for (; i&&s[i - 1] != '/'; i--); return s + i; } char *dirname(char *_s) { char *s = _s; size_t i, j; if (!s || !*s) return "."; i = strlen(s) - 1; for (j = 0; j <= i; j++) if (s[j] == ':') { s = &s[j + 1]; i -= j; break; } for (; s[i] == '/'; i--) if (!i) return (s == _s) ? "/" : _s; for (; s[i] != '/'; i--) if (!i) return (s == _s) ? "." : _s; for (; s[i] == '/'; i--) if (!i) if (s == _s) return "/"; else break; s[i + 1] = 0; return _s; } int usrcmd_cd(int argc, char **argv) { FRESULT res; if (argc == 2) { if ((res = f_chdir(argv[1])) != FR_OK) { put_rc("f_chdir", res); return 0; } if ((res = f_chdrive(argv[1]) != FR_OK)) { put_rc("f_chdrive", res); return 0; } } char path[256]; if ((res = f_getcwd(path, sizeof(path))) != FR_OK) { put_rc("f_getcwd", res); return 0; } strlcat(path, "\n", sizeof(path)); ntstdio_printf(&ntstdio, path); return 0; } #define LS_ALL 0x01 #define LS_LONG 0x02 /* lsコマンド 1行表示 */ void print_one_list(FILINFO *fno, BYTE list_option) { char *fn; #if _USE_LFN fn = *fno->lfname ? fno->lfname : fno->fname; #else fn = fno->fname; #endif if (!(list_option & LS_ALL)) { if ((fno->fattrib & AM_HID) || (fn[0] == '.')) return; } if (list_option & LS_LONG) { ntstdio_printf(&ntstdio, "%c%c%c%c%c %04d/%02d/%02d %02d:%02d:%02d ", (fno->fattrib & AM_DIR) ? 'd' : '-', (fno->fattrib & AM_RDO) ? 'r' : '-', (fno->fattrib & AM_HID) ? 'h' : '-', (fno->fattrib & AM_SYS) ? 's' : '-', (fno->fattrib & AM_ARC) ? 'a' : '-', ((fno->fdate & 0xFE00) >> 9) + 1980, ((fno->fdate & 0x01E0) >> 5), ( fno->fdate & 0x001F), ((fno->ftime & 0xF800) >> 11), ((fno->ftime & 0x07E0) >> 5), ( fno->ftime & 0x001F)); if (fno->fattrib & AM_DIR) { /* It is a directory */ ntstdio_printf(&ntstdio, "%10S ", " "); } else { ntstdio_printf(&ntstdio, "%10d ", fno->fsize); } } if (fno->fattrib & AM_DIR) { /* It is a directory */ ntstdio_printf(&ntstdio, "\x1B[32m%s\x1B[0m\n", fn); } else { ntstdio_printf(&ntstdio, "%s\n", fn); } } #define LFN_BUF_SIZE (_MAX_LFN + 1) /* lsコマンド dir内 表示 */ void print_ls(char *path_p, char *pattern_p, BYTE list_option) { FRESULT res; FILINFO fno; DIR dir; char *fn; /* This function assumes non-Unicode configuration */ if ((pattern_p != NULL) && (pattern_p[0] == '\0')) pattern_p = NULL; char *path_backup = NULL; path_backup = ff_memalloc(LFN_BUF_SIZE); if (path_backup == NULL) { ntstdio_printf(&ntstdio, "ff_memalloc err.\n"); return; } #if _USE_LFN char *lfn = NULL; lfn = ff_memalloc(LFN_BUF_SIZE); if (lfn == NULL) { ntstdio_printf(&ntstdio, "ff_memalloc err.\n"); ff_memfree(path_backup); return; } fno.lfname = lfn; fno.lfsize = LFN_BUF_SIZE; #endif if ((path_p != NULL) && (pattern_p == NULL)) { if ((res = f_opendir(&dir, path_p)) != FR_OK) put_rc("f_opendir", res); res = f_readdir(&dir, &fno); } else { res = f_findfirst(&dir, &fno, path_p, pattern_p); } while ((res == FR_OK) && (fno.fname[0] != 0)) { if (pattern_p != NULL && (fno.fattrib & AM_DIR) && ((fno.fname[0] == '.') ? (pattern_p[0] == '.') : 1)) {/* DIR とパターンマッチしている場合は DIR 内部を ls する */ #if _USE_LFN fn = *fno.lfname ? fno.lfname : fno.fname; #else fn = fno->fname; #endif if ((res = f_getcwd(path_backup, LFN_BUF_SIZE)) != FR_OK) { put_rc("f_getcwd", res); } if ((res = f_chdrive(path_p)) != RES_OK) { put_rc("f_chdrive", res); } if ((res = f_chdir(path_p)) != RES_OK) { put_rc("f_chdir", res); } ntstdio_printf(&ntstdio, "\n%s/%s:\n", path_p, fn); print_ls(fn, NULL, list_option); ntstdio_printf(&ntstdio, "\n"); if ((res = f_chdrive(path_backup)) != RES_OK) { put_rc("f_chdrive", res); } if ((res = f_chdir(path_backup)) != RES_OK) { put_rc("f_chdir", res); } } else { print_one_list(&fno, list_option); } if (pattern_p == NULL) res = f_readdir(&dir, &fno); /* all */ else res = f_findnext(&dir, &fno); /* pattern matching */ } f_closedir(&dir); if (lfn != NULL) ff_memfree(lfn); if (path_backup != NULL) ff_memfree(path_backup); } int usrcmd_ls(int argc, char **argv) { char *pattern_p = NULL, *basename_p = NULL, *dirname_p = NULL; char default_pattern[_MAX_LFN] = ""; int i; BYTE list_option = 0; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { if (argv[i][1] == 'a') { list_option |= LS_ALL; } else if (argv[i][1] == 'l') { list_option |= LS_LONG; } continue; } if (argv[i][0] != '\0') { /* pattern matching ? */ pattern_p = &argv[i][0]; break; } } if (pattern_p != NULL) strlcpy(default_pattern, pattern_p, sizeof(default_pattern)); basename_p = basename(pattern_p); dirname_p = dirname(default_pattern); if (((dirname_p[0] == '/') && (basename_p[0] == '/')) || (!strncmp(dirname_p, ".", strlen(dirname_p)) && !strncmp(basename_p, ".", strlen(basename_p)))) { basename_p = NULL; } print_ls(dirname_p, basename_p, list_option); return 0; } int usrcmd_cp(int argc, char **argv) { char *src_str_p = NULL, *dst_str_p = NULL; unsigned char i; FRESULT res; FILINFO fno; FIL src_fp, dst_fp; size_t read_size, write_size; char *lfn = NULL, *local_buff = NULL, *dst_mod_str_p = NULL; char *src_basename_p; if (argc < 2) return 0; /* 引数チェック */ for (i = 1; i < argc; i++) { if (argv[i][0] == '-') continue; if (argv[i][0] != '\0') { if (src_str_p == NULL) src_str_p = &argv[i][0]; else { dst_str_p = &argv[i][0]; break; } } } if ((src_str_p == NULL) || (dst_str_p == NULL)) return 0; #if _USE_LFN /* LFN buffer alloc */ lfn = ff_memalloc(LFN_BUF_SIZE); if (lfn == NULL) { ntstdio_printf(&ntstdio, "alloc err.\n"); goto cp_end; } fno.lfname = lfn; fno.lfsize = LFN_BUF_SIZE; #endif /* copy buffer alloc */ local_buff = ff_memalloc(64); if (local_buff == NULL) { ntstdio_printf(&ntstdio, "alloc err.\n"); goto cp_end; } /*************/ /* src check */ /*************/ res = f_stat(src_str_p, &fno); if (res != FR_OK) { if (res == FR_NO_FILE) ntstdio_printf(&ntstdio, "src no file.\n", res); else ntstdio_printf(&ntstdio, "src stat err(%d).\n", res); goto cp_end; } if (fno.fattrib & AM_DIR) { /* src is dir */ /*******************************************************/ /* from dir */ /* 未実装 */ } else { /* src is file */ res = f_open(&src_fp, src_str_p, (FA_OPEN_EXISTING | FA_READ)); if (res != FR_OK) { ntstdio_printf(&ntstdio, "src open err(%d).\n", res); goto cp_end; } } /*************/ /* dst check */ /*************/ res = f_stat(dst_str_p, &fno); if (res != FR_NO_FILE) { if (res == FR_OK) { if (fno.fattrib & AM_DIR) { /* dst is dir */ src_basename_p = basename(src_str_p); dst_mod_str_p = ff_memalloc(LFN_BUF_SIZE); if (dst_mod_str_p == NULL) { ntstdio_printf(&ntstdio, "alloc err.\n"); goto cp_end; } ntstdio_snprintf(dst_mod_str_p, LFN_BUF_SIZE, "%s/%s\0", dst_str_p, src_basename_p); dst_str_p = dst_mod_str_p; } else { ntstdio_printf(&ntstdio, "dst file exists.\n"); goto cp_end_1; } } else { ntstdio_printf(&ntstdio, "src stat err(%d).\n", res); goto cp_end_1; } } res = f_open(&dst_fp, dst_str_p, (FA_CREATE_NEW | FA_WRITE)); if (res != FR_OK) { ntstdio_printf(&ntstdio, "dst open err(%d).\n", res); goto cp_end_1; } /********/ /* copy */ /********/ do { /* read from src */ res = f_read(&src_fp, local_buff, sizeof(local_buff), &read_size); if (res != FR_OK) { ntstdio_printf(&ntstdio, "src read err(%d).\n", res); goto cp_end_2; } /* write to dst */ res = f_write(&dst_fp, local_buff, read_size, &write_size); if (res != FR_OK) { ntstdio_printf(&ntstdio, "dst write err(%d).\n", res); goto cp_end_2; } if (read_size != write_size) { ntstdio_printf(&ntstdio, "dst write err(disk full).\n", res); goto cp_end_2; } } while (read_size == sizeof(local_buff)); cp_end_2: f_close(&dst_fp); cp_end_1: f_close(&src_fp); cp_end: if(dst_mod_str_p != NULL) ff_memfree(dst_mod_str_p); if(local_buff != NULL) ff_memfree(local_buff); if(lfn != NULL) ff_memfree(lfn); return 0; } int usrcmd_rm(int argc, char **argv) { FRESULT res; if (argc == 2) { if ((res = f_unlink(argv[1])) != FR_OK) { put_rc("f_unlink", res); return 0; } } return 0; } int usrcmd_mv(int argc, char **argv) { FRESULT res; if (argc == 3) { if ((res = f_rename(argv[1], argv[2])) != FR_OK) { put_rc("f_rename", res); return 0; } } return 0; } int usrcmd_mkdir(int argc, char **argv) { FRESULT res; if (argc == 2) { if ((res = f_mkdir(argv[1])) != FR_OK) { put_rc("f_mkdir", res); return 0; } } return 0; } int usrcmd_hexdump(int argc, char **argv) { FRESULT res; FIL fsrc; unsigned char data[16 + 1]; unsigned char ascii[sizeof("\x1B[31m0\x1B[0m\x1B[31m1\x1B[0m\x1B[31m2\x1B[0m\x1B[31m3\x1B[0m\x1B[31m4\x1B[0m\x1B[31m5\x1B[0m\x1B[31m6\x1B[0m\x1B[31m7\x1B[0m\x1B[31m8\x1B[0m\x1B[31m9\x1B[0m\x1B[31ma\x1B[0m\x1B[31mb\x1B[0m\x1B[31mc\x1B[0m\x1B[31md\x1B[0m\x1B[31me\x1B[0m\x1B[31mf\x1B[0m")]; char line[sizeof("00000000: 00 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 00 : \n") + sizeof(ascii)]; if (argc != 2) { ntstdio_printf(&ntstdio, "hexdump file\n"); } if ((res = f_open(&fsrc, argv[1], FA_OPEN_EXISTING | FA_READ)) != FR_OK) { put_rc("f_open", res); return 0; } for (int i = 0; i < fsrc.fsize; i += 16) { ascii[0] = '\0'; line[0] = '\0'; char *pos = line; int rst = sizeof(line); int len = ntstdio_snprintf(pos, rst, "%08X: ", i); pos += len; rst -= len; UINT br = 0; if ((res = f_read(&fsrc, data, 16, &br)) != FR_OK) { put_rc("f_read", res); f_close(&fsrc); return 0; } data[16] = '\0'; char *apos = ascii; int arst = sizeof(ascii); for (int j = 0; j < br; j++) { unsigned char c = data[j]; if (j != 7) len = ntstdio_snprintf(pos, rst, "%02X ", c); else len = ntstdio_snprintf(pos, rst, "%02X-", c); pos += len; rst -= len; if (c < 0x20) { len = ntstdio_snprintf(apos, arst , "\x1B[31m%c\x1B[0m", c + 0x40); } else if (c == 0xFF) { len = ntstdio_snprintf(apos, arst, "\x1B[32m%c\x1B[0m", 'E'); } else { len = ntstdio_snprintf(apos, arst, "%c", c); } apos += len; arst -= len; } for (int j = br; j < 16; j++) { if (j != 7) len = ntstdio_snprintf(pos, rst, " "); else len = ntstdio_snprintf(pos, rst, " -"); pos += len; rst -= len; } len = ntstdio_snprintf(pos, rst, ": %s\n", ascii); pos += len; rst -= len; ntstdio_printf(&ntstdio, line); } f_close(&fsrc); return 0; } int usrcmd_info(int argc, char **argv) { if (argc != 2) { ntstdio_printf(&ntstdio, "info sys\n"); ntstdio_printf(&ntstdio, "info ver\n"); return 0; } if (strcmp(argv[1], "sys") == 0) { ntstdio_printf(&ntstdio, "GR-PEACH Monitor\n"); return 0; } if (strcmp(argv[1], "ver") == 0) { int mj, mn, bd; ntshell_version(&mj, &mn, &bd); ntstdio_printf(&ntstdio, "Version %d.%d.%d\n", mj, mn, bd); return 0; } ntstdio_printf(&ntstdio, "Unknown sub command found\n"); return -1; } int usrcmd_exit(int argc, char **argv) { ntshell_exit = 1; return 0; }