Subversion Repositories HelenOS-historic

Rev

Rev 594 | Rev 601 | 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. #include <console/kconsole.h>
  30. #include <console/console.h>
  31. #include <console/chardev.h>
  32. #include <console/cmd.h>
  33. #include <print.h>
  34. #include <panic.h>
  35. #include <typedefs.h>
  36. #include <arch/types.h>
  37. #include <list.h>
  38. #include <arch.h>
  39. #include <macros.h>
  40. #include <debug.h>
  41. #include <func.h>
  42. #include <symtab.h>
  43.  
  44. /** Simple kernel console.
  45.  *
  46.  * The console is realized by kernel thread kconsole.
  47.  * It doesn't understand any useful command on its own,
  48.  * but makes it possible for other kernel subsystems to
  49.  * register their own commands.
  50.  */
  51.  
  52. /** Locking.
  53.  *
  54.  * There is a list of cmd_info_t structures. This list
  55.  * is protected by cmd_lock spinlock. Note that specially
  56.  * the link elements of cmd_info_t are protected by
  57.  * this lock.
  58.  *
  59.  * Each cmd_info_t also has its own lock, which protects
  60.  * all elements thereof except the link element.
  61.  *
  62.  * cmd_lock must be acquired before any cmd_info lock.
  63.  * When locking two cmd info structures, structure with
  64.  * lower address must be locked first.
  65.  */
  66.  
  67. spinlock_t cmd_lock;    /**< Lock protecting command list. */
  68. link_t cmd_head;    /**< Command list. */
  69.  
  70. static cmd_info_t *parse_cmdline(char *cmdline, size_t len);
  71. static bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end);
  72.  
  73. /** Initialize kconsole data structures. */
  74. void kconsole_init(void)
  75. {
  76.     spinlock_initialize(&cmd_lock, "kconsole_cmd");
  77.     list_initialize(&cmd_head);
  78.  
  79.     cmd_init();
  80. }
  81.  
  82.  
  83. /** Register kconsole command.
  84.  *
  85.  * @param cmd Structure describing the command.
  86.  *
  87.  * @return 0 on failure, 1 on success.
  88.  */
  89. int cmd_register(cmd_info_t *cmd)
  90. {
  91.     ipl_t ipl;
  92.     link_t *cur;
  93.    
  94.     spinlock_lock(&cmd_lock);
  95.    
  96.     /*
  97.      * Make sure the command is not already listed.
  98.      */
  99.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  100.         cmd_info_t *hlp;
  101.        
  102.         hlp = list_get_instance(cur, cmd_info_t, link);
  103.  
  104.         if (hlp == cmd) {
  105.             /* The command is already there. */
  106.             spinlock_unlock(&cmd_lock);
  107.             return 0;
  108.         }
  109.  
  110.         /* Avoid deadlock. */
  111.         if (hlp < cmd) {
  112.             spinlock_lock(&hlp->lock);
  113.             spinlock_lock(&cmd->lock);
  114.         } else {
  115.             spinlock_lock(&cmd->lock);
  116.             spinlock_lock(&hlp->lock);
  117.         }
  118.        
  119.         if ((strncmp(hlp->name, cmd->name, strlen(cmd->name)) == 0)) {
  120.             /* The command is already there. */
  121.             spinlock_unlock(&hlp->lock);
  122.             spinlock_unlock(&cmd->lock);
  123.             spinlock_unlock(&cmd_lock);
  124.             return 0;
  125.         }
  126.        
  127.         spinlock_unlock(&hlp->lock);
  128.         spinlock_unlock(&cmd->lock);
  129.     }
  130.    
  131.     /*
  132.      * Now the command can be added.
  133.      */
  134.     list_append(&cmd->link, &cmd_head);
  135.    
  136.     spinlock_unlock(&cmd_lock);
  137.     return 1;
  138. }
  139.  
  140. /** Kernel console managing thread.
  141.  *
  142.  * @param arg Not used.
  143.  */
  144. void kconsole(void *arg)
  145. {
  146.     char cmdline[MAX_CMDLINE+1];
  147.     cmd_info_t *cmd_info;
  148.     count_t len;
  149.  
  150.     if (!stdin) {
  151.         printf("%s: no stdin\n", __FUNCTION__);
  152.         return;
  153.     }
  154.    
  155.     while (true) {
  156.         printf("%s> ", __FUNCTION__);
  157.         if (!(len = gets(stdin, cmdline, sizeof(cmdline))))
  158.             continue;
  159.         cmdline[len] = '\0';
  160.         cmd_info = parse_cmdline(cmdline, len);
  161.         if (!cmd_info)
  162.             continue;
  163.         (void) cmd_info->func(cmd_info->argv);
  164.     }
  165. }
  166.  
  167. static int parse_int_arg(char *text, size_t len, __native *result)
  168. {
  169.     char symname[MAX_SYMBOL_NAME];
  170.     __address symaddr;
  171.     bool isaddr = false;
  172.     bool isptr = false;
  173.    
  174.     /* If we get a name, try to find it in symbol table */
  175.     if (text[0] < '0' | text[0] > '9') {
  176.         if (text[0] == '&') {
  177.             isaddr = true;
  178.             text++;len--;
  179.         } else if (text[0] == '*') {
  180.             isptr = true;
  181.             text++;len--;
  182.         }
  183.         strncpy(symname, text, min(len+1, MAX_SYMBOL_NAME));
  184.         symaddr = get_symbol_addr(symname);
  185.         if (!symaddr) {
  186.             printf("Symbol %s not found.\n",symname);
  187.             return -1;
  188.         }
  189.         if (symaddr == (__address) -1) {
  190.             printf("Duplicate symbol %s.\n",symname);
  191.             symtab_print_search(symname);
  192.             return -1;
  193.         }
  194.         if (isaddr)
  195.             *result = (__native)symaddr;
  196.         else if (isptr)
  197.             *result = **((__native **)symaddr);
  198.         else
  199.             *result = *((__native *)symaddr);
  200.     } else /* It's a number - convert it */
  201.         *result = atoi(text);
  202.     return 0;
  203. }
  204.  
  205. /** Parse command line.
  206.  *
  207.  * @param cmdline Command line as read from input device.
  208.  * @param len Command line length.
  209.  *
  210.  * @return Structure describing the command.
  211.  */
  212. cmd_info_t *parse_cmdline(char *cmdline, size_t len)
  213. {
  214.     index_t start = 0, end = 0;
  215.     cmd_info_t *cmd = NULL;
  216.     link_t *cur;
  217.     ipl_t ipl;
  218.     int i;
  219.    
  220.     if (!parse_argument(cmdline, len, &start, &end)) {
  221.         /* Command line did not contain alphanumeric word. */
  222.         return NULL;
  223.     }
  224.  
  225.     spinlock_lock(&cmd_lock);
  226.    
  227.     for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
  228.         cmd_info_t *hlp;
  229.        
  230.         hlp = list_get_instance(cur, cmd_info_t, link);
  231.         spinlock_lock(&hlp->lock);
  232.        
  233.         if (strncmp(hlp->name, &cmdline[start], (end - start) + 1) == 0) {
  234.             cmd = hlp;
  235.             break;
  236.         }
  237.        
  238.         spinlock_unlock(&hlp->lock);
  239.     }
  240.    
  241.     spinlock_unlock(&cmd_lock);
  242.    
  243.     if (!cmd) {
  244.         /* Unknown command. */
  245.         printf("Unknown command.\n");
  246.         return NULL;
  247.     }
  248.  
  249.     /* cmd == hlp is locked */
  250.    
  251.     /*
  252.      * The command line must be further analyzed and
  253.      * the parameters therefrom must be matched and
  254.      * converted to those specified in the cmd info
  255.      * structure.
  256.      */
  257.  
  258.     for (i = 0; i < cmd->argc; i++) {
  259.         char *buf;
  260.         start = end + 1;
  261.         if (!parse_argument(cmdline, len, &start, &end)) {
  262.             printf("Too few arguments.\n");
  263.             spinlock_unlock(&cmd->lock);
  264.             return NULL;
  265.         }
  266.        
  267.         switch (cmd->argv[i].type) {
  268.         case ARG_TYPE_STRING:
  269.                 buf = cmd->argv[i].buffer;
  270.                 strncpy(buf, (const char *) &cmdline[start], min((end - start) + 2, cmd->argv[i].len));
  271.             buf[min((end - start) + 1, cmd->argv[i].len - 1)] = '\0';
  272.             break;
  273.         case ARG_TYPE_INT:
  274.             if (parse_int_arg(cmdline+start, end-start+1,
  275.                       &cmd->argv[i].intval))
  276.                 return NULL;
  277.             break;
  278.         case ARG_TYPE_VAR:
  279.             if (start != end && cmdline[start] == '"' && cmdline[end] == '"') {
  280.                 buf = cmd->argv[i].buffer;
  281.                 strncpy(buf, (const char *) &cmdline[start+1],
  282.                     min((end-start), cmd->argv[i].len));
  283.                 buf[min((end - start), cmd->argv[i].len - 1)] = '\0';
  284.                 cmd->argv[i].intval = (__native) buf;
  285.                 cmd->argv[i].vartype = ARG_TYPE_STRING;
  286.             } else if (!parse_int_arg(cmdline+start, end-start+1,
  287.                          &cmd->argv[i].intval))
  288.                 cmd->argv[i].vartype = ARG_TYPE_INT;
  289.             else {
  290.                 printf("Unrecognized variable argument.\n");
  291.                 return NULL;
  292.             }
  293.             break;
  294.         case ARG_TYPE_INVALID:
  295.         default:
  296.             printf("invalid argument type\n");
  297.             return NULL;
  298.             break;
  299.         }
  300.     }
  301.    
  302.     start = end + 1;
  303.     if (parse_argument(cmdline, len, &start, &end)) {
  304.         printf("Too many arguments.\n");
  305.         spinlock_unlock(&cmd->lock);
  306.         return NULL;
  307.     }
  308.    
  309.     spinlock_unlock(&cmd->lock);
  310.     return cmd;
  311. }
  312.  
  313. /** Parse argument.
  314.  *
  315.  * Find start and end positions of command line argument.
  316.  *
  317.  * @param cmdline Command line as read from the input device.
  318.  * @param len Number of characters in cmdline.
  319.  * @param start On entry, 'start' contains pointer to the index
  320.  *        of first unprocessed character of cmdline.
  321.  *        On successful exit, it marks beginning of the next argument.
  322.  * @param end Undefined on entry. On exit, 'end' points to the last character
  323.  *        of the next argument.
  324.  *
  325.  * @return false on failure, true on success.
  326.  */
  327. bool parse_argument(char *cmdline, size_t len, index_t *start, index_t *end)
  328. {
  329.     int i;
  330.     bool found_start = false;
  331.    
  332.     ASSERT(start != NULL);
  333.     ASSERT(end != NULL);
  334.    
  335.     for (i = *start; i < len; i++) {
  336.         if (!found_start) {
  337.             if (is_white(cmdline[i]))
  338.                 (*start)++;
  339.             else
  340.                 found_start = true;
  341.         } else {
  342.             if (is_white(cmdline[i]))
  343.                 break;
  344.         }
  345.     }
  346.     *end = i - 1;
  347.  
  348.     return found_start;
  349. }
  350.