Subversion Repositories HelenOS-historic

Rev

Rev 1053 | Rev 1072 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (C) 2005 Jakub Jermar
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /**
  30.  * This file is meant to contain all wrapper functions for
  31.  * all kconsole commands. The point is in separating
  32.  * kconsole specific wrappers from kconsole-unaware functions
  33.  * from other subsystems.
  34.  */
  35.  
  36. #include <console/cmd.h>
  37. #include <console/kconsole.h>
  38. #include <print.h>
  39. #include <panic.h>
  40. #include <typedefs.h>
  41. #include <arch/types.h>
  42. #include <adt/list.h>
  43. #include <arch.h>
  44. #include <func.h>
  45. #include <macros.h>
  46. #include <debug.h>
  47. #include <symtab.h>
  48. #include <cpu.h>
  49. #include <mm/tlb.h>
  50. #include <arch/mm/tlb.h>
  51. #include <mm/frame.h>
  52. #include <main/version.h>
  53. #include <mm/slab.h>
  54. #include <proc/scheduler.h>
  55. #include <proc/thread.h>
  56. #include <proc/task.h>
  57.  
  58. /** Data and methods for 'help' command. */
  59. static int cmd_help(cmd_arg_t *argv);
  60. static cmd_info_t help_info = {
  61.     .name = "help",
  62.     .description = "List of supported commands.",
  63.     .func = cmd_help,
  64.     .argc = 0
  65. };
  66.  
  67. static cmd_info_t exit_info = {
  68.     .name = "exit",
  69.     .description ="Exit kconsole",
  70.     .argc = 0
  71. };
  72.  
  73. /** Data and methods for 'description' command. */
  74. static int cmd_desc(cmd_arg_t *argv);
  75. static void desc_help(void);
  76. static char desc_buf[MAX_CMDLINE+1];
  77. static cmd_arg_t desc_argv = {
  78.     .type = ARG_TYPE_STRING,
  79.     .buffer = desc_buf,
  80.     .len = sizeof(desc_buf)
  81. };
  82. static cmd_info_t desc_info = {
  83.     .name = "describe",
  84.     .description = "Describe specified command.",
  85.     .help = desc_help,
  86.     .func = cmd_desc,
  87.     .argc = 1,
  88.     .argv = &desc_argv
  89. };
  90.  
  91. /** Data and methods for 'symaddr' command. */
  92. static int cmd_symaddr(cmd_arg_t *argv);
  93. static char symaddr_buf[MAX_CMDLINE+1];
  94. static cmd_arg_t symaddr_argv = {
  95.     .type = ARG_TYPE_STRING,
  96.     .buffer = symaddr_buf,
  97.     .len = sizeof(symaddr_buf)
  98. };
  99. static cmd_info_t symaddr_info = {
  100.     .name = "symaddr",
  101.     .description = "Return symbol address.",
  102.     .func = cmd_symaddr,
  103.     .argc = 1,
  104.     .argv = &symaddr_argv
  105. };
  106.  
  107. static char set_buf[MAX_CMDLINE+1];
  108. static int cmd_set4(cmd_arg_t *argv);
  109. static cmd_arg_t set4_argv[] = {
  110.     {
  111.         .type = ARG_TYPE_STRING,
  112.         .buffer = set_buf,
  113.         .len = sizeof(set_buf)
  114.     },
  115.     {
  116.         .type = ARG_TYPE_INT
  117.     }
  118. };
  119. static cmd_info_t set4_info = {
  120.     .name = "set4",
  121.     .description = "set <dest_addr> <value> - 4byte version",
  122.     .func = cmd_set4,
  123.     .argc = 2,
  124.     .argv = set4_argv
  125. };
  126.  
  127. /** Data and methods for 'call0' command. */
  128. static char call0_buf[MAX_CMDLINE+1];
  129. static char carg1_buf[MAX_CMDLINE+1];
  130. static char carg2_buf[MAX_CMDLINE+1];
  131. static char carg3_buf[MAX_CMDLINE+1];
  132.  
  133. static int cmd_call0(cmd_arg_t *argv);
  134. static cmd_arg_t call0_argv = {
  135.     .type = ARG_TYPE_STRING,
  136.     .buffer = call0_buf,
  137.     .len = sizeof(call0_buf)
  138. };
  139. static cmd_info_t call0_info = {
  140.     .name = "call0",
  141.     .description = "call0 <function> -> call function().",
  142.     .func = cmd_call0,
  143.     .argc = 1,
  144.     .argv = &call0_argv
  145. };
  146.  
  147. /** Data and methods for 'call1' command. */
  148. static int cmd_call1(cmd_arg_t *argv);
  149. static cmd_arg_t call1_argv[] = {
  150.     {
  151.         .type = ARG_TYPE_STRING,
  152.         .buffer = call0_buf,
  153.         .len = sizeof(call0_buf)
  154.     },
  155.     {
  156.         .type = ARG_TYPE_VAR,
  157.         .buffer = carg1_buf,
  158.         .len = sizeof(carg1_buf)
  159.     }
  160. };
  161. static cmd_info_t call1_info = {
  162.     .name = "call1",
  163.     .description = "call1 <function> <arg1> -> call function(arg1).",
  164.     .func = cmd_call1,
  165.     .argc = 2,
  166.     .argv = call1_argv
  167. };
  168.  
  169. /** Data and methods for 'call2' command. */
  170. static int cmd_call2(cmd_arg_t *argv);
  171. static cmd_arg_t call2_argv[] = {
  172.     {
  173.         .type = ARG_TYPE_STRING,
  174.         .buffer = call0_buf,
  175.         .len = sizeof(call0_buf)
  176.     },
  177.     {
  178.         .type = ARG_TYPE_VAR,
  179.         .buffer = carg1_buf,
  180.         .len = sizeof(carg1_buf)
  181.     },
  182.     {
  183.         .type = ARG_TYPE_VAR,
  184.         .buffer = carg2_buf,
  185.         .len = sizeof(carg2_buf)
  186.     }
  187. };
  188. static cmd_info_t call2_info = {
  189.     .name = "call2",
  190.     .description = "call2 <function> <arg1> <arg2> -> call function(arg1,arg2).",
  191.     .func = cmd_call2,
  192.     .argc = 3,
  193.     .argv = call2_argv
  194. };
  195.  
  196. /** Data and methods for 'call3' command. */
  197. static int cmd_call3(cmd_arg_t *argv);
  198. static cmd_arg_t call3_argv[] = {
  199.     {
  200.         .type = ARG_TYPE_STRING,
  201.         .buffer = call0_buf,
  202.         .len = sizeof(call0_buf)
  203.     },
  204.     {
  205.         .type = ARG_TYPE_VAR,
  206.         .buffer = carg1_buf,
  207.         .len = sizeof(carg1_buf)
  208.     },
  209.     {
  210.         .type = ARG_TYPE_VAR,
  211.         .buffer = carg2_buf,
  212.         .len = sizeof(carg2_buf)
  213.     },
  214.     {
  215.         .type = ARG_TYPE_VAR,
  216.         .buffer = carg3_buf,
  217.         .len = sizeof(carg3_buf)
  218.     }
  219.  
  220. };
  221. static cmd_info_t call3_info = {
  222.     .name = "call3",
  223.     .description = "call3 <function> <arg1> <arg2> <arg3> -> call function(arg1,arg2,arg3).",
  224.     .func = cmd_call3,
  225.     .argc = 4,
  226.     .argv = call3_argv
  227. };
  228.  
  229. /** Data and methods for 'halt' command. */
  230. static int cmd_halt(cmd_arg_t *argv);
  231. static cmd_info_t halt_info = {
  232.     .name = "halt",
  233.     .description = "Halt the kernel.",
  234.     .func = cmd_halt,
  235.     .argc = 0
  236. };
  237.  
  238. /** Data and methods for 'tlb' command. */
  239. static int cmd_tlb(cmd_arg_t *argv);
  240. cmd_info_t tlb_info = {
  241.     .name = "tlb",
  242.     .description = "Print TLB of current processor.",
  243.     .help = NULL,
  244.     .func = cmd_tlb,
  245.     .argc = 0,
  246.     .argv = NULL
  247. };
  248.  
  249. static int cmd_threads(cmd_arg_t *argv);
  250. static cmd_info_t threads_info = {
  251.     .name = "threads",
  252.     .description = "List all threads",
  253.     .func = cmd_threads,
  254.     .argc = 0
  255. };
  256.  
  257. static int cmd_tasks(cmd_arg_t *argv);
  258. static cmd_info_t tasks_info = {
  259.     .name = "tasks",
  260.     .description = "List all tasks",
  261.     .func = cmd_tasks,
  262.     .argc = 0
  263. };
  264.  
  265.  
  266. static int cmd_sched(cmd_arg_t *argv);
  267. static cmd_info_t sched_info = {
  268.     .name = "scheduler",
  269.     .description = "List all scheduler information",
  270.     .func = cmd_sched,
  271.     .argc = 0
  272. };
  273.  
  274. static int cmd_slabs(cmd_arg_t *argv);
  275. static cmd_info_t slabs_info = {
  276.     .name = "slabs",
  277.     .description = "List SLAB caches.",
  278.     .func = cmd_slabs,
  279.     .argc = 0
  280. };
  281.  
  282. /** Data and methods for 'zones' command */
  283. static int cmd_zones(cmd_arg_t *argv);
  284. static cmd_info_t zones_info = {
  285.     .name = "zones",
  286.     .description = "List of memory zones.",
  287.     .func = cmd_zones,
  288.     .argc = 0
  289. };
  290.  
  291. /** Data and methods for 'zone' command */
  292. static int cmd_zone(cmd_arg_t *argv);
  293. static cmd_arg_t zone_argv = {
  294.     .type = ARG_TYPE_INT,
  295. };
  296.  
  297. static cmd_info_t zone_info = {
  298.     .name = "zone",
  299.     .description = "Show memory zone structure.",
  300.     .func = cmd_zone,
  301.     .argc = 1,
  302.     .argv = &zone_argv
  303. };
  304.  
  305. static int cmd_hello(cmd_arg_t *argv);
  306. static cmd_info_t hello_info = {
  307.     .name = "hello",
  308.     .description = "Hello Message",
  309.     .func = cmd_hello,
  310.     .argc = 0
  311. };
  312.  
  313. /** Data and methods for 'cpus' command. */
  314. static int cmd_cpus(cmd_arg_t *argv);
  315. cmd_info_t cpus_info = {
  316.     .name = "cpus",
  317.     .description = "List all processors.",
  318.     .help = NULL,
  319.     .func = cmd_cpus,
  320.     .argc = 0,
  321.     .argv = NULL
  322. };
  323.  
  324. /** Data and methods for 'version' command. */
  325. static int cmd_version(cmd_arg_t *argv);
  326. cmd_info_t version_info = {
  327.     .name = "version",
  328.     .description = "Print version information.",
  329.     .help = NULL,
  330.     .func = cmd_version,
  331.     .argc = 0,
  332.     .argv = NULL
  333. };
  334.  
  335. static cmd_info_t *basic_commands[] = {
  336.     &call0_info,
  337.     &call1_info,
  338.     &call2_info,
  339.     &call3_info,
  340.     &cpus_info,
  341.     &desc_info,
  342.     &exit_info,
  343.     &halt_info,
  344.     &help_info,
  345.     &set4_info,
  346.     &slabs_info,
  347.     &symaddr_info,
  348.     &sched_info,
  349.     &threads_info,
  350.     &tasks_info,
  351.     &tlb_info,
  352.     &version_info,
  353.     &zones_info,
  354.     &zone_info,
  355.     &hello_info,
  356.     NULL
  357. };
  358.  
  359.  
  360. /** Initialize command info structure.
  361.  *
  362.  * @param cmd Command info structure.
  363.  *
  364.  */
  365. void cmd_initialize(cmd_info_t *cmd)
  366. {
  367.     spinlock_initialize(&cmd->lock, "cmd");
  368.     link_initialize(&cmd->link);
  369. }
  370.  
  371. /** Initialize and register commands. */
  372. void cmd_init(void)
  373. {
  374.     int i;
  375.  
  376.     for (i=0;basic_commands[i]; i++) {
  377.         cmd_initialize(basic_commands[i]);
  378.         if (!cmd_register(basic_commands[i]))
  379.             panic("could not register command %s\n",
  380.                   basic_commands[i]->name);
  381.     }
  382. }
  383.  
  384.  
  385. /** List supported commands.
  386.  *
  387.  * @param argv Argument vector.
  388.  *
  389.  * @return 0 on failure, 1 on success.
  390.  */
  391. int cmd_help(cmd_arg_t *argv)
  392. {
  393.     link_t *cur;
  394.  
  395.     spinlock_lock(&cmd_lock);
  396.    
  397.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  398.         cmd_info_t *hlp;
  399.        
  400.         hlp = list_get_instance(cur, cmd_info_t, link);
  401.         spinlock_lock(&hlp->lock);
  402.        
  403.         printf("%s - %s\n", hlp->name, hlp->description);
  404.  
  405.         spinlock_unlock(&hlp->lock);
  406.     }
  407.    
  408.     spinlock_unlock(&cmd_lock);
  409.  
  410.     return 1;
  411. }
  412.  
  413. /** Describe specified command.
  414.  *
  415.  * @param argv Argument vector.
  416.  *
  417.  * @return 0 on failure, 1 on success.
  418.  */
  419. int cmd_desc(cmd_arg_t *argv)
  420. {
  421.     link_t *cur;
  422.  
  423.     spinlock_lock(&cmd_lock);
  424.    
  425.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  426.         cmd_info_t *hlp;
  427.        
  428.         hlp = list_get_instance(cur, cmd_info_t, link);
  429.         spinlock_lock(&hlp->lock);
  430.  
  431.         if (strncmp(hlp->name, (const char *) argv->buffer, strlen(hlp->name)) == 0) {
  432.             printf("%s - %s\n", hlp->name, hlp->description);
  433.             if (hlp->help)
  434.                 hlp->help();
  435.             spinlock_unlock(&hlp->lock);
  436.             break;
  437.         }
  438.  
  439.         spinlock_unlock(&hlp->lock);
  440.     }
  441.    
  442.     spinlock_unlock(&cmd_lock);
  443.  
  444.     return 1;
  445. }
  446.  
  447. /** Search symbol table */
  448. int cmd_symaddr(cmd_arg_t *argv)
  449. {
  450.     symtab_print_search(argv->buffer);
  451.    
  452.     return 1;
  453. }
  454.  
  455. /** Call function with zero parameters */
  456. int cmd_call0(cmd_arg_t *argv)
  457. {
  458.     __address symaddr;
  459.     char *symbol;
  460.     __native (*f)(void);
  461.  
  462.     symaddr = get_symbol_addr(argv->buffer);
  463.     if (!symaddr)
  464.         printf("Symbol %s not found.\n", argv->buffer);
  465.     else if (symaddr == (__address) -1) {
  466.         symtab_print_search(argv->buffer);
  467.         printf("Duplicate symbol, be more specific.\n");
  468.     } else {
  469.         symbol = get_symtab_entry(symaddr);
  470.         printf("Calling f(): 0x%p: %s\n", symaddr, symbol);
  471.         f =  (__native (*)(void)) symaddr;
  472.         printf("Result: 0x%p\n", f());
  473.     }
  474.    
  475.     return 1;
  476. }
  477.  
  478. /** Call function with one parameter */
  479. int cmd_call1(cmd_arg_t *argv)
  480. {
  481.     __address symaddr;
  482.     char *symbol;
  483.     __native (*f)(__native,...);
  484.     __native arg1 = argv[1].intval;
  485.  
  486.     symaddr = get_symbol_addr(argv->buffer);
  487.     if (!symaddr)
  488.         printf("Symbol %s not found.\n", argv->buffer);
  489.     else if (symaddr == (__address) -1) {
  490.         symtab_print_search(argv->buffer);
  491.         printf("Duplicate symbol, be more specific.\n");
  492.     } else {
  493.         symbol = get_symtab_entry(symaddr);
  494.         printf("Calling f(0x%x): 0x%p: %s\n", arg1, symaddr, symbol);
  495.         f =  (__native (*)(__native,...)) symaddr;
  496.         printf("Result: 0x%p\n", f(arg1));
  497.     }
  498.    
  499.     return 1;
  500. }
  501.  
  502. /** Call function with two parameters */
  503. int cmd_call2(cmd_arg_t *argv)
  504. {
  505.     __address symaddr;
  506.     char *symbol;
  507.     __native (*f)(__native,__native,...);
  508.     __native arg1 = argv[1].intval;
  509.     __native arg2 = argv[2].intval;
  510.  
  511.     symaddr = get_symbol_addr(argv->buffer);
  512.     if (!symaddr)
  513.         printf("Symbol %s not found.\n", argv->buffer);
  514.     else if (symaddr == (__address) -1) {
  515.         symtab_print_search(argv->buffer);
  516.         printf("Duplicate symbol, be more specific.\n");
  517.     } else {
  518.         symbol = get_symtab_entry(symaddr);
  519.         printf("Calling f(0x%x,0x%x): 0x%p: %s\n",
  520.                arg1, arg2, symaddr, symbol);
  521.         f =  (__native (*)(__native,__native,...)) symaddr;
  522.         printf("Result: 0x%p\n", f(arg1, arg2));
  523.     }
  524.    
  525.     return 1;
  526. }
  527.  
  528. /** Call function with three parameters */
  529. int cmd_call3(cmd_arg_t *argv)
  530. {
  531.     __address symaddr;
  532.     char *symbol;
  533.     __native (*f)(__native,__native,__native,...);
  534.     __native arg1 = argv[1].intval;
  535.     __native arg2 = argv[2].intval;
  536.     __native arg3 = argv[3].intval;
  537.  
  538.     symaddr = get_symbol_addr(argv->buffer);
  539.     if (!symaddr)
  540.         printf("Symbol %s not found.\n", argv->buffer);
  541.     else if (symaddr == (__address) -1) {
  542.         symtab_print_search(argv->buffer);
  543.         printf("Duplicate symbol, be more specific.\n");
  544.     } else {
  545.         symbol = get_symtab_entry(symaddr);
  546.         printf("Calling f(0x%x,0x%x, 0x%x): 0x%p: %s\n",
  547.                arg1, arg2, arg3, symaddr, symbol);
  548.         f =  (__native (*)(__native,__native,__native,...)) symaddr;
  549.         printf("Result: 0x%p\n", f(arg1, arg2, arg3));
  550.     }
  551.    
  552.     return 1;
  553. }
  554.  
  555.  
  556. /** Print detailed description of 'describe' command. */
  557. void desc_help(void)
  558. {
  559.     printf("Syntax: describe command_name\n");
  560. }
  561.  
  562. /** Halt the kernel.
  563.  *
  564.  * @param argv Argument vector (ignored).
  565.  *
  566.  * @return 0 on failure, 1 on success (never returns).
  567.  */
  568. int cmd_halt(cmd_arg_t *argv)
  569. {
  570.     halt();
  571.     return 1;
  572. }
  573.  
  574. /** Command for printing TLB contents.
  575.  *
  576.  * @param argv Not used.
  577.  *
  578.  * @return Always returns 1.
  579.  */
  580. int cmd_tlb(cmd_arg_t *argv)
  581. {
  582.     tlb_print();
  583.     return 1;
  584. }
  585.  
  586. /** Write 4 byte value to address */
  587. int cmd_set4(cmd_arg_t *argv)
  588. {
  589.     __u32 *addr ;
  590.     __u32 arg1 = argv[1].intval;
  591.     bool pointer = false;
  592.  
  593.     if (((char *)argv->buffer)[0] == '*') {
  594.         addr = (__u32 *) get_symbol_addr(argv->buffer+1);
  595.         pointer = true;
  596.     } else if (((char *)argv->buffer)[0] >= '0' &&
  597.            ((char *)argv->buffer)[0] <= '9')
  598.         addr = (__u32 *)atoi((char *)argv->buffer);
  599.     else
  600.         addr = (__u32 *)get_symbol_addr(argv->buffer);
  601.  
  602.     if (!addr)
  603.         printf("Symbol %s not found.\n", argv->buffer);
  604.     else if (addr == (__u32 *) -1) {
  605.         symtab_print_search(argv->buffer);
  606.         printf("Duplicate symbol, be more specific.\n");
  607.     } else {
  608.         if (pointer)
  609.             addr = (__u32 *)(*(__native *)addr);
  610.         printf("Writing 0x%x -> 0x%p\n", arg1, addr);
  611.         *addr = arg1;
  612.        
  613.     }
  614.    
  615.     return 1;
  616. }
  617.  
  618. /** Command for listings SLAB caches
  619.  *
  620.  * @param argv Ignores
  621.  *
  622.  * @return Always 1
  623.  */
  624. int cmd_slabs(cmd_arg_t * argv) {
  625.     slab_print_list();
  626.     return 1;
  627. }
  628.  
  629.  
  630. /** Command for listings Thread information
  631.  *
  632.  * @param argv Ignores
  633.  *
  634.  * @return Always 1
  635.  */
  636. int cmd_threads(cmd_arg_t * argv) {
  637.     thread_print_list();
  638.     return 1;
  639. }
  640.  
  641. /** Command for listings Task information
  642.  *
  643.  * @param argv Ignores
  644.  *
  645.  * @return Always 1
  646.  */
  647. int cmd_tasks(cmd_arg_t * argv) {
  648.     task_print_list();
  649.     return 1;
  650. }
  651.  
  652. /** Command for listings Thread information
  653.  *
  654.  * @param argv Ignores
  655.  *
  656.  * @return Always 1
  657.  */
  658. int cmd_sched(cmd_arg_t * argv) {
  659.     sched_print_list();
  660.     return 1;
  661. }
  662.  
  663. /** Command for listing memory zones
  664.  *
  665.  * @param argv Ignored
  666.  *
  667.  * return Always 1
  668.  */
  669. int cmd_zones(cmd_arg_t * argv) {
  670.     zone_print_list();
  671.     return 1;
  672. }
  673.  
  674. /** Command for memory zone details
  675.  *
  676.  * @param argv Integer argument from cmdline expected
  677.  *
  678.  * return Always 1
  679.  */
  680. int cmd_zone(cmd_arg_t * argv) {
  681.     zone_print_one(argv[0].intval);
  682.     return 1;
  683. }
  684.  
  685. /** Command for listing processors.
  686.  *
  687.  * @param argv Ignored.
  688.  *
  689.  * return Always 1.
  690.  */
  691. int cmd_cpus(cmd_arg_t *argv)
  692. {
  693.     cpu_list();
  694.     return 1;
  695. }
  696.  
  697. /** Command for printing kernel version.
  698.  *
  699.  * @param argv Ignored.
  700.  *
  701.  * return Always 1.
  702.  */
  703. int cmd_version(cmd_arg_t *argv)
  704. {
  705.     version_print();
  706.     return 1;
  707. }
  708.  
  709.  
  710. int cmd_hello(cmd_arg_t *argv)
  711. {
  712.     printf("\nHello, World !!!\n");
  713.     return 1;
  714. }
  715.