#include "builtins.h" #include "shell.h" #include #include #include #include #include #include #include #include #include #include #define DEFAULT_ARGV(...) \ char *_argv_default[] = {argv[0], __VA_ARGS__}; \ if (argc <= 1) { \ argc = sizeof(_argv_default) / sizeof(*_argv_default); \ argv = _argv_default; \ } static void cmd_cat(int argc, char **argv) { const size_t buflen = 4096; char *buf = malloc(buflen); DEFAULT_ARGV("!stdin"); for (int i = 1; i < argc; i++) { FILE *file = fopen(argv[i], "r"); if (!file) { perror(argv[i]); return; } if (!strcmp(argv[i], "!stdin")) fextflags(file, FEXT_NOFILL); for (;;) { int len = fread(buf, 1, buflen, file); if (len <= 0) break; fwrite(buf, 1, len, stdout); } fclose(file); } } static void cmd_echo(int argc, char **argv) { bool newline = true; int i = 1; if (!strcmp("-n", argv[i])) { i++; newline = false; } printf("%s", argv[i++]); for (; i < argc; i++) printf(" %s", argv[i]); if (newline) printf("\n"); } void cmd_getsize(int argc, char **argv) { if (argc < 2) errx(1, "no arguments"); for (int i = 1; i < argc; i++) { hid_t h = camellia_open(argv[i], OPEN_READ); if (h < 0) { warn("error opening %s", argv[i]); continue; } printf("%s: %d\n", argv[i], (int)_sys_getsize(h)); _sys_close(h); } } void cmd_hexdump(int argc, char **argv) { DEFAULT_ARGV("!stdin"); const size_t buflen = 4096; uint8_t *buf = malloc(buflen); FILE *file; bool canonical = strcmp(argv[0], "hd") == 0; size_t readlen = ~0; size_t pos = 0; bool raw = false; int c; optind = 0; while ((c = getopt(argc, argv, "Cn:s:r")) != -1) { switch (c) { case 'C': canonical = true; break; case 'n': readlen = strtol(optarg, NULL, 0); break; case 's': pos = strtol(optarg, NULL, 0); break; case 'r': /* "raw" mode, print data as soon as it's read without buffering */ raw = true; break; default: return; } } if (readlen != (size_t)~0) readlen += pos; for (; optind < argc; optind++) { file = fopen(argv[optind], "r"); if (!file) { warn("couldn't open %s", argv[optind]); continue; } if (raw) fextflags(file, FEXT_NOFILL); fseek(file, pos, SEEK_SET); bool skipped = false; while (pos < readlen) { size_t len = buflen; if (len > readlen - pos) len = readlen - pos; len = fread(buf, 1, len, file); if (len == 0) break; for (size_t i = 0; i < len; i += 16) { if (i >= 16 && !memcmp(buf + i, buf + i - 16, 16)) { if (!skipped) { printf("*\n"); skipped = true; } continue; } else skipped = false; printf("%08zx ", pos + i); for (size_t j = i; j < i + 8 && j < len; j++) printf("%02x ", buf[j]); printf(" "); for (size_t j = i + 8; j < i + 16 && j < len; j++) printf("%02x ", buf[j]); if (canonical) { printf(" |"); for (size_t j = i; j < i + 16 && j < len; j++) { char c = '.'; if (0x20 <= buf[j] && buf[j] < 0x7f) c = buf[j]; printf("%c", c); } printf("|\n"); } else { printf("\n"); } } pos += len; } printf("%08zx\n", pos); fclose(file); } } static void cmd_ls(int argc, char **argv) { FILE *file; const size_t buflen = 4096; char *buf = malloc(buflen); DEFAULT_ARGV("."); for (int i = 1; i < argc; i++) { char *path = (void*)argv[i]; int pathlen = strlen(path); if (!pathlen || path[pathlen - 1] != '/') { memcpy(buf, path, pathlen); buf[pathlen] = '/'; buf[pathlen+1] = '\0'; path = buf; } file = fopen(path, "r"); if (!file) { warn("couldn't open %s", argv[i]); continue; } for (;;) { int len = fread(buf, 1, buflen, file); if (len <= 0) break; for (int i = 0; i < len; i++) if (buf[i] == '\0') buf[i] = '\n'; fwrite(buf, 1, len, stdout); } fclose(file); } } static void cmd_mkdir(int argc, char **argv) { // TODO mkdir -p if (argc < 2) errx(1, "no arguments"); for (int i = 1; i < argc; i++) { if (mkdir(argv[i], 0777) < 0) perror(argv[i]); } } static void cmd_rm(int argc, char **argv) { if (argc < 2) errx(1, "no arguments"); for (int i = 1; i < argc; i++) { if (unlink(argv[i]) < 0) perror(argv[i]); } } static void cmd_sleep(int argc, char **argv) { if (argc < 2) errx(1, "no arguments"); _sys_sleep(strtol(argv[1], NULL, 0) * 1000); } static void cmd_touch(int argc, char **argv) { if (argc < 2) errx(1, "no arguments"); for (int i = 1; i < argc; i++) { FILE *f = fopen(argv[i], "a"); if (!f) perror(argv[i]); fclose(f); } } static void cmd_whitelist(int argc, char **argv) { int split = 1; for (; split < argc;) { if (!strcmp("--", argv[split])) break; split++; } argv[split] = NULL; MOUNT_AT("/") { fs_whitelist((void*)&argv[1]); } if (split < argc) { run_args(argc - split - 1, &argv[split + 1], NULL); } else { const char **argv = (const char*[]){"shell", NULL}; run_args(1, (void*)argv, NULL); } } struct builtin builtins[] = { {"cat", cmd_cat}, {"echo", cmd_echo}, {"getsize", cmd_getsize}, {"hd", cmd_hexdump}, {"hexdump", cmd_hexdump}, {"ls", cmd_ls}, {"mkdir", cmd_mkdir}, {"rm", cmd_rm}, {"sleep", cmd_sleep}, {"touch", cmd_touch}, {"whitelist", cmd_whitelist}, {NULL, NULL}, };