Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.     UMKa - User-Mode KolibriOS developer tools
  3.     umka_shell - interactive shell
  4.     Copyright (C) 2018--2020  Ivan Baravy <dunkaist@gmail.com>
  5.  
  6.     This program is free software: you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation, either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program.  If not, see <https://www.gnu.org/licenses/>.
  18. */
  19.  
  20. #include <stdio.h>
  21. #include <stdbool.h>
  22. #include <stdint.h>
  23. #include <inttypes.h>
  24. #include <limits.h>
  25. #include <stdlib.h>
  26. #include <stddef.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #include <sys/types.h>
  30. #include <sys/select.h>
  31. #include <sys/stat.h>
  32. #include <fcntl.h>
  33. #include <assert.h>
  34. #include <time.h>
  35. #include <fcntl.h>
  36. #include <sys/socket.h>
  37. #include <sys/types.h>
  38. #include <netinet/in.h>
  39. #include <arpa/inet.h>
  40. #include <errno.h>
  41. #include "vdisk.h"
  42. #include "vnet.h"
  43. #include "umka.h"
  44. #include "trace.h"
  45. #include "pci.h"
  46. #include "util.h"
  47. #include "lodepng.h"
  48.  
  49. #define PATH_MAX 4096
  50. #define FGETS_BUF_LEN 4096
  51. #define MAX_COMMAND_ARGS 42
  52. #define PRINT_BYTES_PER_LINE 32
  53. #define MAX_DIRENTS_TO_READ 100
  54. #define MAX_BYTES_TO_READ (1024*1024)
  55.  
  56. #define DEFAULT_READDIR_ENCODING UTF8
  57. #define DEFAULT_PATH_ENCODING UTF8
  58.  
  59. FILE *fin, *fout;
  60.  
  61. char cur_dir[PATH_MAX] = "/";
  62. const char *last_dir = cur_dir;
  63. bool cur_dir_changed = true;
  64.  
  65. char cmd_buf[FGETS_BUF_LEN];
  66.  
  67. typedef struct {
  68.     char *name;
  69.     void (*func) (int, char **);
  70. } func_table_t;
  71.  
  72. const char *f70_status_name[] = {
  73.                                  "success",
  74.                                  "disk_base",
  75.                                  "unsupported_fs",
  76.                                  "unknown_fs",
  77.                                  "partition",
  78.                                  "file_not_found",
  79.                                  "end_of_file",
  80.                                  "memory_pointer",
  81.                                  "disk_full",
  82.                                  "fs_fail",
  83.                                  "access_denied",
  84.                                  "device",
  85.                                  "out_of_memory"
  86.                                 };
  87.  
  88. static const char *
  89. get_f70_status_name(int s) {
  90.     switch (s) {
  91.     case ERROR_SUCCESS:
  92. //        return "";
  93.     case ERROR_DISK_BASE:
  94.     case ERROR_UNSUPPORTED_FS:
  95.     case ERROR_UNKNOWN_FS:
  96.     case ERROR_PARTITION:
  97.     case ERROR_FILE_NOT_FOUND:
  98.     case ERROR_END_OF_FILE:
  99.     case ERROR_MEMORY_POINTER:
  100.     case ERROR_DISK_FULL:
  101.     case ERROR_FS_FAIL:
  102.     case ERROR_ACCESS_DENIED:
  103.     case ERROR_DEVICE:
  104.     case ERROR_OUT_OF_MEMORY:
  105.         return f70_status_name[s];
  106.     default:
  107.         return "unknown";
  108.     }
  109. }
  110.  
  111. static void
  112. convert_f70_file_attr(uint32_t attr, char s[KF_ATTR_CNT+1]) {
  113.     s[0] = (attr & KF_READONLY) ? 'r' : '-';
  114.     s[1] = (attr & KF_HIDDEN)   ? 'h' : '-';
  115.     s[2] = (attr & KF_SYSTEM)   ? 's' : '-';
  116.     s[3] = (attr & KF_LABEL)    ? 'l' : '-';
  117.     s[4] = (attr & KF_FOLDER)   ? 'f' : '-';
  118.     s[5] = '\0';
  119. }
  120.  
  121. static void
  122. print_f70_status(f7080ret_t *r, int use_ebx) {
  123.     fprintf(fout, "status = %d %s", r->status, get_f70_status_name(r->status));
  124.     if (use_ebx &&
  125.         (r->status == ERROR_SUCCESS || r->status == ERROR_END_OF_FILE))
  126.         fprintf(fout, ", count = %d", r->count);
  127.     fputc('\n', fout);
  128. }
  129.  
  130. static bool
  131. parse_uintmax(const char *str, uintmax_t *res) {
  132.     char *endptr;
  133.     *res = strtoumax(str, &endptr, 0);
  134.     bool ok = (str != endptr) && (*endptr == '\0');
  135.     return ok;
  136. }
  137.  
  138. static bool
  139. parse_uint32(const char *str, uint32_t *res) {
  140.     uintmax_t x;
  141.     if (parse_uintmax(str, &x) && x <= UINT32_MAX) {
  142.         *res = (uint32_t)x;
  143.         return true;
  144.     } else {
  145.         perror("invalid number");
  146.         return false;
  147.     }
  148. }
  149.  
  150. static bool
  151. parse_uint64(const char *str, uint64_t *res) {
  152.     uintmax_t x;
  153.     if (parse_uintmax(str, &x) && x <= UINT64_MAX) {
  154.         *res = x;
  155.         return true;
  156.     } else {
  157.         perror("invalid number");
  158.         return false;
  159.     }
  160. }
  161.  
  162. static void
  163. print_bytes(uint8_t *x, size_t len) {
  164.     for (size_t i = 0; i < len; i++) {
  165.         if (i % PRINT_BYTES_PER_LINE == 0 && i != 0) {
  166.             fputc('\n', fout);
  167.         }
  168.         fprintf(fout, "%2.2x", x[i]);
  169.     }
  170.     fputc('\n', fout);
  171. }
  172.  
  173. static void
  174. print_hash(uint8_t *x, size_t len) {
  175.     hash_context ctx;
  176.     hash_oneshot(&ctx, x, len);
  177.     for (size_t i = 0; i < HASH_SIZE; i++) {
  178.         fprintf(fout, "%2.2x", ctx.hash[i]);
  179.     }
  180.     fputc('\n', fout);
  181. }
  182.  
  183. static const char *
  184. get_last_dir(const char *path) {
  185.     const char *last = strrchr(path, '/');
  186.     if (!last) {
  187.         last = path;
  188.     } else if (last != path || last[1] != '\0') {
  189.         last++;
  190.     }
  191.     return last;
  192. }
  193.  
  194. static void
  195. prompt() {
  196.     if (cur_dir_changed) {
  197.         if (umka_initialized) {
  198.             COVERAGE_ON();
  199.             umka_sys_get_cwd(cur_dir, PATH_MAX);
  200.             COVERAGE_OFF();
  201.         }
  202.         last_dir = get_last_dir(cur_dir);
  203.         cur_dir_changed = false;
  204.     }
  205.     fprintf(fout, "%s> ", last_dir);
  206.     fflush(fout);
  207. }
  208.  
  209. static int
  210. next_line(int is_tty, int block) {
  211.     if (is_tty) {
  212.         prompt();
  213.     }
  214.     if (block) {
  215.         return fgets(cmd_buf, FGETS_BUF_LEN, fin) != NULL;
  216.     } else {
  217.         fd_set readfds;
  218. //        FD_ZERO(&readfds);
  219.         memset(&readfds, 0, sizeof(readfds));
  220.         FD_SET(fileno(fin), &readfds);
  221.         struct timeval timeout = {.tv_sec = 0, .tv_usec = 0};
  222.         int sr = select(fileno(fin)+1, &readfds, NULL, NULL, &timeout);
  223.         if (sr > 0) {
  224.             fgets(cmd_buf, FGETS_BUF_LEN, fin);
  225.             if (cmd_buf[0] == EOF) {
  226.                 cmd_buf[0] = '\0';
  227.             }
  228.         } else {
  229.             cmd_buf[0] = '\0';
  230.         }
  231.         return 1;
  232.     }
  233. }
  234.  
  235. static int
  236. split_args(char *s, char **argv) {
  237.     int argc = -1;
  238.     for (; (argv[++argc] = strtok(s, " \t\n\r")) != NULL; s = NULL);
  239.     return argc;
  240. }
  241.  
  242. static void
  243. shell_umka_init(int argc, char **argv) {
  244.     const char *usage = \
  245.         "usage: umka_init";
  246.     (void)argv;
  247.     if (argc < 0) {
  248.         fputs(usage, fout);
  249.         return;
  250.     }
  251.     COVERAGE_ON();
  252.     umka_init();
  253.     COVERAGE_OFF();
  254. }
  255.  
  256. static void
  257. shell_umka_set_boot_params(int argc, char **argv) {
  258.     const char *usage = \
  259.         "usage: umka_set_boot_params [--x_res <num>] [--y_res <num>]\n"
  260.         "  --x_res <num>    screen width\n"
  261.         "  --y_res <num>    screen height";
  262.  
  263.     argc -= 1;
  264.     argv += 1;
  265.  
  266.     while (argc) {
  267.         if (!strcmp(argv[0], "--x_res") && argc > 1) {
  268.             kos_boot.x_res = strtoul(argv[1], NULL, 0);
  269.             kos_boot.pitch = kos_boot.x_res * 4;    // assume 32bpp
  270.             argc -= 2;
  271.             argv += 2;
  272.             continue;
  273.         } else if (!strcmp(argv[0], "--y_res") && argc > 1) {
  274.             kos_boot.y_res = strtoul(argv[1], NULL, 0);
  275.             argc -= 2;
  276.             argv += 2;
  277.             continue;
  278.         } else {
  279.             printf("bad option: %s\n", argv[0]);
  280.             puts(usage);
  281.             exit(1);
  282.         }
  283.     }
  284.  
  285. }
  286.  
  287. static void
  288. shell_i40(int argc, char **argv) {
  289.     const char *usage = \
  290.         "usage: i40 <eax> [ebx [ecx [edx [esi [edi [ebp]]]]]]...\n"
  291.         "  see '/kernel/docs/sysfuncs.txt' for details";
  292.     if (argc < 2 || argc > 8) {
  293.         fputs(usage, fout);
  294.         return;
  295.     }
  296.     pushad_t regs = {0, 0, 0, 0, 0, 0, 0, 0};
  297.     if (argv[1]) regs.eax = strtoul(argv[1], NULL, 0);
  298.     if (argv[2]) regs.ebx = strtoul(argv[2], NULL, 0);
  299.     if (argv[3]) regs.ecx = strtoul(argv[3], NULL, 0);
  300.     if (argv[4]) regs.edx = strtoul(argv[4], NULL, 0);
  301.     if (argv[5]) regs.esi = strtoul(argv[5], NULL, 0);
  302.     if (argv[6]) regs.edi = strtoul(argv[6], NULL, 0);
  303.     if (argv[7]) regs.ebp = strtoul(argv[7], NULL, 0);
  304.     COVERAGE_ON();
  305.     umka_i40(&regs);
  306.     COVERAGE_OFF();
  307.     fprintf(fout, "eax = %8.8x  %" PRIu32 "  %" PRIi32 "\n"
  308.            "ebx = %8.8x  %" PRIu32 "  %" PRIi32 "\n",
  309.            regs.eax, regs.eax, (int32_t)regs.eax,
  310.            regs.ebx, regs.ebx, (int32_t)regs.ebx);
  311. }
  312.  
  313. static void
  314. disk_list_partitions(disk_t *d) {
  315.     for (size_t i = 0; i < d->num_partitions; i++) {
  316.         fprintf(fout, "/%s/%d: ", d->name, i+1);
  317.         if (d->partitions[i]->fs_user_functions == xfs_user_functions) {
  318.             fputs("xfs\n", fout);
  319.         } else if (d->partitions[i]->fs_user_functions == ext_user_functions) {
  320.             fputs("ext\n", fout);
  321.         } else if (d->partitions[i]->fs_user_functions == fat_user_functions) {
  322.             fputs("fat\n", fout);
  323.         } else if (d->partitions[i]->fs_user_functions == ntfs_user_functions) {
  324.             fputs("ntfs\n", fout);
  325.         } else {
  326.             fputs("???\n", fout);
  327.         }
  328.     }
  329. }
  330.  
  331. static void
  332. shell_ramdisk_init(int argc, char **argv) {
  333.     const char *usage = \
  334.         "usage: ramdisk_init <file>\n"
  335.         "  <file>           absolute or relative path";
  336.     if (argc != 2) {
  337.         fputs(usage, fout);
  338.         return;
  339.     }
  340.     const char *fname = argv[1];
  341.     FILE *f = fopen(fname, "r");
  342.     if (!f) {
  343.         fprintf(fout, "[!] can't open file '%s': %s\n", fname, strerror(errno));
  344.         return;
  345.     }
  346.     fseek(f, 0, SEEK_END);
  347.     size_t fsize = ftell(f);
  348.     if (fsize > 2880*512) {
  349.         fprintf(fout, "[!] file '%s' is too big, max size is 1474560 bytes\n",
  350.                 fname);
  351.         return;
  352.     }
  353.     rewind(f);
  354.     fread(kos_ramdisk, fsize, 1, f);
  355.     fclose(f);
  356.     COVERAGE_ON();
  357.     void *ramdisk = kos_ramdisk_init();
  358.     COVERAGE_OFF();
  359.     disk_list_partitions(ramdisk);
  360. }
  361.  
  362. static void
  363. shell_disk_add(int argc, char **argv) {
  364.     const char *usage = \
  365.         "usage: disk_add <file> <name> [option]...\n"
  366.         "  <file>           absolute or relative path\n"
  367.         "  <name>           disk name, e.g. hd0 or rd\n"
  368.         "  -c cache size    size of disk cache in bytes";
  369.     if (argc < 3) {
  370.         fputs(usage, fout);
  371.         return;
  372.     }
  373.     size_t cache_size = 0;
  374.     int adjust_cache_size = 0;
  375.     int opt;
  376.     optind = 1;
  377.     const char *file_name = argv[optind++];
  378.     const char *disk_name = argv[optind++];
  379.     while ((opt = getopt(argc, argv, "c:")) != -1) {
  380.         switch (opt) {
  381.         case 'c':
  382.             cache_size = strtoul(optarg, NULL, 0);
  383.             adjust_cache_size = 1;
  384.             break;
  385.         default:
  386.             fputs(usage, fout);
  387.             return;
  388.         }
  389.     }
  390.  
  391.     void *userdata = vdisk_init(file_name, adjust_cache_size, cache_size);
  392.     if (userdata) {
  393.         COVERAGE_ON();
  394.         void *vdisk = disk_add(&vdisk_functions, disk_name, userdata, 0);
  395.         COVERAGE_OFF();
  396.         if (vdisk) {
  397.             COVERAGE_ON();
  398.             disk_media_changed(vdisk, 1);
  399.             COVERAGE_OFF();
  400.             disk_list_partitions(vdisk);
  401.             return;
  402.         }
  403.     }
  404.     fprintf(fout, "umka: can't add file '%s' as disk '%s'\n", file_name,
  405.             disk_name);
  406.     return;
  407. }
  408.  
  409. static void
  410. disk_del_by_name(const char *name) {
  411.     for(disk_t *d = disk_list.next; d != &disk_list; d = d->next) {
  412.         if (!strcmp(d->name, name)) {
  413.             COVERAGE_ON();
  414.             disk_del(d);
  415.             COVERAGE_OFF();
  416.             return;
  417.         }
  418.     }
  419.     fprintf(fout, "umka: can't find disk '%s'\n", name);
  420. }
  421.  
  422. static void
  423. shell_disk_del(int argc, char **argv) {
  424.     const char *usage = \
  425.         "usage: disk_del <name>\n"
  426.         "  name             disk name, i.e. rd or hd0";
  427.     if (argc != 2) {
  428.         fputs(usage, fout);
  429.         return;
  430.     }
  431.     const char *name = argv[1];
  432.     disk_del_by_name(name);
  433.     return;
  434. }
  435.  
  436. static void
  437. shell_pwd(int argc, char **argv) {
  438.     const char *usage = \
  439.         "usage: pwd";
  440.     if (argc != 1) {
  441.         fputs(usage, fout);
  442.         return;
  443.     }
  444.     (void)argv;
  445.     bool quoted = false;
  446.     const char *quote = quoted ? "'" : "";
  447.     COVERAGE_ON();
  448.     umka_sys_get_cwd(cur_dir, PATH_MAX);
  449.     COVERAGE_OFF();
  450.     fprintf(fout, "%s%s%s\n", quote, cur_dir, quote);
  451. }
  452.  
  453. static void
  454. shell_set_pixel(int argc, char **argv) {
  455.     const char *usage = \
  456.         "usage: set_pixel <x> <y> <color> [-i]\n"
  457.         "  x                x window coordinate\n"
  458.         "  y                y window coordinate\n"
  459.         "  color            argb in hex\n"
  460.         "  -i               inverted color";
  461.     if (argc < 4) {
  462.         fputs(usage, fout);
  463.         return;
  464.     }
  465.     size_t x = strtoul(argv[1], NULL, 0);
  466.     size_t y = strtoul(argv[2], NULL, 0);
  467.     uint32_t color = strtoul(argv[3], NULL, 16);
  468.     int invert = (argc == 5) && !strcmp(argv[4], "-i");
  469.     COVERAGE_ON();
  470.     umka_sys_set_pixel(x, y, color, invert);
  471.     COVERAGE_OFF();
  472. }
  473.  
  474. static void
  475. shell_write_text(int argc, char **argv) {
  476.     const char *usage = \
  477.         "usage: write_text <x> <y> <color> <string> <asciiz> <fill_bg>"
  478.             " <font_and_enc> <draw_to_buf> <scale_factor> <length>"
  479.             " <bg_color_or_buf>\n"
  480.         "  x                x window coordinate\n"
  481.         "  y                y window coordinate\n"
  482.         "  color            argb in hex\n"
  483.         "  string           escape spaces\n"
  484.         "  asciiz           1 if the string is zero-terminated\n"
  485.         "  fill_bg          fill text background with specified color\n"
  486.         "  font_and_enc     font size and string encoding\n"
  487.         "  draw_to_buf      draw to the buffer pointed to by the next param\n"
  488.         "  length           length of the string if it is non-asciiz\n"
  489.         "  bg_color_or_buf  argb or pointer";
  490.     if (argc != 12) {
  491.         fputs(usage, fout);
  492.         return;
  493.     }
  494.     size_t x = strtoul(argv[1], NULL, 0);
  495.     size_t y = strtoul(argv[2], NULL, 0);
  496.     uint32_t color = strtoul(argv[3], NULL, 16);
  497.     const char *string = argv[4];
  498.     int asciiz = strtoul(argv[5], NULL, 0);
  499.     int fill_background = strtoul(argv[6], NULL, 0);
  500.     int font_and_encoding = strtoul(argv[7], NULL, 0);
  501.     int draw_to_buffer = strtoul(argv[8], NULL, 0);
  502.     int scale_factor = strtoul(argv[9], NULL, 0);
  503.     int length = strtoul(argv[10], NULL, 0);
  504.     int background_color_or_buffer = strtoul(argv[11], NULL, 0);
  505.     COVERAGE_ON();
  506.     umka_sys_write_text(x, y, color, asciiz, fill_background, font_and_encoding,
  507.                         draw_to_buffer, scale_factor, string, length,
  508.                         background_color_or_buffer);
  509.     COVERAGE_OFF();
  510. }
  511.  
  512. static void
  513. shell_dump_win_stack(int argc, char **argv) {
  514.     const char *usage = \
  515.         "usage: dump_win_stack [count]\n"
  516.         "  count            how many items to dump";
  517.     if (argc < 1) {
  518.         fputs(usage, fout);
  519.         return;
  520.     }
  521.     int depth = 5;
  522.     if (argc > 1) {
  523.         depth = strtol(argv[1], NULL, 0);
  524.     }
  525.     for (int i = 0; i < depth; i++) {
  526.         fprintf(fout, "%3i: %3u\n", i, kos_win_stack[i]);
  527.     }
  528. }
  529.  
  530. static void
  531. shell_dump_win_pos(int argc, char **argv) {
  532.     const char *usage = \
  533.         "usage: dump_win_pos [count]\n"
  534.         "  count            how many items to dump";
  535.     if (argc < 1) {
  536.         fputs(usage, fout);
  537.         return;
  538.     }
  539.     int depth = 5;
  540.     if (argc > 1) {
  541.         depth = strtol(argv[1], NULL, 0);
  542.     }
  543.     for (int i = 0; i < depth; i++) {
  544.         fprintf(fout, "%3i: %3u\n", i, kos_win_pos[i]);
  545.     }
  546. }
  547.  
  548. static void
  549. shell_dump_win_map(int argc, char **argv) {
  550.     const char *usage = \
  551.         "usage: dump_win_map";
  552.     (void)argv;
  553.     if (argc < 0) {
  554.         fputs(usage, fout);
  555.         return;
  556.     }
  557.     for (size_t y = 0; y < kos_display.height; y++) {
  558.         for (size_t x = 0; x < kos_display.width; x++) {
  559.             fputc(kos_display.win_map[y * kos_display.width + x] + '0', fout);
  560.         }
  561.         fputc('\n', fout);
  562.     }
  563. }
  564.  
  565. static void
  566. shell_dump_appdata(int argc, char **argv) {
  567.     const char *usage = \
  568.         "usage: dump_appdata <index> [-p]\n"
  569.         "  index            index into appdata array to dump\n"
  570.         "  -p               print fields that are pointers";
  571.     if (argc < 2) {
  572.         fputs(usage, fout);
  573.         return;
  574.     }
  575.     int show_pointers = 0;
  576.     int idx = strtol(argv[1], NULL, 0);
  577.     if (argc > 2 && !strcmp(argv[2], "-p")) {
  578.         show_pointers = 1;
  579.     }
  580.     appdata_t *a = kos_slot_base + idx;
  581.     fprintf(fout, "app_name: %s\n", a->app_name);
  582.     if (show_pointers) {
  583.         fprintf(fout, "process: %p\n", (void*)a->process);
  584.         fprintf(fout, "fpu_state: %p\n", (void*)a->fpu_state);
  585.         fprintf(fout, "exc_handler: %p\n", (void*)a->exc_handler);
  586.     }
  587.     fprintf(fout, "except_mask: %" PRIx32 "\n", a->except_mask);
  588.     if (show_pointers) {
  589.         fprintf(fout, "pl0_stack: %p\n", (void*)a->pl0_stack);
  590.         fprintf(fout, "cursor: %p\n", (void*)a->cursor);
  591.         fprintf(fout, "fd_ev: %p\n", (void*)a->fd_ev);
  592.         fprintf(fout, "bk_ev: %p\n", (void*)a->bk_ev);
  593.         fprintf(fout, "fd_obj: %p\n", (void*)a->fd_obj);
  594.         fprintf(fout, "bk_obj: %p\n", (void*)a->bk_obj);
  595.         fprintf(fout, "saved_esp: %p\n", (void*)a->saved_esp);
  596.     }
  597.     fprintf(fout, "dbg_state: %u\n", a->dbg_state);
  598.     fprintf(fout, "cur_dir: %s\n", a->cur_dir);
  599.     fprintf(fout, "draw_bgr_x: %u\n", a->draw_bgr_x);
  600.     fprintf(fout, "draw_bgr_y: %u\n", a->draw_bgr_y);
  601.     fprintf(fout, "event_mask: %" PRIx32 "\n", a->event_mask);
  602.     fprintf(fout, "terminate_protection: %u\n", a->terminate_protection);
  603.     fprintf(fout, "keyboard_mode: %u\n", a->keyboard_mode);
  604.     fprintf(fout, "captionEncoding: %u\n", a->captionEncoding);
  605.     fprintf(fout, "exec_params: %s\n", a->exec_params);
  606.     fprintf(fout, "wnd_caption: %s\n", a->wnd_caption);
  607.     fprintf(fout, "wnd_clientbox (ltwh): %u %u %u %u\n", a->wnd_clientbox.left,
  608.             a->wnd_clientbox.top, a->wnd_clientbox.width,
  609.             a->wnd_clientbox.height);
  610.     fprintf(fout, "priority: %u\n", a->priority);
  611.  
  612.     fprintf(fout, "in_schedule: prev");
  613.     if (show_pointers) {
  614.         fprintf(fout, " %p", (void*)a->in_schedule.prev);
  615.     }
  616.     fprintf(fout, " (%u), next",
  617.             (appdata_t*)a->in_schedule.prev - kos_slot_base);
  618.     if (show_pointers) {
  619.         fprintf(fout, " %p", (void*)a->in_schedule.next);
  620.     }
  621.     fprintf(fout, " (%u)\n",
  622.             (appdata_t*)a->in_schedule.next - kos_slot_base);
  623. }
  624.  
  625. static void
  626. shell_dump_taskdata(int argc, char **argv) {
  627.     const char *usage = \
  628.         "usage: dump_taskdata <index>\n"
  629.         "  index            index into taskdata array to dump";
  630.     if (argc < 2) {
  631.         fputs(usage, fout);
  632.         return;
  633.     }
  634.     int idx = strtol(argv[1], NULL, 0);
  635.     taskdata_t *t = kos_task_table + idx;
  636.     fprintf(fout, "event_mask: %" PRIx32 "\n", t->event_mask);
  637.     fprintf(fout, "pid: %" PRId32 "\n", t->pid);
  638.     fprintf(fout, "state: 0x%" PRIx8 "\n", t->state);
  639.     fprintf(fout, "wnd_number: %" PRIu8 "\n", t->wnd_number);
  640.     fprintf(fout, "counter_sum: %" PRIu32 "\n", t->counter_sum);
  641.     fprintf(fout, "counter_add: %" PRIu32 "\n", t->counter_add);
  642.     fprintf(fout, "cpu_usage: %" PRIu32 "\n", t->cpu_usage);
  643. }
  644.  
  645. static void
  646. shell_switch_to_thread(int argc, char **argv) {
  647.     const char *usage = \
  648.         "usage: switch_to_thread <tid>\n"
  649.         "  <tid>          thread id to switch to";
  650.     if (argc != 2) {
  651.         fputs(usage, fout);
  652.         return;
  653.     }
  654.     uint8_t tid = strtoul(argv[1], NULL, 0);
  655.     kos_current_slot_idx = tid;
  656.     kos_task_base = kos_task_table + tid;
  657.     kos_current_slot = kos_slot_base + tid;
  658. }
  659.  
  660. static void
  661. shell_set(int argc, char **argv) {
  662.     const char *usage = \
  663.         "usage: set <var> <value>\n"
  664.         "  <var>          variable to set\n"
  665.         "  <value>        decimal or hex value";
  666.     if (argc != 3) {
  667.         fputs(usage, fout);
  668.         return;
  669.     }
  670.     const char *var = argv[1];
  671.     size_t value = strtoul(argv[2], NULL, 0);
  672.     if (!strcmp(var, "redraw_background")) {
  673.         kos_redraw_background = value;
  674.     } else {
  675.         printf("bad option: %s\n", argv[0]);
  676.         puts(usage);
  677.         exit(1);
  678.     }
  679. }
  680.  
  681. static void
  682. shell_new_sys_thread(int argc, char **argv) {
  683.     const char *usage = \
  684.         "usage: new_sys_thread";
  685.     if (!argc) {
  686.         fputs(usage, fout);
  687.         return;
  688.     }
  689.     (void)argv;
  690.     size_t tid = umka_new_sys_threads(0, NULL, NULL);
  691.     fprintf(fout, "tid: %u\n", tid);
  692. }
  693.  
  694. static void
  695. shell_mouse_move(int argc, char **argv) {
  696.     const char *usage = \
  697.         "usage: mouse_move [-l] [-m] [-r] [-x {+|-|=}<value>]"
  698.             "[-y {+|-|=}<value>] [-h {+|-}<value>] [-v {+|-}<value>]\n"
  699.         "  -l             left button is held\n"
  700.         "  -m             middle button is held\n"
  701.         "  -r             right button is held\n"
  702.         "  -x             increase, decrease or set x coordinate\n"
  703.         "  -y             increase, decrease or set y coordinate\n"
  704.         "  -h             scroll horizontally\n"
  705.         "  -v             scroll vertically\n";
  706.     if (!argc) {
  707.         fputs(usage, fout);
  708.         return;
  709.     }
  710.     int lbheld = 0, mbheld = 0, rbheld = 0, xabs = 0, yabs = 0;
  711.     int32_t xmoving = 0, ymoving = 0, hscroll = 0, vscroll = 0;
  712.     int opt;
  713.     optind = 1;
  714.     while ((opt = getopt(argc, argv, "lmrx:y:h:v:")) != -1) {
  715.         switch (opt) {
  716.         case 'l':
  717.             lbheld = 1;
  718.             break;
  719.         case 'm':
  720.             mbheld = 1;
  721.             break;
  722.         case 'r':
  723.             rbheld = 1;
  724.             break;
  725.         case 'x':
  726.             switch (*optarg++) {
  727.             case '=':
  728.                 xabs = 1;
  729.                 __attribute__ ((fallthrough));
  730.             case '+':
  731.                 xmoving = strtol(optarg, NULL, 0);
  732.                 break;
  733.             case '-':
  734.                 xmoving = -strtol(optarg, NULL, 0);
  735.                 break;
  736.             default:
  737.                 fputs(usage, fout);
  738.                 return;
  739.             }
  740.             break;
  741.         case 'y':
  742.             switch (*optarg++) {
  743.             case '=':
  744.                 yabs = 1;
  745.                 __attribute__ ((fallthrough));
  746.             case '+':
  747.                 ymoving = strtol(optarg, NULL, 0);
  748.                 break;
  749.             case '-':
  750.                 ymoving = -strtol(optarg, NULL, 0);
  751.                 break;
  752.             default:
  753.                 fputs(usage, fout);
  754.                 return;
  755.             }
  756.             break;
  757.         case 'h':
  758.             if ((optarg[0] != '+') && (optarg[0] != '-')) {
  759.                 fputs(usage, fout);
  760.                 return;
  761.             }
  762.             hscroll = strtol(optarg, NULL, 0);
  763.             break;
  764.         case 'v':
  765.             if ((optarg[0] != '+') && (optarg[0] != '-')) {
  766.                 fputs(usage, fout);
  767.                 return;
  768.             }
  769.             vscroll = strtol(optarg, NULL, 0);
  770.             break;
  771.         default:
  772.             fputs(usage, fout);
  773.             return;
  774.         }
  775.     }
  776.     COVERAGE_ON();
  777.     umka_mouse_move(lbheld, mbheld, rbheld, xabs, xmoving, yabs, ymoving,
  778.                     hscroll, vscroll);
  779.     COVERAGE_OFF();
  780. }
  781.  
  782. static void
  783. shell_process_info(int argc, char **argv) {
  784.     const char *usage = \
  785.         "usage: process_info <pid>\n"
  786.         "  pid              process id to dump, -1 for self";
  787.     if (argc != 2) {
  788.         fputs(usage, fout);
  789.         return;
  790.     }
  791.     process_information_t info;
  792.     int32_t pid = strtol(argv[1], NULL, 0);
  793.     COVERAGE_ON();
  794.     umka_sys_process_info(pid, &info);
  795.     COVERAGE_OFF();
  796.     fprintf(fout, "cpu_usage: %u\n", info.cpu_usage);
  797.     fprintf(fout, "window_stack_position: %u\n", info.window_stack_position);
  798.     fprintf(fout, "window_stack_value: %u\n", info.window_stack_value);
  799.     fprintf(fout, "process_name: %s\n", info.process_name);
  800.     fprintf(fout, "memory_start: 0x%.8" PRIx32 "\n", info.memory_start);
  801.     fprintf(fout, "used_memory: %u (0x%x)\n", info.used_memory,
  802.             info.used_memory);
  803.     fprintf(fout, "pid: %u\n", info.pid);
  804.     fprintf(fout, "box: %u %u %u %u\n", info.box.left, info.box.top,
  805.             info.box.width, info.box.height);
  806.     fprintf(fout, "slot_state: %u\n", info.slot_state);
  807.     fprintf(fout, "client_box: %u %u %u %u\n", info.client_box.left,
  808.             info.client_box.top, info.client_box.width, info.client_box.height);
  809.     fprintf(fout, "wnd_state: 0x%.2" PRIx8 "\n", info.wnd_state);
  810. }
  811.  
  812. static void
  813. shell_display_number(int argc, char **argv) {
  814.     const char *usage = \
  815.         "usage: display_number <is_pointer> <base> <num_digits> <is_qword>"
  816.             " <show_lead_zeros> <num_or_ptr> <x> <y> <color> <fill_bg> <font>"
  817.             " <draw_to_buf> <scale_factor> <bg_color_or_buf>\n"
  818.         "  is_pointer       if num_or_ptr argument is a pointer\n"
  819.         "  base             0 - dec, 1 - hex, 2 - bin\n"
  820.         "  num_digits       how many digits to print\n"
  821.         "  is_qword         if 1, is_pointer = 1 and num_or_ptr is pointer\n"
  822.         "  show_lead_zeros  0/1\n"
  823.         "  num_or_ptr       number itself or a pointer to it\n"
  824.         "  x                x window coord\n"
  825.         "  y                y window coord\n"
  826.         "  color            argb in hex\n"
  827.         "  fill_bg          0/1\n"
  828.         "  font             0 = 6x9, 1 = 8x16\n"
  829.         "  draw_to_buf      0/1\n"
  830.         "  scale_factor     0 = x1, ..., 7 = x8\n"
  831.         "  bg_color_or_buf  depending on flags fill_bg and draw_to_buf";
  832.     if (argc != 15) {
  833.         fputs(usage, fout);
  834.         return;
  835.     }
  836.     int is_pointer = strtoul(argv[1], NULL, 0);
  837.     int base = strtoul(argv[2], NULL, 0);
  838.     if (base == 10) base = 0;
  839.     else if (base == 16) base = 1;
  840.     else if (base == 2) base = 2;
  841.     else base = 0;
  842.     size_t digits_to_display = strtoul(argv[3], NULL, 0);
  843.     int is_qword = strtoul(argv[4], NULL, 0);
  844.     int show_leading_zeros = strtoul(argv[5], NULL, 0);
  845.     uintptr_t number_or_pointer = strtoul(argv[6], NULL, 0);
  846.     size_t x = strtoul(argv[7], NULL, 0);
  847.     size_t y = strtoul(argv[8], NULL, 0);
  848.     uint32_t color = strtoul(argv[9], NULL, 16);
  849.     int fill_background = strtoul(argv[10], NULL, 0);
  850.     int font = strtoul(argv[11], NULL, 0);
  851.     int draw_to_buffer = strtoul(argv[12], NULL, 0);
  852.     int scale_factor = strtoul(argv[13], NULL, 0);
  853.     uintptr_t background_color_or_buffer = strtoul(argv[14], NULL, 16);
  854.     COVERAGE_ON();
  855.     umka_sys_display_number(is_pointer, base, digits_to_display, is_qword,
  856.                             show_leading_zeros, number_or_pointer, x, y, color,
  857.                             fill_background, font, draw_to_buffer, scale_factor,
  858.                             background_color_or_buffer);
  859.     COVERAGE_OFF();
  860. }
  861.  
  862. static void
  863. shell_set_window_colors(int argc, char **argv) {
  864.     const char *usage = \
  865.         "usage: set_window_colors <frame> <grab> <work_3d_dark> <work_3d_light>"
  866.             " <grab_text> <work> <work_button> <work_button_text> <work_text>"
  867.             " <work_graph>\n"
  868.         "  *                all colors are in hex";
  869.     if (argc != (1 + sizeof(system_colors_t)/4)) {
  870.         fputs(usage, fout);
  871.         return;
  872.     }
  873.     system_colors_t colors;
  874.     colors.frame            = strtoul(argv[1], NULL, 16);
  875.     colors.grab             = strtoul(argv[2], NULL, 16);
  876.     colors.work_3d_dark     = strtoul(argv[3], NULL, 16);
  877.     colors.work_3d_light    = strtoul(argv[4], NULL, 16);
  878.     colors.grab_text        = strtoul(argv[5], NULL, 16);
  879.     colors.work             = strtoul(argv[6], NULL, 16);
  880.     colors.work_button      = strtoul(argv[7], NULL, 16);
  881.     colors.work_button_text = strtoul(argv[8], NULL, 16);
  882.     colors.work_text        = strtoul(argv[9], NULL, 16);
  883.     colors.work_graph       = strtoul(argv[10], NULL, 16);
  884.     COVERAGE_ON();
  885.     umka_sys_set_window_colors(&colors);
  886.     COVERAGE_OFF();
  887. }
  888.  
  889. static void
  890. shell_get_window_colors(int argc, char **argv) {
  891.     const char *usage = \
  892.         "usage: get_window_colors";
  893.     if (argc != 1) {
  894.         fputs(usage, fout);
  895.         return;
  896.     }
  897.     (void)argv;
  898.     system_colors_t colors;
  899.     memset(&colors, 0xaa, sizeof(colors));
  900.     COVERAGE_ON();
  901.     umka_sys_get_window_colors(&colors);
  902.     COVERAGE_OFF();
  903.     fprintf(fout, "0x%.8" PRIx32 " frame\n", colors.frame);
  904.     fprintf(fout, "0x%.8" PRIx32 " grab\n", colors.grab);
  905.     fprintf(fout, "0x%.8" PRIx32 " work_3d_dark\n", colors.work_3d_dark);
  906.     fprintf(fout, "0x%.8" PRIx32 " work_3d_light\n", colors.work_3d_light);
  907.     fprintf(fout, "0x%.8" PRIx32 " grab_text\n", colors.grab_text);
  908.     fprintf(fout, "0x%.8" PRIx32 " work\n", colors.work);
  909.     fprintf(fout, "0x%.8" PRIx32 " work_button\n", colors.work_button);
  910.     fprintf(fout, "0x%.8" PRIx32 " work_button_text\n",
  911.             colors.work_button_text);
  912.     fprintf(fout, "0x%.8" PRIx32 " work_text\n", colors.work_text);
  913.     fprintf(fout, "0x%.8" PRIx32 " work_graph\n", colors.work_graph);
  914. }
  915.  
  916. static void
  917. shell_get_skin_height(int argc, char **argv) {
  918.     const char *usage = \
  919.         "usage: get_skin_height";
  920.     if (argc != 1) {
  921.         fputs(usage, fout);
  922.         return;
  923.     }
  924.     (void)argv;
  925.     COVERAGE_ON();
  926.     uint32_t skin_height = umka_sys_get_skin_height();
  927.     COVERAGE_OFF();
  928.     fprintf(fout, "%" PRIu32 "\n", skin_height);
  929. }
  930.  
  931. static void
  932. shell_get_screen_area(int argc, char **argv) {
  933.     const char *usage = \
  934.         "usage: get_screen_area";
  935.     if (argc != 1) {
  936.         fputs(usage, fout);
  937.         return;
  938.     }
  939.     (void)argv;
  940.     rect_t wa;
  941.     COVERAGE_ON();
  942.     umka_sys_get_screen_area(&wa);
  943.     COVERAGE_OFF();
  944.     fprintf(fout, "%" PRIu32 " left\n", wa.left);
  945.     fprintf(fout, "%" PRIu32 " top\n", wa.top);
  946.     fprintf(fout, "%" PRIu32 " right\n", wa.right);
  947.     fprintf(fout, "%" PRIu32 " bottom\n", wa.bottom);
  948. }
  949.  
  950. static void
  951. shell_set_screen_area(int argc, char **argv) {
  952.     const char *usage = \
  953.         "usage: set_screen_area <left> <top> <right> <bottom>\n"
  954.         "  left             left x coord\n"
  955.         "  top              top y coord\n"
  956.         "  right            right x coord (not length!)\n"
  957.         "  bottom           bottom y coord";
  958.     if (argc != 5) {
  959.         fputs(usage, fout);
  960.         return;
  961.     }
  962.     rect_t wa;
  963.     wa.left   = strtoul(argv[1], NULL, 0);
  964.     wa.top    = strtoul(argv[2], NULL, 0);
  965.     wa.right  = strtoul(argv[3], NULL, 0);
  966.     wa.bottom = strtoul(argv[4], NULL, 0);
  967.     COVERAGE_ON();
  968.     umka_sys_set_screen_area(&wa);
  969.     COVERAGE_OFF();
  970. }
  971.  
  972. static void
  973. shell_get_skin_margins(int argc, char **argv) {
  974.     const char *usage = \
  975.         "usage: get_skin_margins";
  976.     if (argc != 1) {
  977.         fputs(usage, fout);
  978.         return;
  979.     }
  980.     (void)argv;
  981.     rect_t wa;
  982.     COVERAGE_ON();
  983.     umka_sys_get_skin_margins(&wa);
  984.     COVERAGE_OFF();
  985.     fprintf(fout, "%" PRIu32 " left\n", wa.left);
  986.     fprintf(fout, "%" PRIu32 " top\n", wa.top);
  987.     fprintf(fout, "%" PRIu32 " right\n", wa.right);
  988.     fprintf(fout, "%" PRIu32 " bottom\n", wa.bottom);
  989. }
  990.  
  991. static void
  992. shell_set_button_style(int argc, char **argv) {
  993.     const char *usage = \
  994.         "usage: set_button_style <style>\n"
  995.         "  style            0 - flat, 1 - 3d";
  996.     if (argc != 2) {
  997.         fputs(usage, fout);
  998.         return;
  999.     }
  1000.     uint32_t style = strtoul(argv[1], NULL, 0);
  1001.     COVERAGE_ON();
  1002.     umka_sys_set_button_style(style);
  1003.     COVERAGE_OFF();
  1004. }
  1005.  
  1006. static void
  1007. shell_set_skin(int argc, char **argv) {
  1008.     const char *usage = \
  1009.         "usage: set_skin <path>\n"
  1010.         "  path             i.e. /rd/1/DEFAULT.SKN";
  1011.     if (argc != 2) {
  1012.         fputs(usage, fout);
  1013.         return;
  1014.     }
  1015.     const char *path = argv[1];
  1016.     COVERAGE_ON();
  1017.     int32_t status = umka_sys_set_skin(path);
  1018.     COVERAGE_OFF();
  1019.     fprintf(fout, "status: %" PRIi32 "\n", status);
  1020. }
  1021.  
  1022. static void
  1023. shell_get_font_smoothing(int argc, char **argv) {
  1024.     const char *usage = \
  1025.         "usage: get_font_smoothing";
  1026.     if (argc != 1) {
  1027.         fputs(usage, fout);
  1028.         return;
  1029.     }
  1030.     (void)argv;
  1031.     const char *names[] = {"off", "anti-aliasing", "subpixel"};
  1032.     COVERAGE_ON();
  1033.     int type = umka_sys_get_font_smoothing();
  1034.     COVERAGE_OFF();
  1035.     fprintf(fout, "font smoothing: %i - %s\n", type, names[type]);
  1036. }
  1037.  
  1038. static void
  1039. shell_set_font_smoothing(int argc, char **argv) {
  1040.     const char *usage = \
  1041.         "usage: set_font_smoothing <mode>\n"
  1042.         "  mode             0 - off, 1 - gray AA, 2 - subpixel AA";
  1043.     if (argc != 2) {
  1044.         fputs(usage, fout);
  1045.         return;
  1046.     }
  1047.     int type = strtol(argv[1], NULL, 0);
  1048.     COVERAGE_ON();
  1049.     umka_sys_set_font_smoothing(type);
  1050.     COVERAGE_OFF();
  1051. }
  1052.  
  1053. static void
  1054. shell_get_font_size(int argc, char **argv) {
  1055.     const char *usage = \
  1056.         "usage: get_font_size";
  1057.     if (argc != 1) {
  1058.         fputs(usage, fout);
  1059.         return;
  1060.     }
  1061.     (void)argv;
  1062.     COVERAGE_ON();
  1063.     size_t size = umka_sys_get_font_size();
  1064.     COVERAGE_OFF();
  1065.     fprintf(fout, "%upx\n", size);
  1066. }
  1067.  
  1068. static void
  1069. shell_set_font_size(int argc, char **argv) {
  1070.     const char *usage = \
  1071.         "usage: set_font_size <size>\n"
  1072.         "  size             in pixels";
  1073.     if (argc != 2) {
  1074.         fputs(usage, fout);
  1075.         return;
  1076.     }
  1077.     uint32_t size = strtoul(argv[1], NULL, 0);
  1078.     COVERAGE_ON();
  1079.     umka_sys_set_font_size(size);
  1080.     COVERAGE_OFF();
  1081. }
  1082.  
  1083. static void
  1084. shell_button(int argc, char **argv) {
  1085.     const char *usage = \
  1086.         "usage: button <x> <xsize> <y> <ysize> <id> <color> <draw_button>"
  1087.             " <draw_frame>\n"
  1088.         "  x                x\n"
  1089.         "  xsize            may be size-1, check it\n"
  1090.         "  y                y\n"
  1091.         "  ysize            may be size-1, check it\n"
  1092.         "  id               24-bit\n"
  1093.         "  color            hex\n"
  1094.         "  draw_button      0/1\n"
  1095.         "  draw_frame       0/1";
  1096.     if (argc != 9) {
  1097.         fputs(usage, fout);
  1098.         return;
  1099.     }
  1100.     size_t x     = strtoul(argv[1], NULL, 0);
  1101.     size_t xsize = strtoul(argv[2], NULL, 0);
  1102.     size_t y     = strtoul(argv[3], NULL, 0);
  1103.     size_t ysize = strtoul(argv[4], NULL, 0);
  1104.     uint32_t button_id = strtoul(argv[5], NULL, 0);
  1105.     uint32_t color = strtoul(argv[6], NULL, 16);
  1106.     int draw_button = strtoul(argv[7], NULL, 0);
  1107.     int draw_frame = strtoul(argv[8], NULL, 0);
  1108.     COVERAGE_ON();
  1109.     umka_sys_button(x, xsize, y, ysize, button_id, draw_button, draw_frame,
  1110.                     color);
  1111.     COVERAGE_OFF();
  1112. }
  1113.  
  1114. static void
  1115. shell_put_image(int argc, char **argv) {
  1116.     const char *usage = \
  1117.         "usage: put_image <file> <xsize> <ysize> <x> <y>\n"
  1118.         "  file             file with rgb triplets\n"
  1119.         "  xsize            x size\n"
  1120.         "  ysize            y size\n"
  1121.         "  x                x coord\n"
  1122.         "  y                y coord";
  1123.     if (argc != 6) {
  1124.         fputs(usage, fout);
  1125.         return;
  1126.     }
  1127.     FILE *f = fopen(argv[1], "r");
  1128.     fseek(f, 0, SEEK_END);
  1129.     size_t fsize = ftell(f);
  1130.     rewind(f);
  1131.     uint8_t *image = (uint8_t*)malloc(fsize);
  1132.     fread(image, fsize, 1, f);
  1133.     fclose(f);
  1134.     size_t xsize = strtoul(argv[2], NULL, 0);
  1135.     size_t ysize = strtoul(argv[3], NULL, 0);
  1136.     size_t x = strtoul(argv[4], NULL, 0);
  1137.     size_t y = strtoul(argv[5], NULL, 0);
  1138.     COVERAGE_ON();
  1139.     umka_sys_put_image(image, xsize, ysize, x, y);
  1140.     COVERAGE_OFF();
  1141.     free(image);
  1142. }
  1143.  
  1144. static void
  1145. shell_put_image_palette(int argc, char **argv) {
  1146.     const char *usage = \
  1147.         "usage: put_image_palette <file> <xsize> <ysize> <x> <y> <bpp>"
  1148.             " <row_offset>\n"
  1149.         "  file             path/to/file, contents according tp bpp argument\n"
  1150.         "  xsize            x size\n"
  1151.         "  ysize            y size\n"
  1152.         "  x                x coord\n"
  1153.         "  y                y coord\n"
  1154.         "  bpp              bits per pixel\n"
  1155.         "  row_offset       in bytes";
  1156.     if (argc != 8) {
  1157.         fputs(usage, fout);
  1158.         return;
  1159.     }
  1160.     FILE *f = fopen(argv[1], "r");
  1161.     fseek(f, 0, SEEK_END);
  1162.     size_t fsize = ftell(f);
  1163.     rewind(f);
  1164.     uint8_t *image = (uint8_t*)malloc(fsize);
  1165.     fread(image, fsize, 1, f);
  1166.     fclose(f);
  1167.     size_t xsize = strtoul(argv[2], NULL, 0);
  1168.     size_t ysize = strtoul(argv[3], NULL, 0);
  1169.     size_t x = strtoul(argv[4], NULL, 0);
  1170.     size_t y = strtoul(argv[5], NULL, 0);
  1171.     size_t bpp = strtoul(argv[6], NULL, 0);
  1172.     void *palette = NULL;
  1173.     size_t row_offset = strtoul(argv[7], NULL, 0);
  1174.     COVERAGE_ON();
  1175.     umka_sys_put_image_palette(image, xsize, ysize, x, y, bpp, palette,
  1176.                                row_offset);
  1177.     COVERAGE_OFF();
  1178.     free(image);
  1179. }
  1180.  
  1181. static void
  1182. shell_draw_rect(int argc, char **argv) {
  1183.     const char *usage = \
  1184.         "usage: draw_rect <x> <xsize> <y> <ysize> <color> [-g]\n"
  1185.         "  x                x coord\n"
  1186.         "  xsize            x size\n"
  1187.         "  y                y coord\n"
  1188.         "  ysize            y size\n"
  1189.         "  color            in hex\n"
  1190.         "  -g               0/1 - gradient";
  1191.     if (argc < 6) {
  1192.         fputs(usage, fout);
  1193.         return;
  1194.     }
  1195.     size_t x     = strtoul(argv[1], NULL, 0);
  1196.     size_t xsize = strtoul(argv[2], NULL, 0);
  1197.     size_t y     = strtoul(argv[3], NULL, 0);
  1198.     size_t ysize = strtoul(argv[4], NULL, 0);
  1199.     uint32_t color = strtoul(argv[5], NULL, 16);
  1200.     int gradient = (argc == 7) && !strcmp(argv[6], "-g");
  1201.     COVERAGE_ON();
  1202.     umka_sys_draw_rect(x, xsize, y, ysize, color, gradient);
  1203.     COVERAGE_OFF();
  1204. }
  1205.  
  1206. static void
  1207. shell_get_screen_size(int argc, char **argv) {
  1208.     const char *usage = \
  1209.         "usage: get_screen_size";
  1210.     if (argc != 1) {
  1211.         fputs(usage, fout);
  1212.         return;
  1213.     }
  1214.     (void)argv;
  1215.     uint32_t xsize, ysize;
  1216.     COVERAGE_ON();
  1217.     umka_sys_get_screen_size(&xsize, &ysize);
  1218.     COVERAGE_OFF();
  1219.     fprintf(fout, "%" PRIu32 "x%" PRIu32 "\n", xsize, ysize);
  1220. }
  1221.  
  1222. static void
  1223. shell_draw_line(int argc, char **argv) {
  1224.     const char *usage = \
  1225.         "usage: draw_line <xbegin> <xend> <ybegin> <yend> <color> [-i]\n"
  1226.         "  xbegin           x left coord\n"
  1227.         "  xend             x right coord\n"
  1228.         "  ybegin           y top coord\n"
  1229.         "  yend             y bottom coord\n"
  1230.         "  color            hex\n"
  1231.         "  -i               inverted color";
  1232.     if (argc < 6) {
  1233.         fputs(usage, fout);
  1234.         return;
  1235.     }
  1236.     size_t x    = strtoul(argv[1], NULL, 0);
  1237.     size_t xend = strtoul(argv[2], NULL, 0);
  1238.     size_t y    = strtoul(argv[3], NULL, 0);
  1239.     size_t yend = strtoul(argv[4], NULL, 0);
  1240.     uint32_t color = strtoul(argv[5], NULL, 16);
  1241.     int invert = (argc == 7) && !strcmp(argv[6], "-i");
  1242.     COVERAGE_ON();
  1243.     umka_sys_draw_line(x, xend, y, yend, color, invert);
  1244.     COVERAGE_OFF();
  1245. }
  1246.  
  1247. static void
  1248. shell_set_window_caption(int argc, char **argv) {
  1249.     const char *usage = \
  1250.         "usage: set_window_caption <caption> <encoding>\n"
  1251.         "  caption          asciiz string\n"
  1252.         "  encoding         1 = cp866, 2 = UTF-16LE, 3 = UTF-8";
  1253.     if (argc != 3) {
  1254.         fputs(usage, fout);
  1255.         return;
  1256.     }
  1257.     const char *caption = argv[1];
  1258.     int encoding = strtoul(argv[2], NULL, 0);
  1259.     COVERAGE_ON();
  1260.     umka_sys_set_window_caption(caption, encoding);
  1261.     COVERAGE_OFF();
  1262. }
  1263.  
  1264. static void
  1265. shell_draw_window(int argc, char **argv) {
  1266.     const char *usage = \
  1267.         "usage: draw_window <x> <xsize> <y> <ysize> <color> <has_caption>"
  1268.             " <client_relative> <fill_workarea> <gradient_fill> <movable>"
  1269.             " <style> <caption>\n"
  1270.         "  x                x coord\n"
  1271.         "  xsize            x size\n"
  1272.         "  y                y coord\n"
  1273.         "  ysize            y size\n"
  1274.         "  color            hex\n"
  1275.         "  has_caption      0/1\n"
  1276.         "  client_relative  0/1\n"
  1277.         "  fill_workarea    0/1\n"
  1278.         "  gradient_fill    0/1\n"
  1279.         "  movable          0/1\n"
  1280.         "  style            1 - draw nothing, 3 - skinned, 4 - skinned fixed\n"
  1281.         "  caption          asciiz";
  1282.     if (argc != 13) {
  1283.         fputs(usage, fout);
  1284.         return;
  1285.     }
  1286.     size_t x     = strtoul(argv[1], NULL, 0);
  1287.     size_t xsize = strtoul(argv[2], NULL, 0);
  1288.     size_t y     = strtoul(argv[3], NULL, 0);
  1289.     size_t ysize = strtoul(argv[4], NULL, 0);
  1290.     uint32_t color = strtoul(argv[5], NULL, 16);
  1291.     int has_caption = strtoul(argv[6], NULL, 0);
  1292.     int client_relative = strtoul(argv[7], NULL, 0);
  1293.     int fill_workarea = strtoul(argv[8], NULL, 0);
  1294.     int gradient_fill = strtoul(argv[9], NULL, 0);
  1295.     int movable = strtoul(argv[10], NULL, 0);
  1296.     int style = strtoul(argv[11], NULL, 0);
  1297.     const char *caption = argv[12];
  1298.     COVERAGE_ON();
  1299.     umka_sys_draw_window(x, xsize, y, ysize, color, has_caption,
  1300.                          client_relative, fill_workarea, gradient_fill, movable,
  1301.                          style, caption);
  1302.     COVERAGE_OFF();
  1303. }
  1304.  
  1305. static void
  1306. shell_window_redraw(int argc, char **argv) {
  1307.     const char *usage = \
  1308.         "usage: window_redraw <1|2>\n"
  1309.         "  1                begin\n"
  1310.         "  2                end";
  1311.     if (argc != 2) {
  1312.         fputs(usage, fout);
  1313.         return;
  1314.     }
  1315.     int begin_end = strtoul(argv[1], NULL, 0);
  1316.     COVERAGE_ON();
  1317.     umka_sys_window_redraw(begin_end);
  1318.     COVERAGE_OFF();
  1319. }
  1320.  
  1321. static void
  1322. shell_move_window(int argc, char **argv) {
  1323.     const char *usage = \
  1324.         "usage: move_window <x> <y> <xsize> <ysize>\n"
  1325.         "  x                new x coord\n"
  1326.         "  y                new y coord\n"
  1327.         "  xsize            x size -1\n"
  1328.         "  ysize            y size -1";
  1329.     if (argc != 5) {
  1330.         fputs(usage, fout);
  1331.         return;
  1332.     }
  1333.     size_t x      = strtoul(argv[1], NULL, 0);
  1334.     size_t y      = strtoul(argv[2], NULL, 0);
  1335.     ssize_t xsize = strtol(argv[3], NULL, 0);
  1336.     ssize_t ysize = strtol(argv[4], NULL, 0);
  1337.     COVERAGE_ON();
  1338.     umka_sys_move_window(x, y, xsize, ysize);
  1339.     COVERAGE_OFF();
  1340. }
  1341.  
  1342. static void
  1343. shell_blit_bitmap(int argc, char **argv) {
  1344.     const char *usage = \
  1345.         "usage: blit_bitmap <dstx> <dsty> <dstxsize> <dstysize> <srcx> <srcy>"
  1346.             " <srcxsize> <srcysize> <operation> <background> <transparent>"
  1347.             " <client_relative> <row_length>\n"
  1348.         "  dstx             dst rect x offset, window-relative\n"
  1349.         "  dsty             dst rect y offset, window-relative\n"
  1350.         "  dstxsize         dst rect width\n"
  1351.         "  dstysize         dst rect height\n"
  1352.         "  srcx             src rect x offset, window-relative\n"
  1353.         "  srcy             src rect y offset, window-relative\n"
  1354.         "  srcxsize         src rect width\n"
  1355.         "  srcysize         src rect height\n"
  1356.         "  operation        0 - copy\n"
  1357.         "  background       0/1 - blit into background surface\n"
  1358.         "  transparent      0/1\n"
  1359.         "  client_relative  0/1\n"
  1360.         "  row_length       in bytes";
  1361.     if (argc != 15) {
  1362.         fputs(usage, fout);
  1363.         return;
  1364.     }
  1365.     const char *fname = argv[1];
  1366.     FILE *f = fopen(fname, "r");
  1367.     if (!f) {
  1368.         fprintf(fout, "[!] can't open file '%s': %s\n", fname, strerror(errno));
  1369.         return;
  1370.     }
  1371.     fseek(f, 0, SEEK_END);
  1372.     size_t fsize = ftell(f);
  1373.     rewind(f);
  1374.     uint8_t *image = (uint8_t*)malloc(fsize);
  1375.     fread(image, fsize, 1, f);
  1376.     fclose(f);
  1377.     size_t dstx     = strtoul(argv[2], NULL, 0);
  1378.     size_t dsty     = strtoul(argv[3], NULL, 0);
  1379.     size_t dstxsize = strtoul(argv[4], NULL, 0);
  1380.     size_t dstysize = strtoul(argv[5], NULL, 0);
  1381.     size_t srcx     = strtoul(argv[6], NULL, 0);
  1382.     size_t srcy     = strtoul(argv[7], NULL, 0);
  1383.     size_t srcxsize = strtoul(argv[8], NULL, 0);
  1384.     size_t srcysize = strtoul(argv[9], NULL, 0);
  1385.     int operation   = strtoul(argv[10], NULL, 0);
  1386.     int background  = strtoul(argv[11], NULL, 0);
  1387.     int transparent = strtoul(argv[12], NULL, 0);
  1388.     int client_relative = strtoul(argv[13], NULL, 0);
  1389.     int row_length = strtoul(argv[14], NULL, 0);
  1390.     uint32_t params[] = {dstx, dsty, dstxsize, dstysize, srcx, srcy, srcxsize,
  1391.                          srcysize, (uintptr_t)image, row_length};
  1392.     COVERAGE_ON();
  1393.     umka_sys_blit_bitmap(operation, background, transparent, client_relative,
  1394.                          params);
  1395.     COVERAGE_OFF();
  1396.     free(image);
  1397. }
  1398.  
  1399. static void
  1400. shell_scrot(int argc, char **argv) {
  1401.     const char *usage = \
  1402.         "usage: scrot <file>\n"
  1403.         "  file             path/to/file in png format";
  1404.     if (argc != 2) {
  1405.         fputs(usage, fout);
  1406.         return;
  1407.     }
  1408.     uint32_t xsize, ysize;
  1409.     COVERAGE_ON();
  1410.     umka_sys_get_screen_size(&xsize, &ysize);
  1411.     COVERAGE_OFF();
  1412.  
  1413.     uint32_t *lfb = (uint32_t*)kos_lfb_base;    // assume 32bpp
  1414.     for (size_t y = 0; y < ysize; y++) {
  1415.         for (size_t x = 0; x < xsize; x++) {
  1416.             *lfb++ |= 0xff000000;
  1417.         }
  1418.     }
  1419.  
  1420.     unsigned error = lodepng_encode32_file(argv[1], kos_lfb_base, xsize, ysize);
  1421.     if(error) fprintf(fout, "error %u: %s\n", error, lodepng_error_text(error));
  1422. }
  1423.  
  1424. static void
  1425. shell_cd(int argc, char **argv) {
  1426.     const char *usage = \
  1427.         "usage: cd <path>\n"
  1428.         "  path             path/to/dir";
  1429.     if (argc != 2) {
  1430.         fputs(usage, fout);
  1431.         return;
  1432.     }
  1433.     COVERAGE_ON();
  1434.     umka_sys_set_cwd(argv[1]);
  1435.     COVERAGE_OFF();
  1436.     cur_dir_changed = true;
  1437. }
  1438.  
  1439. static void
  1440. ls_range(f7080s1arg_t *fX0, f70or80_t f70or80) {
  1441.     f7080ret_t r;
  1442.     size_t bdfe_len = (fX0->encoding == CP866) ? BDFE_LEN_CP866 :
  1443.                                                  BDFE_LEN_UNICODE;
  1444.     uint32_t requested = fX0->size;
  1445.     if (fX0->size > MAX_DIRENTS_TO_READ) {
  1446.         fX0->size = MAX_DIRENTS_TO_READ;
  1447.     }
  1448.     for (; requested; requested -= fX0->size) {
  1449.         if (fX0->size > requested) {
  1450.             fX0->size = requested;
  1451.         }
  1452.         COVERAGE_ON();
  1453.         umka_sys_lfn(fX0, &r, f70or80);
  1454.         COVERAGE_OFF();
  1455.         fX0->offset += fX0->size;
  1456.         print_f70_status(&r, 1);
  1457.         f7080s1info_t *dir = fX0->buf;
  1458.         int ok = (r.count <= fX0->size);
  1459.         ok &= (dir->cnt == r.count);
  1460.         ok &= (r.status == ERROR_SUCCESS && r.count == fX0->size)
  1461.               || (r.status == ERROR_END_OF_FILE && r.count < fX0->size);
  1462.         assert(ok);
  1463.         if (!ok)
  1464.             break;
  1465.         bdfe_t *bdfe = dir->bdfes;
  1466.         for (size_t i = 0; i < dir->cnt; i++) {
  1467.             char fattr[KF_ATTR_CNT+1];
  1468.             convert_f70_file_attr(bdfe->attr, fattr);
  1469.             fprintf(fout, "%s %s\n", fattr, bdfe->name);
  1470.             bdfe = (bdfe_t*)((uintptr_t)bdfe + bdfe_len);
  1471.         }
  1472.         if (r.status == ERROR_END_OF_FILE) {
  1473.             break;
  1474.         }
  1475.     }
  1476. }
  1477.  
  1478. static void
  1479. ls_all(f7080s1arg_t *fX0, f70or80_t f70or80) {
  1480.     f7080ret_t r;
  1481.     size_t bdfe_len = (fX0->encoding == CP866) ? BDFE_LEN_CP866 :
  1482.                                                  BDFE_LEN_UNICODE;
  1483.     while (true) {
  1484.         COVERAGE_ON();
  1485.         umka_sys_lfn(fX0, &r, f70or80);
  1486.         COVERAGE_OFF();
  1487.         print_f70_status(&r, 1);
  1488.         assert((r.status == ERROR_SUCCESS && r.count == fX0->size)
  1489.               || (r.status == ERROR_END_OF_FILE && r.count < fX0->size));
  1490.         f7080s1info_t *dir = fX0->buf;
  1491.         fX0->offset += dir->cnt;
  1492.         int ok = (r.count <= fX0->size);
  1493.         ok &= (dir->cnt == r.count);
  1494.         ok &= (r.status == ERROR_SUCCESS && r.count == fX0->size)
  1495.               || (r.status == ERROR_END_OF_FILE && r.count < fX0->size);
  1496.         assert(ok);
  1497.         if (!ok)
  1498.             break;
  1499.         fprintf(fout, "total = %"PRIi32"\n", dir->total_cnt);
  1500.         bdfe_t *bdfe = dir->bdfes;
  1501.         for (size_t i = 0; i < dir->cnt; i++) {
  1502.             char fattr[KF_ATTR_CNT+1];
  1503.             convert_f70_file_attr(bdfe->attr, fattr);
  1504.             fprintf(fout, "%s %s\n", fattr, bdfe->name);
  1505.             bdfe = (bdfe_t*)((uintptr_t)bdfe + bdfe_len);
  1506.         }
  1507.         if (r.status == ERROR_END_OF_FILE) {
  1508.             break;
  1509.         }
  1510.     }
  1511. }
  1512.  
  1513. static fs_enc_t
  1514. parse_encoding(const char *str) {
  1515.     fs_enc_t enc;
  1516.     if (!strcmp(str, "default")) {
  1517.         enc = DEFAULT_ENCODING;
  1518.     } else if (!strcmp(str, "cp866")) {
  1519.         enc = CP866;
  1520.     } else if (!strcmp(str, "utf16")) {
  1521.         enc = UTF16;
  1522.     } else if (!strcmp(str, "utf8")) {
  1523.         enc = UTF8;
  1524.     } else {
  1525.         enc = INVALID_ENCODING;
  1526.     }
  1527.     return enc;
  1528. }
  1529.  
  1530. static void
  1531. shell_exec(int argc, char **argv) {
  1532.     const char *usage = \
  1533.         "usage: exec <file>\n"
  1534.         "  file           executable to run";
  1535.     if (!argc) {
  1536.         fputs(usage, fout);
  1537.         return;
  1538.     }
  1539.     f7080s7arg_t fX0 = {.sf = 7};
  1540.     f7080ret_t r;
  1541.     int opt = 1;
  1542.     fX0.u.f70.zero = 0;
  1543.     fX0.u.f70.path = argv[opt++];
  1544.     fX0.flags = 0;
  1545.     fX0.params = "test";
  1546.  
  1547.     COVERAGE_ON();
  1548.     umka_sys_lfn(&fX0, &r, F70);
  1549.     COVERAGE_OFF();
  1550.     if (r.status < 0) {
  1551.         r.status = -r.status;
  1552.     } else {
  1553.         fprintf(fout, "pid: %" PRIu32 "\n", r.status);
  1554.         r.status = 0;
  1555.     }
  1556.     print_f70_status(&r, 1);
  1557. }
  1558.  
  1559. static void
  1560. shell_ls(int argc, char **argv, const char *usage, f70or80_t f70or80) {
  1561.     if (!argc) {
  1562.         fputs(usage, fout);
  1563.         return;
  1564.     }
  1565.     int opt;
  1566.     optind = 1;
  1567.     const char *optstring = (f70or80 == F70) ? "f:c:e:" : "f:c:e:p:";
  1568.     const char *path = ".";
  1569.     uint32_t readdir_enc = DEFAULT_READDIR_ENCODING;
  1570.     uint32_t path_enc = DEFAULT_PATH_ENCODING;
  1571.     uint32_t from_idx = 0, count = MAX_DIRENTS_TO_READ;
  1572.     if (argc > 1 && *argv[optind] != '-') {
  1573.         path = argv[optind++];
  1574.     }
  1575.     while ((opt = getopt(argc, argv, optstring)) != -1) {
  1576.         switch (opt) {
  1577.         case 'f':
  1578.             from_idx = strtoul(optarg, NULL, 0);
  1579.             break;
  1580.         case 'c':
  1581.             count = strtoul(optarg, NULL, 0);
  1582.             break;
  1583.         case 'e':
  1584.             readdir_enc = parse_encoding(optarg);
  1585.             break;
  1586.         case 'p':
  1587.             path_enc = parse_encoding(optarg);
  1588.             break;
  1589.         default:
  1590.             fputs(usage, fout);
  1591.             return;
  1592.         }
  1593.     }
  1594.  
  1595.     size_t bdfe_len = (readdir_enc <= CP866) ? BDFE_LEN_CP866 :
  1596.                                                BDFE_LEN_UNICODE;
  1597.     f7080s1info_t *dir = (f7080s1info_t*)malloc(sizeof(f7080s1info_t) +
  1598.                                                 bdfe_len * MAX_DIRENTS_TO_READ);
  1599.     f7080s1arg_t fX0 = {.sf = 1, .offset = from_idx, .encoding = readdir_enc,
  1600.                         .size = count, .buf = dir};
  1601.     if (f70or80 == F70) {
  1602.         fX0.u.f70.zero = 0;
  1603.         fX0.u.f70.path = path;
  1604.     } else {
  1605.         fX0.u.f80.path_encoding = path_enc;
  1606.         fX0.u.f80.path = path;
  1607.     }
  1608.     if (count != MAX_DIRENTS_TO_READ) {
  1609.         ls_range(&fX0, f70or80);
  1610.     } else {
  1611.         ls_all(&fX0, f70or80);
  1612.     }
  1613.     free(dir);
  1614.     return;
  1615. }
  1616.  
  1617. static void
  1618. shell_ls70(int argc, char **argv) {
  1619.     const char *usage = \
  1620.         "usage: ls70 [dir] [option]...\n"
  1621.         "  -f number        index of the first dir entry to read\n"
  1622.         "  -c number        number of dir entries to read\n"
  1623.         "  -e encoding      cp866|utf16|utf8\n"
  1624.         "                   return directory listing in this encoding";
  1625.     shell_ls(argc, argv, usage, F70);
  1626. }
  1627.  
  1628. static void
  1629. shell_ls80(int argc, char **argv) {
  1630.     const char *usage = \
  1631.         "usage: ls80 [dir] [option]...\n"
  1632.         "  -f number        index of the first dir entry to read\n"
  1633.         "  -c number        number of dir entries to read\n"
  1634.         "  -e encoding      cp866|utf16|utf8\n"
  1635.         "                   return directory listing in this encoding\n"
  1636.         "  -p encoding      cp866|utf16|utf8\n"
  1637.         "                   path to dir is specified in this encoding";
  1638.     shell_ls(argc, argv, usage, F80);
  1639. }
  1640.  
  1641. static void
  1642. shell_stat(int argc, char **argv, f70or80_t f70or80) {
  1643.     const char *usage = \
  1644.         "usage: stat <file>\n"
  1645.         "  file             path/to/file";
  1646.     if (argc != 2) {
  1647.         fputs(usage, fout);
  1648.         return;
  1649.     }
  1650.     f7080s5arg_t fX0 = {.sf = 5, .flags = 0};
  1651.     f7080ret_t r;
  1652.     bdfe_t file;
  1653.     fX0.buf = &file;
  1654.     if (f70or80 == F70) {
  1655.         fX0.u.f70.zero = 0;
  1656.         fX0.u.f70.path = argv[1];
  1657.     } else {
  1658.         fX0.u.f80.path_encoding = DEFAULT_PATH_ENCODING;
  1659.         fX0.u.f80.path = argv[1];
  1660.     }
  1661.     COVERAGE_ON();
  1662.     umka_sys_lfn(&fX0, &r, f70or80);
  1663.     COVERAGE_OFF();
  1664.     print_f70_status(&r, 0);
  1665.     if (r.status != ERROR_SUCCESS)
  1666.         return;
  1667.     char fattr[KF_ATTR_CNT+1];
  1668.     convert_f70_file_attr(file.attr, fattr);
  1669.     fprintf(fout, "attr: %s\n", fattr);
  1670.     if ((file.attr & KF_FOLDER) == 0) {   // don't show size for dirs
  1671.         fprintf(fout, "size: %llu\n", file.size);
  1672.     }
  1673.  
  1674. #if PRINT_DATE_TIME == 1    // TODO: runtime, argv flag
  1675.     time_t time;
  1676.     struct tm *t;
  1677.     time = kos_time_to_epoch(&file.ctime);
  1678.     t = localtime(&time);
  1679.     fprintf(fout, "ctime: %4.4i.%2.2i.%2.2i %2.2i:%2.2i:%2.2i\n",
  1680.            t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
  1681.            t->tm_hour, t->tm_min, t->tm_sec);
  1682.     time = kos_time_to_epoch(&file.atime);
  1683.     t = localtime(&time);
  1684.     fprintf(fout, "atime: %4.4i.%2.2i.%2.2i %2.2i:%2.2i:%2.2i\n",
  1685.            t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
  1686.            t->tm_hour, t->tm_min, t->tm_sec);
  1687.     time = kos_time_to_epoch(&file.mtime);
  1688.     t = localtime(&time);
  1689.     fprintf(fout, "mtime: %4.4i.%2.2i.%2.2i %2.2i:%2.2i:%2.2i\n",
  1690.            t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
  1691.            t->tm_hour, t->tm_min, t->tm_sec);
  1692. #endif
  1693.     return;
  1694. }
  1695.  
  1696. static void
  1697. shell_stat70(int argc, char **argv) {
  1698.     shell_stat(argc, argv, F70);
  1699. }
  1700.  
  1701. static void
  1702. shell_stat80(int argc, char **argv) {
  1703.     shell_stat(argc, argv, F80);
  1704. }
  1705.  
  1706. static void
  1707. shell_read(int argc, char **argv, f70or80_t f70or80, const char *usage) {
  1708.     if (argc < 3) {
  1709.         fputs(usage, fout);
  1710.         return;
  1711.     }
  1712.     f7080s0arg_t fX0 = {.sf = 0};
  1713.     f7080ret_t r;
  1714.     bool dump_bytes = false, dump_hash = false;
  1715.     int opt = 1;
  1716.     if (f70or80 == F70) {
  1717.         fX0.u.f70.zero = 0;
  1718.         fX0.u.f70.path = argv[opt++];
  1719.     } else {
  1720.         fX0.u.f80.path_encoding = DEFAULT_PATH_ENCODING;
  1721.         fX0.u.f80.path = argv[opt++];
  1722.     }
  1723.     if ((opt >= argc) || !parse_uint64(argv[opt++], &fX0.offset))
  1724.         return;
  1725.     if ((opt >= argc) || !parse_uint32(argv[opt++], &fX0.count))
  1726.         return;
  1727.     for (; opt < argc; opt++) {
  1728.         if (!strcmp(argv[opt], "-b")) {
  1729.             dump_bytes = true;
  1730.         } else if (!strcmp(argv[opt], "-h")) {
  1731.             dump_hash = true;
  1732.         } else if (!strcmp(argv[opt], "-e")) {
  1733.             if (f70or80 == F70) {
  1734.                 fprintf(fout, "f70 doesn't accept encoding parameter,"
  1735.                         " use f80\n");
  1736.                 return;
  1737.             }
  1738.         } else {
  1739.             fprintf(fout, "invalid option: '%s'\n", argv[opt]);
  1740.             return;
  1741.         }
  1742.     }
  1743.     fX0.buf = (uint8_t*)malloc(fX0.count);
  1744.  
  1745.     COVERAGE_ON();
  1746.     umka_sys_lfn(&fX0, &r, f70or80);
  1747.     COVERAGE_OFF();
  1748.  
  1749.     print_f70_status(&r, 1);
  1750.     if (r.status == ERROR_SUCCESS || r.status == ERROR_END_OF_FILE) {
  1751.         if (dump_bytes)
  1752.             print_bytes(fX0.buf, r.count);
  1753.         if (dump_hash)
  1754.             print_hash(fX0.buf, r.count);
  1755.     }
  1756.  
  1757.     free(fX0.buf);
  1758.     return;
  1759. }
  1760.  
  1761. static void
  1762. shell_read70(int argc, char **argv) {
  1763.     const char *usage = \
  1764.         "usage: read70 <file> <offset> <length> [-b] [-h]\n"
  1765.         "  file             path/to/file\n"
  1766.         "  offset           in bytes\n"
  1767.         "  length           in bytes\n"
  1768.         "  -b               dump bytes in hex\n"
  1769.         "  -h               print hash of data read";
  1770.  
  1771.     shell_read(argc, argv, F70, usage);
  1772. }
  1773.  
  1774. static void
  1775. shell_read80(int argc, char **argv) {
  1776.     const char *usage = \
  1777.         "usage: read80 <file> <offset> <length> [-b] [-h]"
  1778.             " [-e cp866|utf8|utf16]\n"
  1779.         "  file             path/to/file\n"
  1780.         "  offset           in bytes\n"
  1781.         "  length           in bytes\n"
  1782.         "  -b               dump bytes in hex\n"
  1783.         "  -h               print hash of data read\n"
  1784.         "  -e               encoding";
  1785.     shell_read(argc, argv, F80, usage);
  1786. }
  1787.  
  1788. static void
  1789. shell_acpi_preload_table(int argc, char **argv) {
  1790.     const char *usage = \
  1791.         "usage: acpi_preload_table <file>\n"
  1792.         "  file             path/to/local/file.aml";
  1793.     if (argc != 2) {
  1794.         fputs(usage, fout);
  1795.         return;
  1796.     }
  1797.     FILE *f = fopen(argv[1], "r");
  1798.     if (!f) {
  1799.         fprintf(fout, "[umka] can't open file: %s\n", argv[1]);
  1800.         return;
  1801.     }
  1802.     fseek(f, 0, SEEK_END);
  1803.     size_t fsize = ftell(f);
  1804.     rewind(f);
  1805.     uint8_t *table = (uint8_t*)malloc(fsize);
  1806.     fread(table, fsize, 1, f);
  1807.     fclose(f);
  1808.     fprintf(fout, "table #%zu\n", kos_acpi_ssdt_cnt);
  1809.     kos_acpi_ssdt_base[kos_acpi_ssdt_cnt] = table;
  1810.     kos_acpi_ssdt_size[kos_acpi_ssdt_cnt] = fsize;
  1811.     kos_acpi_ssdt_cnt++;
  1812. }
  1813.  
  1814. static void
  1815. shell_pci_set_path(int argc, char **argv) {
  1816.     const char *usage = \
  1817.         "usage: pci_set_path <path>\n"
  1818.         "  path           where aaaa:bb:cc.d dirs are";
  1819.     if (argc != 2) {
  1820.         fputs(usage, fout);
  1821.         return;
  1822.     }
  1823.     strcpy(pci_path, argv[1]);
  1824. }
  1825.  
  1826. static void
  1827. shell_pci_get_path(int argc, char **argv) {
  1828.     (void)argv;
  1829.     const char *usage = \
  1830.         "usage: pci_get_path";
  1831.     if (argc != 1) {
  1832.         fputs(usage, fout);
  1833.         return;
  1834.     }
  1835.     fprintf(fout, "pci path: %s\n", pci_path);
  1836. }
  1837.  
  1838. static void
  1839. shell_stack_init(int argc, char **argv) {
  1840.     const char *usage = \
  1841.         "usage: stack_init";
  1842.     if (argc != 1) {
  1843.         fputs(usage, fout);
  1844.         return;
  1845.     }
  1846.     (void)argv;
  1847.     umka_stack_init();
  1848. }
  1849.  
  1850. static void
  1851. shell_net_add_device(int argc, char **argv) {
  1852.     const char *usage = \
  1853.         "usage: net_add_device";
  1854.     if (argc != 1) {
  1855.         fputs(usage, fout);
  1856.         return;
  1857.     }
  1858.     (void)argv;
  1859.     net_device_t *vnet = vnet_init(42);   // FIXME: tap & list like block devices
  1860.     int32_t dev_num = kos_net_add_device(vnet);
  1861.     fprintf(fout, "device number: %" PRIi32 "\n", dev_num);
  1862. }
  1863.  
  1864. static void
  1865. shell_net_get_dev_count(int argc, char **argv) {
  1866.     const char *usage = \
  1867.         "usage: net_get_dev_count";
  1868.     if (argc != 1) {
  1869.         fputs(usage, fout);
  1870.         return;
  1871.     }
  1872.     (void)argv;
  1873.     uint32_t count = umka_sys_net_get_dev_count();
  1874.     fprintf(fout, "active network devices: %u\n", count);
  1875. }
  1876.  
  1877. static void
  1878. shell_net_get_dev_type(int argc, char **argv) {
  1879.     const char *usage = \
  1880.         "usage: net_get_dev_type <dev_num>\n"
  1881.         "  dev_num        device number as returned by net_add_device";
  1882.     if (argc != 2) {
  1883.         fputs(usage, fout);
  1884.         return;
  1885.     }
  1886.     uint8_t dev_num = strtoul(argv[1], NULL, 0);
  1887.     int32_t dev_type = umka_sys_net_get_dev_type(dev_num);
  1888.     fprintf(fout, "status: %s\n", dev_type == -1 ? "fail" : "ok");
  1889.     if (dev_type != -1) {
  1890.         fprintf(fout, "type of network device #%" PRIu8 ": %i\n",
  1891.                 dev_num, dev_type);
  1892.     }
  1893. }
  1894.  
  1895. static void
  1896. shell_net_get_dev_name(int argc, char **argv) {
  1897.     const char *usage = \
  1898.         "usage: net_get_dev_name <dev_num>\n"
  1899.         "  dev_num        device number as returned by net_add_device";
  1900.     if (argc != 2) {
  1901.         fputs(usage, fout);
  1902.         return;
  1903.     }
  1904.     char dev_name[64];
  1905.     uint8_t dev_num = strtoul(argv[1], NULL, 0);
  1906.     int32_t status = umka_sys_net_get_dev_name(dev_num, dev_name);
  1907.     fprintf(fout, "status: %s\n", status == -1 ? "fail" : "ok");
  1908.     if (status != -1) {
  1909.         fprintf(fout, "name of network device #%" PRIu8 ": %s\n",
  1910.                 dev_num, dev_name);
  1911.     }
  1912. }
  1913.  
  1914. static void
  1915. shell_net_dev_reset(int argc, char **argv) {
  1916.     const char *usage = \
  1917.         "usage: net_dev_reset <dev_num>\n"
  1918.         "  dev_num        device number as returned by net_add_device";
  1919.     if (argc != 2) {
  1920.         fputs(usage, fout);
  1921.         return;
  1922.     }
  1923.     uint8_t dev_num = strtoul(argv[1], NULL, 0);
  1924.     int32_t status = umka_sys_net_dev_reset(dev_num);
  1925.     fprintf(fout, "status: %s\n", status == -1 ? "fail" : "ok");
  1926. }
  1927.  
  1928. static void
  1929. shell_net_dev_stop(int argc, char **argv) {
  1930.     const char *usage = \
  1931.         "usage: net_dev_stop <dev_num>\n"
  1932.         "  dev_num        device number as returned by net_add_device";
  1933.     if (argc != 2) {
  1934.         fputs(usage, fout);
  1935.         return;
  1936.     }
  1937.     uint8_t dev_num = strtoul(argv[1], NULL, 0);
  1938.     int32_t status = umka_sys_net_dev_stop(dev_num);
  1939.     fprintf(fout, "status: %s\n", status == -1 ? "fail" : "ok");
  1940. }
  1941.  
  1942. static void
  1943. shell_net_get_dev(int argc, char **argv) {
  1944.     const char *usage = \
  1945.         "usage: net_get_dev <dev_num>\n"
  1946.         "  dev_num        device number as returned by net_add_device";
  1947.     if (argc != 2) {
  1948.         fputs(usage, fout);
  1949.         return;
  1950.     }
  1951.     uint8_t dev_num = strtoul(argv[1], NULL, 0);
  1952.     intptr_t dev = umka_sys_net_get_dev(dev_num);
  1953.     fprintf(fout, "status: %s\n", dev == -1 ? "fail" : "ok");
  1954.     if (dev != -1) {
  1955.         fprintf(fout, "address of net dev #%" PRIu8 ": 0x%x\n", dev_num, dev);
  1956.     }
  1957. }
  1958.  
  1959. static void
  1960. shell_net_get_packet_tx_count(int argc, char **argv) {
  1961.     const char *usage = \
  1962.         "usage: net_get_packet_tx_count <dev_num>\n"
  1963.         "  dev_num        device number as returned by net_add_device";
  1964.     if (argc != 2) {
  1965.         fputs(usage, fout);
  1966.         return;
  1967.     }
  1968.     uint8_t dev_num = strtoul(argv[1], NULL, 0);
  1969.     uint32_t count = umka_sys_net_get_packet_tx_count(dev_num);
  1970.     fprintf(fout, "status: %s\n", count == UINT32_MAX ? "fail" : "ok");
  1971.     if (count != UINT32_MAX) {
  1972.         fprintf(fout, "packet tx count of net dev #%" PRIu8 ": %" PRIu32 "\n",
  1973.                dev_num, count);
  1974.     }
  1975. }
  1976.  
  1977. static void
  1978. shell_net_get_packet_rx_count(int argc, char **argv) {
  1979.     const char *usage = \
  1980.         "usage: net_get_packet_rx_count <dev_num>\n"
  1981.         "  dev_num        device number as returned by net_add_device";
  1982.     if (argc != 2) {
  1983.         fputs(usage, fout);
  1984.         return;
  1985.     }
  1986.     uint8_t dev_num = strtoul(argv[1], NULL, 0);
  1987.     uint32_t count = umka_sys_net_get_packet_rx_count(dev_num);
  1988.     fprintf(fout, "status: %s\n", count == UINT32_MAX ? "fail" : "ok");
  1989.     if (count != UINT32_MAX) {
  1990.         fprintf(fout, "packet rx count of net dev #%" PRIu8 ": %" PRIu32 "\n",
  1991.                dev_num, count);
  1992.     }
  1993. }
  1994.  
  1995. static void
  1996. shell_net_get_byte_tx_count(int argc, char **argv) {
  1997.     const char *usage = \
  1998.         "usage: net_get_byte_tx_count <dev_num>\n"
  1999.         "  dev_num        device number as returned by net_add_device";
  2000.     if (argc != 2) {
  2001.         fputs(usage, fout);
  2002.         return;
  2003.     }
  2004.     uint8_t dev_num = strtoul(argv[1], NULL, 0);
  2005.     uint32_t count = umka_sys_net_get_byte_tx_count(dev_num);
  2006.     fprintf(fout, "status: %s\n", count == UINT32_MAX ? "fail" : "ok");
  2007.     if (count != UINT32_MAX) {
  2008.         fprintf(fout, "byte tx count of net dev #%" PRIu8 ": %" PRIu32 "\n",
  2009.                dev_num, count);
  2010.     }
  2011. }
  2012.  
  2013. static void
  2014. shell_net_get_byte_rx_count(int argc, char **argv) {
  2015.     const char *usage = \
  2016.         "usage: net_get_byte_rx_count <dev_num>\n"
  2017.         "  dev_num        device number as returned by net_add_device";
  2018.     if (argc != 2) {
  2019.         fputs(usage, fout);
  2020.         return;
  2021.     }
  2022.     uint8_t dev_num = strtoul(argv[1], NULL, 0);
  2023.     uint32_t count = umka_sys_net_get_byte_rx_count(dev_num);
  2024.     fprintf(fout, "status: %s\n", count == UINT32_MAX ? "fail" : "ok");
  2025.     if (count != UINT32_MAX) {
  2026.         fprintf(fout, "byte rx count of net dev #%" PRIu8 ": %" PRIu32 "\n",
  2027.                dev_num, count);
  2028.     }
  2029. }
  2030.  
  2031. static void
  2032. print_link_status_names(uint32_t status) {
  2033.     switch (status & 0x3) {
  2034.     case ETH_LINK_DOWN:
  2035.         fprintf(fout, "ETH_LINK_DOWN");
  2036.         break;
  2037.     case ETH_LINK_UNKNOWN:
  2038.         fprintf(fout, "ETH_LINK_UNKNOWN");
  2039.         break;
  2040.     case ETH_LINK_FD:
  2041.         fprintf(fout, "ETH_LINK_FD");
  2042.         break;
  2043.     default:
  2044.         fprintf(fout, "ERROR");
  2045.         break;
  2046.     }
  2047.  
  2048.     switch(status & ~3u) {
  2049.     case ETH_LINK_1G:
  2050.         fprintf(fout, " + ETH_LINK_1G");
  2051.         break;
  2052.     case ETH_LINK_100M:
  2053.         fprintf(fout, " + ETH_LINK_100M");
  2054.         break;
  2055.     case ETH_LINK_10M:
  2056.         fprintf(fout, " + ETH_LINK_10M");
  2057.         break;
  2058.     default:
  2059.         fprintf(fout, " + UNKNOWN");
  2060.         break;
  2061.     }
  2062. }
  2063.  
  2064. static void
  2065. shell_net_get_link_status(int argc, char **argv) {
  2066.     const char *usage = \
  2067.         "usage: net_get_link_status <dev_num>\n"
  2068.         "  dev_num        device number as returned by net_add_device";
  2069.     if (argc != 2) {
  2070.         fputs(usage, fout);
  2071.         return;
  2072.     }
  2073.     uint8_t dev_num = strtoul(argv[1], NULL, 0);
  2074.     uint32_t status = umka_sys_net_get_link_status(dev_num);
  2075.     fprintf(fout, "status: %s\n", status == UINT32_MAX ? "fail" : "ok");
  2076.     if (status != UINT32_MAX) {
  2077.         fprintf(fout, "link status of net dev #%" PRIu8 ": %" PRIu32 " ",
  2078.                dev_num, status);
  2079.         print_link_status_names(status);
  2080.         putchar('\n');
  2081.     }
  2082. }
  2083.  
  2084. static void
  2085. shell_net_open_socket(int argc, char **argv) {
  2086.     const char *usage = \
  2087.         "usage: net_open_socket <domain> <type> <protocol>\n"
  2088.         "  domain         domain\n"
  2089.         "  type           type\n"
  2090.         "  protocol       protocol";
  2091.     if (argc != 4) {
  2092.         fputs(usage, fout);
  2093.         return;
  2094.     }
  2095.     uint32_t domain   = strtoul(argv[1], NULL, 0);
  2096.     uint32_t type     = strtoul(argv[2], NULL, 0);
  2097.     uint32_t protocol = strtoul(argv[3], NULL, 0);
  2098.     f75ret_t r = umka_sys_net_open_socket(domain, type, protocol);
  2099.     fprintf(fout, "value: 0x%" PRIx32 "\n", r.value);
  2100.     fprintf(fout, "errorcode: 0x%" PRIx32 "\n", r.errorcode);
  2101. // UINT32_MAX
  2102. }
  2103.  
  2104. static void
  2105. shell_net_close_socket(int argc, char **argv) {
  2106.     const char *usage = \
  2107.         "usage: net_close_socket <socket number>\n"
  2108.         "  socket number  socket number";
  2109.     if (argc != 2) {
  2110.         fputs(usage, fout);
  2111.         return;
  2112.     }
  2113.     uint32_t fd = strtoul(argv[1], NULL, 0);
  2114.     f75ret_t r = umka_sys_net_close_socket(fd);
  2115.     fprintf(fout, "value: 0x%" PRIx32 "\n", r.value);
  2116.     fprintf(fout, "errorcode: 0x%" PRIx32 "\n", r.errorcode);
  2117. }
  2118.  
  2119. static void
  2120. shell_net_bind(int argc, char **argv) {
  2121.     const char *usage = \
  2122.         "usage: net_bind <fd> <port> <ip>\n"
  2123.         "  fd             socket number\n"
  2124.         "  port           port\n"
  2125.         "  addr           addr";
  2126.     if (argc != 4) {
  2127.         fputs(usage, fout);
  2128.         return;
  2129.     }
  2130.     uint32_t fd = strtoul(argv[1], NULL, 0);
  2131.     uint16_t port = strtoul(argv[2], NULL, 0);
  2132.     char *addr_str = argv[3];
  2133.     uint32_t addr = inet_addr(addr_str);
  2134.     struct sockaddr_in sa;
  2135.     memset(&sa, 0, sizeof(sa));
  2136.     sa.sin_family = AF_INET4;
  2137.     sa.sin_port = htons(port);
  2138.     sa.sin_addr.s_addr = addr;
  2139.     fprintf(fout, "sockaddr at %p\n", (void*)&sa);
  2140.     f75ret_t r = umka_sys_net_bind(fd, &sa, sizeof(struct sockaddr_in));
  2141.     fprintf(fout, "value: 0x%" PRIx32 "\n", r.value);
  2142.     fprintf(fout, "errorcode: 0x%" PRIx32 "\n", r.errorcode);
  2143. }
  2144.  
  2145. static void
  2146. shell_net_listen(int argc, char **argv) {
  2147.     const char *usage = \
  2148.         "usage: net_listen <fd> <backlog>\n"
  2149.         "  fd             socket number\n"
  2150.         "  backlog        max queue length";
  2151.     if (argc != 3) {
  2152.         fputs(usage, fout);
  2153.         return;
  2154.     }
  2155.     uint32_t fd = strtoul(argv[1], NULL, 0);
  2156.     uint32_t backlog = strtoul(argv[2], NULL, 0);
  2157.     f75ret_t r = umka_sys_net_listen(fd, backlog);
  2158.     fprintf(fout, "value: 0x%" PRIx32 "\n", r.value);
  2159.     fprintf(fout, "errorcode: 0x%" PRIx32 "\n", r.errorcode);
  2160. }
  2161.  
  2162. static void
  2163. shell_net_connect(int argc, char **argv) {
  2164.     const char *usage = \
  2165.         "usage: net_connect <fd> <port> <ip>\n"
  2166.         "  fd             socket number\n"
  2167.         "  port           port\n"
  2168.         "  addr           addr";
  2169.     if (argc != 4) {
  2170.         fputs(usage, fout);
  2171.         return;
  2172.     }
  2173.     uint32_t fd = strtoul(argv[1], NULL, 0);
  2174.     uint16_t port = strtoul(argv[2], NULL, 0);
  2175.     char *addr_str = argv[3];
  2176.     uint32_t addr = inet_addr(addr_str);
  2177.     struct sockaddr_in sa;
  2178.     memset(&sa, 0, sizeof(sa));
  2179.     sa.sin_family = AF_INET4;
  2180.     sa.sin_port = htons(port);
  2181.     sa.sin_addr.s_addr = addr;
  2182.     fprintf(fout, "sockaddr at %p\n", (void*)&sa);
  2183.     f75ret_t r = umka_sys_net_connect(fd, &sa, sizeof(struct sockaddr_in));
  2184.     fprintf(fout, "value: 0x%" PRIx32 "\n", r.value);
  2185.     fprintf(fout, "errorcode: 0x%" PRIx32 "\n", r.errorcode);
  2186. }
  2187.  
  2188. static void
  2189. shell_net_accept(int argc, char **argv) {
  2190.     const char *usage = \
  2191.         "usage: net_accept <fd> <port> <ip>\n"
  2192.         "  fd             socket number\n"
  2193.         "  port           port\n"
  2194.         "  addr           addr";
  2195.     if (argc != 4) {
  2196.         fputs(usage, fout);
  2197.         return;
  2198.     }
  2199.     uint32_t fd = strtoul(argv[1], NULL, 0);
  2200.     uint16_t port = strtoul(argv[2], NULL, 0);
  2201.     char *addr_str = argv[3];
  2202.     uint32_t addr = inet_addr(addr_str);
  2203.     struct sockaddr_in sa;
  2204.     memset(&sa, 0, sizeof(sa));
  2205.     sa.sin_family = AF_INET4;
  2206.     sa.sin_port = htons(port);
  2207.     sa.sin_addr.s_addr = addr;
  2208.     fprintf(fout, "sockaddr at %p\n", (void*)&sa);
  2209.     f75ret_t r = umka_sys_net_accept(fd, &sa, sizeof(struct sockaddr_in));
  2210.     fprintf(fout, "value: 0x%" PRIx32 "\n", r.value);
  2211.     fprintf(fout, "errorcode: 0x%" PRIx32 "\n", r.errorcode);
  2212. }
  2213.  
  2214. static void
  2215. shell_net_eth_read_mac(int argc, char **argv) {
  2216.     const char *usage = \
  2217.         "usage: net_eth_read_mac <dev_num>\n"
  2218.         "  dev_num        device number as returned by net_add_device";
  2219.     if (argc != 2) {
  2220.         fputs(usage, fout);
  2221.         return;
  2222.     }
  2223.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2224.     f76ret_t r = umka_sys_net_eth_read_mac(dev_num);
  2225.     if (r.eax == UINT32_MAX) {
  2226.         fprintf(fout, "status: fail\n");
  2227.     } else {
  2228.         fprintf(fout, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
  2229.                (uint8_t)(r.ebx >>  0), (uint8_t)(r.ebx >>  8),
  2230.                (uint8_t)(r.eax >>  0), (uint8_t)(r.eax >>  8),
  2231.                (uint8_t)(r.eax >> 16), (uint8_t)(r.eax >> 24));
  2232.     }
  2233. }
  2234.  
  2235. static void
  2236. shell_net_ipv4_get_addr(int argc, char **argv) {
  2237.     const char *usage = \
  2238.         "usage: net_ipv4_get_addr <dev_num>\n"
  2239.         "  dev_num        device number as returned by net_add_device";
  2240.     if (argc != 2) {
  2241.         fputs(usage, fout);
  2242.         return;
  2243.     }
  2244.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2245.     f76ret_t r = umka_sys_net_ipv4_get_addr(dev_num);
  2246.     if (r.eax == UINT32_MAX) {
  2247.         fprintf(fout, "status: fail\n");
  2248.     } else {
  2249.         fprintf(fout, "%d.%d.%d.%d\n",
  2250.                 (uint8_t)(r.eax >>  0), (uint8_t)(r.eax >>  8),
  2251.                 (uint8_t)(r.eax >> 16), (uint8_t)(r.eax >> 24));
  2252.     }
  2253. }
  2254.  
  2255. static void
  2256. shell_net_ipv4_set_addr(int argc, char **argv) {
  2257.     const char *usage = \
  2258.         "usage: net_ipv4_set_addr <dev_num> <addr>\n"
  2259.         "  dev_num        device number as returned by net_add_device\n"
  2260.         "  addr           a.b.c.d";
  2261.     if (argc != 3) {
  2262.         fputs(usage, fout);
  2263.         return;
  2264.     }
  2265.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2266.     char *addr_str = argv[2];
  2267.     uint32_t addr = inet_addr(addr_str);
  2268.     f76ret_t r = umka_sys_net_ipv4_set_addr(dev_num, addr);
  2269.     if (r.eax == UINT32_MAX) {
  2270.         fprintf(fout, "status: fail\n");
  2271.     } else {
  2272.         fprintf(fout, "status: ok\n");
  2273.     }
  2274. }
  2275.  
  2276. static void
  2277. shell_net_ipv4_get_dns(int argc, char **argv) {
  2278.     const char *usage = \
  2279.         "usage: net_ipv4_get_dns <dev_num>\n"
  2280.         "  dev_num        device number as returned by net_add_device";
  2281.     if (argc != 2) {
  2282.         fputs(usage, fout);
  2283.         return;
  2284.     }
  2285.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2286.     f76ret_t r = umka_sys_net_ipv4_get_dns(dev_num);
  2287.     if (r.eax == UINT32_MAX) {
  2288.         fprintf(fout, "status: fail\n");
  2289.     } else {
  2290.         fprintf(fout, "%d.%d.%d.%d\n",
  2291.                 (uint8_t)(r.eax >>  0), (uint8_t)(r.eax >>  8),
  2292.                 (uint8_t)(r.eax >> 16), (uint8_t)(r.eax >> 24));
  2293.     }
  2294. }
  2295.  
  2296. static void
  2297. shell_net_ipv4_set_dns(int argc, char **argv) {
  2298.     const char *usage = \
  2299.         "usage: net_ipv4_set_dns <dev_num> <dns>\n"
  2300.         "  dev_num        device number as returned by net_add_device\n"
  2301.         "  dns            a.b.c.d";
  2302.     if (argc != 3) {
  2303.         fputs(usage, fout);
  2304.         return;
  2305.     }
  2306.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2307.     uint32_t dns = inet_addr(argv[2]);
  2308.     f76ret_t r = umka_sys_net_ipv4_set_dns(dev_num, dns);
  2309.     if (r.eax == UINT32_MAX) {
  2310.         fprintf(fout, "status: fail\n");
  2311.     } else {
  2312.         fprintf(fout, "status: ok\n");
  2313.     }
  2314. }
  2315.  
  2316. static void
  2317. shell_net_ipv4_get_subnet(int argc, char **argv) {
  2318.     const char *usage = \
  2319.         "usage: net_ipv4_get_subnet <dev_num>\n"
  2320.         "  dev_num        device number as returned by net_add_device";
  2321.     if (argc != 2) {
  2322.         fputs(usage, fout);
  2323.         return;
  2324.     }
  2325.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2326.     f76ret_t r = umka_sys_net_ipv4_get_subnet(dev_num);
  2327.     if (r.eax == UINT32_MAX) {
  2328.         fprintf(fout, "status: fail\n");
  2329.     } else {
  2330.         fprintf(fout, "%d.%d.%d.%d\n",
  2331.                 (uint8_t)(r.eax >>  0), (uint8_t)(r.eax >>  8),
  2332.                 (uint8_t)(r.eax >> 16), (uint8_t)(r.eax >> 24));
  2333.     }
  2334. }
  2335.  
  2336. static void
  2337. shell_net_ipv4_set_subnet(int argc, char **argv) {
  2338.     const char *usage = \
  2339.         "usage: net_ipv4_set_subnet <dev_num> <subnet>\n"
  2340.         "  dev_num        device number as returned by net_add_device\n"
  2341.         "  subnet         a.b.c.d";
  2342.     if (argc != 3) {
  2343.         fputs(usage, fout);
  2344.         return;
  2345.     }
  2346.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2347.     char *subnet_str = argv[2];
  2348.     uint32_t subnet = inet_addr(subnet_str);
  2349.     f76ret_t r = umka_sys_net_ipv4_set_subnet(dev_num, subnet);
  2350.     if (r.eax == UINT32_MAX) {
  2351.         fprintf(fout, "status: fail\n");
  2352.     } else {
  2353.         fprintf(fout, "status: ok\n");
  2354.     }
  2355. }
  2356.  
  2357. static void
  2358. shell_net_ipv4_get_gw(int argc, char **argv) {
  2359.     const char *usage = \
  2360.         "usage: net_ipv4_get_gw <dev_num>\n"
  2361.         "  dev_num        device number as returned by net_add_device";
  2362.     if (argc != 2) {
  2363.         fputs(usage, fout);
  2364.         return;
  2365.     }
  2366.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2367.     f76ret_t r = umka_sys_net_ipv4_get_gw(dev_num);
  2368.     if (r.eax == UINT32_MAX) {
  2369.         fprintf(fout, "status: fail\n");
  2370.     } else {
  2371.         fprintf(fout, "%d.%d.%d.%d\n",
  2372.                 (uint8_t)(r.eax >>  0), (uint8_t)(r.eax >>  8),
  2373.                 (uint8_t)(r.eax >> 16), (uint8_t)(r.eax >> 24));
  2374.     }
  2375. }
  2376.  
  2377. static void
  2378. shell_net_ipv4_set_gw(int argc, char **argv) {
  2379.     const char *usage = \
  2380.         "usage: net_ipv4_set_gw <dev_num> <gw>\n"
  2381.         "  dev_num        device number as returned by net_add_device\n"
  2382.         "  gw             a.b.c.d";
  2383.     if (argc != 3) {
  2384.         fputs(usage, fout);
  2385.         return;
  2386.     }
  2387.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2388.     char *gw_str = argv[2];
  2389.     uint32_t gw = inet_addr(gw_str);
  2390.     f76ret_t r = umka_sys_net_ipv4_set_gw(dev_num, gw);
  2391.     if (r.eax == UINT32_MAX) {
  2392.         fprintf(fout, "status: fail\n");
  2393.     } else {
  2394.         fprintf(fout, "status: ok\n");
  2395.     }
  2396. }
  2397.  
  2398. static void
  2399. shell_net_arp_get_count(int argc, char **argv) {
  2400.     const char *usage = \
  2401.         "usage: net_arp_get_count <dev_num>\n"
  2402.         "  dev_num        device number as returned by net_add_device";
  2403.     if (argc != 2) {
  2404.         fputs(usage, fout);
  2405.         return;
  2406.     }
  2407.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2408.     f76ret_t r = umka_sys_net_arp_get_count(dev_num);
  2409.     if (r.eax == UINT32_MAX) {
  2410.         fprintf(fout, "status: fail\n");
  2411.     } else {
  2412.         fprintf(fout, "%" PRIi32 "\n", r.eax);
  2413.     }
  2414. }
  2415.  
  2416. static void
  2417. shell_net_arp_get_entry(int argc, char **argv) {
  2418.     const char *usage = \
  2419.         "usage: net_arp_get_entry <dev_num> <arp_num>\n"
  2420.         "  dev_num        device number as returned by net_add_device\n"
  2421.         "  arp_num        arp number as returned by net_add_device";
  2422.     if (argc != 3) {
  2423.         fputs(usage, fout);
  2424.         return;
  2425.     }
  2426.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2427.     uint32_t arp_num = strtoul(argv[2], NULL, 0);
  2428.     arp_entry_t arp;
  2429.     f76ret_t r = umka_sys_net_arp_get_entry(dev_num, arp_num, &arp);
  2430.     if (r.eax == UINT32_MAX) {
  2431.         fprintf(fout, "status: fail\n");
  2432.     } else {
  2433.         fprintf(fout, "arp #%u: IP %d.%d.%d.%d, "
  2434.                "mac %2.2" SCNu8 ":%2.2" SCNu8 ":%2.2" SCNu8
  2435.                ":%2.2" SCNu8 ":%2.2" SCNu8 ":%2.2" SCNu8 ", "
  2436.                "status %" PRIu16 ", "
  2437.                "ttl %" PRIu16 "\n",
  2438.                arp_num,
  2439.                (uint8_t)(arp.ip >>  0), (uint8_t)(arp.ip >>  8),
  2440.                (uint8_t)(arp.ip >> 16), (uint8_t)(arp.ip >> 24),
  2441.                arp.mac[0], arp.mac[1], arp.mac[2],
  2442.                arp.mac[3], arp.mac[4], arp.mac[5],
  2443.                arp.status, arp.ttl);
  2444.     }
  2445. }
  2446.  
  2447. static void
  2448. shell_net_arp_add_entry(int argc, char **argv) {
  2449.     const char *usage = \
  2450.         "usage: net_arp_add_entry <dev_num> <addr> <mac> <status> <ttl>\n"
  2451.         "  dev_num        device number as returned by net_add_device\n"
  2452.         "  addr           IP addr\n"
  2453.         "  mac            ethernet addr\n"
  2454.         "  status         see ARP.inc\n"
  2455.         "  ttl            Time to live";
  2456.     if (argc != 6) {
  2457.         fputs(usage, fout);
  2458.         return;
  2459.     }
  2460.     arp_entry_t arp;
  2461.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2462.     arp.ip = inet_addr(argv[2]);
  2463.     sscanf(argv[3], "%" SCNu8 ":%" SCNu8 ":%" SCNu8
  2464.                     ":%" SCNu8 ":%" SCNu8 ":%" SCNu8,
  2465.                     arp.mac+0, arp.mac+1, arp.mac+2,
  2466.                     arp.mac+3, arp.mac+4, arp.mac+5);
  2467.     arp.status = strtoul(argv[4], NULL, 0);
  2468.     arp.ttl = strtoul(argv[5], NULL, 0);
  2469.     f76ret_t r = umka_sys_net_arp_add_entry(dev_num, &arp);
  2470.     if (r.eax == UINT32_MAX) {
  2471.         fprintf(fout, "status: fail\n");
  2472.     }
  2473. }
  2474.  
  2475. static void
  2476. shell_net_arp_del_entry(int argc, char **argv) {
  2477.     const char *usage = \
  2478.         "usage: net_arp_del_entry <dev_num> <arp_num>\n"
  2479.         "  dev_num        device number as returned by net_add_device\n"
  2480.         "  arp_num        arp number as returned by net_add_device";
  2481.     if (argc != 3) {
  2482.         fputs(usage, fout);
  2483.         return;
  2484.     }
  2485.     uint32_t dev_num = strtoul(argv[1], NULL, 0);
  2486.     int32_t arp_num = strtoul(argv[2], NULL, 0);
  2487.     f76ret_t r = umka_sys_net_arp_del_entry(dev_num, arp_num);
  2488.     if (r.eax == UINT32_MAX) {
  2489.         fprintf(fout, "status: fail\n");
  2490.     }
  2491. }
  2492.  
  2493. static void
  2494. shell_bg_set_size(int argc, char **argv) {
  2495.     const char *usage = \
  2496.         "usage: bg_set_size <xsize> <ysize>\n"
  2497.         "  xsize          in pixels\n"
  2498.         "  ysize          in pixels";
  2499.     if (argc != 3) {
  2500.         fputs(usage, fout);
  2501.         return;
  2502.     }
  2503.     uint32_t xsize = strtoul(argv[1], NULL, 0);
  2504.     uint32_t ysize = strtoul(argv[2], NULL, 0);
  2505.     umka_sys_bg_set_size(xsize, ysize);
  2506. }
  2507.  
  2508. static void
  2509. shell_bg_put_pixel(int argc, char **argv) {
  2510.     const char *usage = \
  2511.         "usage: bg_put_pixel <offset> <color>\n"
  2512.         "  offset         in bytes, (x+y*xsize)*3\n"
  2513.         "  color          in hex";
  2514.     if (argc != 3) {
  2515.         fputs(usage, fout);
  2516.         return;
  2517.     }
  2518.     size_t offset = strtoul(argv[1], NULL, 0);
  2519.     uint32_t color = strtoul(argv[2], NULL, 0);
  2520.     umka_sys_bg_put_pixel(offset, color);
  2521. }
  2522.  
  2523. static void
  2524. shell_bg_redraw(int argc, char **argv) {
  2525.     (void)argv;
  2526.     const char *usage = \
  2527.         "usage: bg_redraw";
  2528.     if (argc != 1) {
  2529.         fputs(usage, fout);
  2530.         return;
  2531.     }
  2532.     umka_sys_bg_redraw();
  2533. }
  2534.  
  2535. static void
  2536. shell_bg_set_mode(int argc, char **argv) {
  2537.     const char *usage = \
  2538.         "usage: bg_set_mode <mode>\n"
  2539.         "  mode           1 = tile, 2 = stretch";
  2540.     if (argc != 3) {
  2541.         fputs(usage, fout);
  2542.         return;
  2543.     }
  2544.     uint32_t mode = strtoul(argv[1], NULL, 0);
  2545.     umka_sys_bg_set_mode(mode);
  2546. }
  2547.  
  2548. static void
  2549. shell_bg_put_img(int argc, char **argv) {
  2550.     const char *usage = \
  2551.         "usage: bg_put_img <image> <offset>\n"
  2552.         "  image          file\n"
  2553.         "  offset         in bytes, (x+y*xsize)*3\n";
  2554.     if (argc != 4) {
  2555.         fputs(usage, fout);
  2556.         return;
  2557.     }
  2558.     FILE *f = fopen(argv[1], "r");
  2559.     fseek(f, 0, SEEK_END);
  2560.     size_t fsize = ftell(f);
  2561.     rewind(f);
  2562.     uint8_t *image = (uint8_t*)malloc(fsize);
  2563.     fread(image, fsize, 1, f);
  2564.     fclose(f);
  2565.     size_t offset = strtoul(argv[2], NULL, 0);
  2566.     umka_sys_bg_put_img(image, offset, fsize);
  2567. }
  2568.  
  2569. static void
  2570. shell_bg_map(int argc, char **argv) {
  2571.     (void)argv;
  2572.     const char *usage = \
  2573.         "usage: bg_map";
  2574.     if (argc != 1) {
  2575.         fputs(usage, fout);
  2576.         return;
  2577.     }
  2578.     void *addr = umka_sys_bg_map();
  2579.     fprintf(fout, "%p\n", addr);
  2580. }
  2581.  
  2582. static void
  2583. shell_bg_unmap(int argc, char **argv) {
  2584.     const char *usage = \
  2585.         "usage: bg_unmap <addr>\n"
  2586.         "  addr           return value of bg_map";
  2587.     if (argc != 2) {
  2588.         fputs(usage, fout);
  2589.         return;
  2590.     }
  2591.     void *addr = (void*)strtoul(argv[1], NULL, 0);
  2592.     uint32_t status = umka_sys_bg_unmap(addr);
  2593.     fprintf(fout, "status = %d\n", status);
  2594. }
  2595.  
  2596. static void shell_help(int argc, char **argv);
  2597.  
  2598. func_table_t shell_cmds[] = {
  2599.     { "umka_init",               shell_umka_init },
  2600.     { "umka_set_boot_params",    shell_umka_set_boot_params },
  2601.     { "acpi_preload_table",      shell_acpi_preload_table },
  2602.     { "bg_map",                  shell_bg_map },
  2603.     { "bg_put_img",              shell_bg_put_img },
  2604.     { "bg_put_pixel",            shell_bg_put_pixel },
  2605.     { "bg_redraw",               shell_bg_redraw },
  2606.     { "bg_set_mode",             shell_bg_set_mode },
  2607.     { "bg_set_size",             shell_bg_set_size },
  2608.     { "bg_unmap",                shell_bg_unmap },
  2609.     { "blit_bitmap",             shell_blit_bitmap },
  2610.     { "button",                  shell_button },
  2611.     { "cd",                      shell_cd },
  2612.     { "set",                     shell_set },
  2613.     { "disk_add",                shell_disk_add },
  2614.     { "disk_del",                shell_disk_del },
  2615.     { "display_number",          shell_display_number },
  2616.     { "draw_line",               shell_draw_line },
  2617.     { "draw_rect",               shell_draw_rect },
  2618.     { "draw_window",             shell_draw_window },
  2619.     { "dump_appdata",            shell_dump_appdata },
  2620.     { "dump_taskdata",           shell_dump_taskdata },
  2621.     { "dump_win_pos",            shell_dump_win_pos },
  2622.     { "dump_win_stack",          shell_dump_win_stack },
  2623.     { "dump_win_map",            shell_dump_win_map },
  2624.     { "exec",                    shell_exec },
  2625.     { "get_font_size",           shell_get_font_size },
  2626.     { "get_font_smoothing",      shell_get_font_smoothing },
  2627.     { "get_screen_area",         shell_get_screen_area },
  2628.     { "get_screen_size",         shell_get_screen_size },
  2629.     { "get_skin_height",         shell_get_skin_height },
  2630.     { "get_skin_margins",        shell_get_skin_margins },
  2631.     { "get_window_colors",       shell_get_window_colors },
  2632.     { "help",                    shell_help },
  2633.     { "i40",                     shell_i40 },
  2634.     { "ls70",                    shell_ls70 },
  2635.     { "ls80",                    shell_ls80 },
  2636.     { "move_window",             shell_move_window },
  2637.     { "mouse_move",              shell_mouse_move },
  2638.     { "net_accept",              shell_net_accept },
  2639.     { "net_add_device",          shell_net_add_device },
  2640.     { "net_arp_add_entry",       shell_net_arp_add_entry },
  2641.     { "net_arp_del_entry",       shell_net_arp_del_entry },
  2642.     { "net_arp_get_count",       shell_net_arp_get_count },
  2643.     { "net_arp_get_entry",       shell_net_arp_get_entry },
  2644.     { "net_bind",                shell_net_bind },
  2645.     { "net_close_socket",        shell_net_close_socket },
  2646.     { "net_connect",             shell_net_connect },
  2647.     { "net_dev_reset",           shell_net_dev_reset },
  2648.     { "net_dev_stop",            shell_net_dev_stop },
  2649.     { "net_eth_read_mac",        shell_net_eth_read_mac },
  2650.     { "net_get_byte_rx_count",   shell_net_get_byte_rx_count },
  2651.     { "net_get_byte_tx_count",   shell_net_get_byte_tx_count },
  2652.     { "net_get_dev",             shell_net_get_dev },
  2653.     { "net_get_dev_count",       shell_net_get_dev_count },
  2654.     { "net_get_dev_name",        shell_net_get_dev_name },
  2655.     { "net_get_dev_type",        shell_net_get_dev_type },
  2656.     { "net_get_link_status",     shell_net_get_link_status },
  2657.     { "net_get_packet_rx_count", shell_net_get_packet_rx_count },
  2658.     { "net_get_packet_tx_count", shell_net_get_packet_tx_count },
  2659.     { "net_ipv4_get_addr",       shell_net_ipv4_get_addr },
  2660.     { "net_ipv4_get_dns",        shell_net_ipv4_get_dns },
  2661.     { "net_ipv4_get_gw",         shell_net_ipv4_get_gw },
  2662.     { "net_ipv4_get_subnet",     shell_net_ipv4_get_subnet },
  2663.     { "net_ipv4_set_addr",       shell_net_ipv4_set_addr },
  2664.     { "net_ipv4_set_dns",        shell_net_ipv4_set_dns },
  2665.     { "net_ipv4_set_gw",         shell_net_ipv4_set_gw },
  2666.     { "net_ipv4_set_subnet",     shell_net_ipv4_set_subnet },
  2667.     { "net_listen",              shell_net_listen },
  2668.     { "net_open_socket",         shell_net_open_socket },
  2669.     { "pci_get_path",            shell_pci_get_path },
  2670.     { "pci_set_path",            shell_pci_set_path },
  2671.     { "process_info",            shell_process_info },
  2672.     { "put_image",               shell_put_image },
  2673.     { "put_image_palette",       shell_put_image_palette },
  2674.     { "pwd",                     shell_pwd },
  2675.     { "ramdisk_init",            shell_ramdisk_init },
  2676.     { "read70",                  shell_read70 },
  2677.     { "read80",                  shell_read80 },
  2678.     { "scrot",                   shell_scrot },
  2679.     { "set_button_style",        shell_set_button_style },
  2680.     { "set_cwd",                 shell_cd },
  2681.     { "set_font_size",           shell_set_font_size },
  2682.     { "set_font_smoothing",      shell_set_font_smoothing },
  2683.     { "set_pixel",               shell_set_pixel },
  2684.     { "set_screen_area",         shell_set_screen_area },
  2685.     { "set_skin",                shell_set_skin },
  2686.     { "set_window_caption",      shell_set_window_caption },
  2687.     { "set_window_colors",       shell_set_window_colors },
  2688.     { "stack_init",              shell_stack_init },
  2689.     { "stat70",                  shell_stat70 },
  2690.     { "stat80",                  shell_stat80 },
  2691.     { "window_redraw",           shell_window_redraw },
  2692.     { "write_text",              shell_write_text },
  2693.     { "switch_to_thread",        shell_switch_to_thread },
  2694.     { "new_sys_thread",          shell_new_sys_thread },
  2695. };
  2696.  
  2697. static void
  2698. shell_help(int argc, char **argv) {
  2699.     const char *usage = \
  2700.         "usage: help [command]\n"
  2701.         "  command        help on this command usage";
  2702.     switch (argc) {
  2703.     case 1:
  2704.         fputs(usage, fout);
  2705.         fputs("\navailable commands:\n", fout);
  2706.         for (func_table_t *ft = shell_cmds;
  2707.              ft < shell_cmds + sizeof(shell_cmds) / sizeof(*shell_cmds);
  2708.              ft++) {
  2709.             fprintf(fout, "  %s\n", ft->name);
  2710.         }
  2711.         break;
  2712.     case 2: {
  2713.         const char *cmd_name = argv[1];
  2714.         size_t i;
  2715.         for (i = 0; i < sizeof(shell_cmds) / sizeof(*shell_cmds); i++) {
  2716.             if (!strcmp(shell_cmds[i].name, cmd_name)) {
  2717.                 shell_cmds[i].func(0, NULL);
  2718.                 return;
  2719.             }
  2720.         }
  2721.         fprintf(fout, "no such command: %s\n", cmd_name);
  2722.         break;
  2723.     }
  2724.     default:
  2725.         fputs(usage, fout);
  2726.         return;
  2727.     }
  2728. }
  2729.  
  2730. void *
  2731. run_test(FILE *in, FILE *out, int block) {
  2732.     fin = in;
  2733.     fout = out;
  2734.     int is_tty = isatty(fileno(fin));
  2735.     char **argv = (char**)malloc(sizeof(char*) * (MAX_COMMAND_ARGS + 1));
  2736.     while(next_line(is_tty, block)) {
  2737.         if (cmd_buf[0] == '#' || cmd_buf[0] == '\n' || cmd_buf[0] == '\0' ||
  2738.             cmd_buf[0] == '\r') {
  2739.             fprintf(fout, "%s", cmd_buf);
  2740.             continue;
  2741.         }
  2742.         if (cmd_buf[0] == 'X') break;
  2743.         if (!is_tty) {
  2744.             prompt();
  2745.             fprintf(fout, "%s", cmd_buf);
  2746.             fflush(fout);
  2747.         }
  2748.         int argc = split_args(cmd_buf, argv);
  2749.         func_table_t *ft;
  2750.         for (ft = shell_cmds;
  2751.              ft < shell_cmds + sizeof(shell_cmds) / sizeof(*shell_cmds);
  2752.              ft++) {
  2753.             if (!strcmp(argv[0], ft->name)) {
  2754.                 break;
  2755.             }
  2756.         }
  2757.         if (ft->name) {
  2758.             ft->func(argc, argv);
  2759.         } else {
  2760.             fprintf(fout, "unknown command: %s\n", argv[0]);
  2761.         }
  2762.     }
  2763.     free(argv);
  2764.  
  2765.     return NULL;
  2766. }
  2767.