Home | History | Annotate | Download | only in hdt
      1 /* ----------------------------------------------------------------------- *
      2  *
      3  *   Copyright 2009 Erwan Velu - All Rights Reserved
      4  *
      5  *   Permission is hereby granted, free of charge, to any person
      6  *   obtaining a copy of this software and associated documentation
      7  *   files (the "Software"), to deal in the Software without
      8  *   restriction, including without limitation the rights to use,
      9  *   copy, modify, merge, publish, distribute, sublicense, and/or
     10  *   sell copies of the Software, and to permit persons to whom
     11  *   the Software is furnished to do so, subject to the following
     12  *   conditions:
     13  *
     14  *   The above copyright notice and this permission notice shall
     15  *   be included in all copies or substantial portions of the Software.
     16  *
     17  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     18  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
     19  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     20  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     21  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     22  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     23  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     24  *   OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  * -----------------------------------------------------------------------
     27  */
     28 
     29 #include <stdlib.h>
     30 #include <string.h>
     31 #include <syslinux/config.h>
     32 #include <getkey.h>
     33 #include <acpi/acpi.h>
     34 #include "hdt-cli.h"
     35 #include "hdt-common.h"
     36 
     37 struct cli_mode_descr *list_modes[] = {
     38     &hdt_mode,
     39     &dmi_mode,
     40     &syslinux_mode,
     41     &pxe_mode,
     42     &kernel_mode,
     43     &cpu_mode,
     44     &pci_mode,
     45     &vesa_mode,
     46     &disk_mode,
     47     &vpd_mode,
     48     &memory_mode,
     49     &acpi_mode,
     50     NULL,
     51 };
     52 
     53 /*
     54  * .aliases = {"q", "quit"} won't work since it is an array of pointers, not an
     55  * array of variables. There is no easy way around it besides declaring the arrays of
     56  * strings first.
     57  */
     58 const char *exit_aliases[] = { "q", "quit" };
     59 const char *help_aliases[] = { "h", "?" };
     60 
     61 /* List of aliases */
     62 struct cli_alias hdt_aliases[] = {
     63     {
     64      .command = CLI_EXIT,
     65      .nb_aliases = 2,
     66      .aliases = exit_aliases,
     67      },
     68     {
     69      .command = CLI_HELP,
     70      .nb_aliases = 2,
     71      .aliases = help_aliases,
     72      },
     73 };
     74 
     75 struct cli_mode_descr *current_mode;
     76 int autocomplete_backlog;
     77 
     78 struct autocomplete_list {
     79     char autocomplete_token[MAX_LINE_SIZE];
     80     struct autocomplete_list *next;
     81 };
     82 struct autocomplete_list *autocomplete_head = NULL;
     83 struct autocomplete_list *autocomplete_tail = NULL;
     84 struct autocomplete_list *autocomplete_last_seen = NULL;
     85 
     86 static void autocomplete_add_token_to_list(const char *token)
     87 {
     88     struct autocomplete_list *new = malloc(sizeof(struct autocomplete_list));
     89 
     90     strlcpy(new->autocomplete_token, token, sizeof(new->autocomplete_token));
     91     new->next = NULL;
     92     autocomplete_backlog++;
     93 
     94     if (autocomplete_tail != NULL)
     95 	autocomplete_tail->next = new;
     96     if (autocomplete_head == NULL)
     97 	autocomplete_head = new;
     98     autocomplete_tail = new;
     99 }
    100 
    101 static void autocomplete_destroy_list(void)
    102 {
    103     struct autocomplete_list *tmp = NULL;
    104 
    105     while (autocomplete_head != NULL) {
    106 	tmp = autocomplete_head->next;
    107 	free(autocomplete_head);
    108 	autocomplete_head = tmp;
    109     }
    110     autocomplete_backlog = 0;
    111     autocomplete_tail = NULL;
    112     autocomplete_last_seen = NULL;
    113 }
    114 
    115 /**
    116  * set_mode - set the current mode of the cli
    117  * @mode:	mode to set
    118  *
    119  * Unlike cli_set_mode, this function is not used by the cli directly.
    120  **/
    121 void set_mode(cli_mode_t mode, struct s_hardware *hardware)
    122 {
    123     int i = 0;
    124 
    125     switch (mode) {
    126     case EXIT_MODE:
    127 	hdt_cli.mode = mode;
    128 	break;
    129     case HDT_MODE:
    130 	hdt_cli.mode = mode;
    131 	snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_HDT);
    132 	break;
    133     case PXE_MODE:
    134 	if (hardware->sv->filesystem != SYSLINUX_FS_PXELINUX) {
    135 	    more_printf("You are not currently using PXELINUX\n");
    136 	    break;
    137 	}
    138 	hdt_cli.mode = mode;
    139 	snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_PXE);
    140 	break;
    141     case KERNEL_MODE:
    142 	hdt_cli.mode = mode;
    143 	snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_KERNEL);
    144 	break;
    145     case SYSLINUX_MODE:
    146 	hdt_cli.mode = mode;
    147 	snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_SYSLINUX);
    148 	break;
    149     case VESA_MODE:
    150 	hdt_cli.mode = mode;
    151 	snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_VESA);
    152 	break;
    153     case PCI_MODE:
    154 	hdt_cli.mode = mode;
    155 	snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_PCI);
    156 	break;
    157     case CPU_MODE:
    158 	hdt_cli.mode = mode;
    159 	snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_CPU);
    160 	break;
    161     case DMI_MODE:
    162 	if (!hardware->is_dmi_valid) {
    163 	    more_printf("No valid DMI table found, exiting.\n");
    164 	    break;
    165 	}
    166 	hdt_cli.mode = mode;
    167 	snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_DMI);
    168 	break;
    169     case DISK_MODE:
    170 	hdt_cli.mode = mode;
    171 	snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_DISK);
    172 	break;
    173     case VPD_MODE:
    174 	if (!hardware->is_vpd_valid) {
    175 	    more_printf("No valid VPD table found, exiting.\n");
    176 	    break;
    177 	}
    178 	hdt_cli.mode = mode;
    179 	snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_VPD);
    180 	break;
    181     case MEMORY_MODE:
    182 	hdt_cli.mode = mode;
    183 	snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_MEMORY);
    184 	break;
    185     case ACPI_MODE:
    186 	hdt_cli.mode = mode;
    187 	snprintf(hdt_cli.prompt, sizeof(hdt_cli.prompt), "%s> ", CLI_ACPI);
    188 	break;
    189     default:
    190 	/* Invalid mode */
    191 	more_printf("Unknown mode, please choose among:\n");
    192 	while (list_modes[i]) {
    193 	    more_printf("\t%s\n", list_modes[i]->name);
    194 	    i++;
    195 	}
    196     }
    197 
    198     find_cli_mode_descr(hdt_cli.mode, &current_mode);
    199     /* There is not cli_mode_descr struct for the exit mode */
    200     if (current_mode == NULL && hdt_cli.mode != EXIT_MODE) {
    201 	/* Shouldn't get here... */
    202 	more_printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli.mode);
    203     }
    204 }
    205 
    206 /**
    207  * mode_s_to_mode_t - given a mode string, return the cli_mode_t representation
    208  **/
    209 cli_mode_t mode_s_to_mode_t(char *name)
    210 {
    211     int i = 0;
    212 
    213     while (list_modes[i]) {
    214 	if (!strncmp(name, list_modes[i]->name, sizeof(list_modes[i]->name)))
    215 	    break;
    216 	i++;
    217     }
    218 
    219     if (!list_modes[i])
    220 	return INVALID_MODE;
    221     else
    222 	return list_modes[i]->mode;
    223 }
    224 
    225 /**
    226  * find_cli_mode_descr - find the cli_mode_descr struct associated to a mode
    227  * @mode:	mode to look for
    228  * @mode_found:	store the mode if found, NULL otherwise
    229  *
    230  * Given a mode name, return a pointer to the associated cli_mode_descr
    231  * structure.
    232  * Note: the current mode name is stored in hdt_cli.mode.
    233  **/
    234 void find_cli_mode_descr(cli_mode_t mode, struct cli_mode_descr **mode_found)
    235 {
    236     int i = 0;
    237 
    238     while (list_modes[i] && list_modes[i]->mode != mode)
    239 	i++;
    240 
    241     /* Shouldn't get here... */
    242     if (!list_modes[i])
    243 	*mode_found = NULL;
    244     else
    245 	*mode_found = list_modes[i];
    246 }
    247 
    248 /**
    249  * expand_aliases - resolve aliases mapping
    250  * @line:	command line to parse
    251  * @command:	first token in the line
    252  * @module:	second token in the line
    253  * @argc:	number of arguments
    254  * @argv:	array of arguments
    255  *
    256  * We maintain a small list of static alises to enhance user experience.
    257  * Only commands can be aliased (first token). Otherwise it can become really hairy...
    258  **/
    259 static void expand_aliases(char *line __unused, char **command, char **module,
    260 			   int *argc, char **argv)
    261 {
    262     struct cli_mode_descr *mode;
    263     int i, j;
    264 
    265     find_cli_mode_descr(mode_s_to_mode_t(*command), &mode);
    266     if (mode != NULL && *module == NULL) {
    267 	/*
    268 	 * The user specified a mode instead of `set mode...', e.g.
    269 	 * `dmi' instead of `set mode dmi'
    270 	 */
    271 
    272 	/* *argv is NULL since *module is NULL */
    273 	*argc = 1;
    274 	*argv = malloc(*argc * sizeof(char *));
    275 	argv[0] = malloc((sizeof(*command) + 1) * sizeof(char));
    276 	strlcpy(argv[0], *command, sizeof(*command) + 1);
    277 	dprintf("CLI DEBUG: ALIAS %s ", *command);
    278 
    279 	strlcpy(*command, CLI_SET, sizeof(CLI_SET));	/* set */
    280 
    281 	*module = malloc(sizeof(CLI_MODE) * sizeof(char));
    282 	strlcpy(*module, CLI_MODE, sizeof(CLI_MODE));	/* mode */
    283 
    284 	dprintf("--> %s %s %s\n", *command, *module, argv[0]);
    285 	goto out;
    286     }
    287 
    288     /* Simple aliases mapping a single command to another one */
    289     for (i = 0; i < MAX_ALIASES; i++) {
    290 	for (j = 0; j < hdt_aliases[i].nb_aliases; j++) {
    291 	    if (!strncmp(*command, hdt_aliases[i].aliases[j],
    292 			 sizeof(hdt_aliases[i].aliases[j]))) {
    293 		dprintf("CLI DEBUG: ALIAS %s ", *command);
    294 		strlcpy(*command, hdt_aliases[i].command,
    295 			sizeof(hdt_aliases[i].command) + 1);
    296 		dprintf("--> %s\n", *command);
    297 		goto out;	/* Don't allow chaining aliases */
    298 	    }
    299 	}
    300     }
    301     return;
    302 
    303 out:
    304     dprintf("CLI DEBUG: New parameters:\n");
    305     dprintf("CLI DEBUG: command = %s\n", *command);
    306     dprintf("CLI DEBUG: module  = %s\n", *module);
    307     dprintf("CLI DEBUG: argc    = %d\n", *argc);
    308     for (i = 0; i < *argc; i++)
    309 	dprintf("CLI DEBUG: argv[%d] = %s\n", i, argv[0]);
    310     return;
    311 }
    312 
    313 /**
    314  * parse_command_line - low level parser for the command line
    315  * @line:	command line to parse
    316  * @command:	first token in the line
    317  * @module:	second token in the line
    318  * @argc:	number of arguments
    319  * @argv:	array of arguments
    320  *
    321  * The format of the command line is:
    322  *	<main command> [<module on which to operate> [<args>]]
    323  *	command is always malloc'ed (even for an empty line)
    324  **/
    325 static void parse_command_line(char *line, char **command, char **module,
    326 			       int *argc, char **argv)
    327 {
    328     int argc_iter = 0, args_pos = 0, token_found = 0, token_len = 0;
    329     int args_len = 0;
    330     char *pch = NULL, *pch_next = NULL, *tmp_pch_next = NULL;
    331 
    332     *command = NULL;
    333     *module = NULL;
    334     *argc = 0;
    335 
    336     pch = line;
    337     while (pch != NULL) {
    338 	pch_next = strchr(pch + 1, ' ');
    339 	tmp_pch_next = pch_next;
    340 
    341 	/*
    342 	 * Skip whitespaces if the user entered
    343 	 * 'set   mode        foo' for 'set mode foo'
    344 	 *  ^   ^
    345 	 *  |___|___ pch
    346 	 *      |___ pch_next <- wrong!
    347 	 *
    348 	 *  We still keep the position into tmp_pch_next to compute
    349 	 *  the lenght of the current token.
    350 	 */
    351 	while (pch_next != NULL && !strncmp(pch_next, CLI_SPACE, 1))
    352 	    pch_next++;
    353 
    354 	/* End of line guaranteed to be zeroed */
    355 	if (pch_next == NULL) {
    356 	    token_len = (int)(strchr(pch + 1, '\0') - pch);
    357 	    args_len = token_len;
    358 	} else {
    359 	    token_len = (int)(tmp_pch_next - pch);
    360 	    args_len = (int)(pch_next - pch);
    361 	}
    362 
    363 	if (token_found == 0) {
    364 	    /* Main command to execute */
    365 	    *command = malloc((token_len + 1) * sizeof(char));
    366 	    strlcpy(*command, pch, token_len);
    367 	    (*command)[token_len] = '\0';
    368 	    dprintf("CLI DEBUG parse: command = %s\n", *command);
    369 	    args_pos += args_len;
    370 	} else if (token_found == 1) {
    371 	    /* Module */
    372 	    *module = malloc((token_len + 1) * sizeof(char));
    373 	    strlcpy(*module, pch, token_len);
    374 	    (*module)[token_len] = '\0';
    375 	    dprintf("CLI DEBUG parse: module  = %s\n", *module);
    376 	    args_pos += args_len;
    377 	} else
    378 	    (*argc)++;
    379 
    380 	token_found++;
    381 	pch = pch_next;
    382     }
    383     dprintf("CLI DEBUG parse: argc    = %d\n", *argc);
    384 
    385     /* Skip arguments handling if none is supplied */
    386     if (!*argc)
    387 	return;
    388 
    389     /* Transform the arguments string into an array */
    390     *argv = malloc(*argc * sizeof(char *));
    391     pch = strtok(line + args_pos, CLI_SPACE);
    392     while (pch != NULL) {
    393 	dprintf("CLI DEBUG parse: argv[%d] = %s\n", argc_iter, pch);
    394 	argv[argc_iter] = malloc(strlen(pch) * sizeof(char));
    395 	strlcpy(argv[argc_iter], pch, strlen(pch));
    396 	argc_iter++;
    397 	pch = strtok(NULL, CLI_SPACE);
    398 	/*
    399 	 * strtok(NULL, CLI_SPACE) over a stream of spaces
    400 	 * will return an empty string
    401 	 */
    402 	while (pch != NULL && !strncmp(pch, "", 1))
    403 	    pch = strtok(NULL, CLI_SPACE);
    404     }
    405 }
    406 
    407 /**
    408  * find_cli_callback_descr - find a callback in a list of modules
    409  * @module_name:	Name of the module to find
    410  * @modules_list:	Lits of modules among which to find @module_name
    411  * @module_found:	Pointer to the matched module, NULL if not found
    412  *
    413  * Given a module name and a list of possible modules, find the corresponding
    414  * module structure that matches the module name and store it in @module_found.
    415  **/
    416 void find_cli_callback_descr(const char *module_name,
    417 			     struct cli_module_descr *modules_list,
    418 			     struct cli_callback_descr **module_found)
    419 {
    420     int modules_iter = 0;
    421 
    422     if (modules_list == NULL)
    423 	goto not_found;
    424 
    425     /* Find the callback to execute */
    426     while (modules_list->modules[modules_iter].name &&
    427 	   strcmp(module_name, modules_list->modules[modules_iter].name) != 0)
    428 	modules_iter++;
    429 
    430     if (modules_list->modules[modules_iter].name) {
    431 	*module_found = &(modules_list->modules[modules_iter]);
    432 	dprintf("CLI DEBUG: module %s found\n", (*module_found)->name);
    433 	return;
    434     }
    435 
    436 not_found:
    437     *module_found = NULL;
    438     return;
    439 }
    440 
    441 /**
    442  * autocomplete_command - print matching commands
    443  * @command:	Beginning of the command
    444  *
    445  * Given a string @command, print all availables commands starting with
    446  * @command. Commands are found within the list of commands for the current
    447  * mode and the hdt mode (if the current mode is not hdt).
    448  **/
    449 static void autocomplete_command(char *command)
    450 {
    451     int j = 0;
    452     struct cli_callback_descr *associated_module = NULL;
    453 
    454     /* First take care of the two special commands: 'show' and 'set' */
    455     if (strncmp(CLI_SHOW, command, strlen(command)) == 0) {
    456 	printf("%s\n", CLI_SHOW);
    457 	autocomplete_add_token_to_list(CLI_SHOW);
    458     }
    459     if (strncmp(CLI_SET, command, strlen(command)) == 0) {
    460 	printf("%s\n", CLI_SET);
    461 	autocomplete_add_token_to_list(CLI_SET);
    462     }
    463 
    464     /*
    465      * Then, go through the modes for the special case
    466      *      '<mode>' -> 'set mode <mode>'
    467      */
    468     while (list_modes[j]) {
    469 	if (strncmp(list_modes[j]->name, command, strlen(command)) == 0) {
    470 	    printf("%s\n", list_modes[j]->name);
    471 	    autocomplete_add_token_to_list(list_modes[j]->name);
    472 	}
    473 	j++;
    474     }
    475 
    476     /*
    477      * Let's go now through the list of default_modules for the current mode
    478      * (single token commands for the current_mode)
    479      */
    480     j = 0;
    481     if (current_mode->default_modules && current_mode->default_modules->modules) {
    482 	while (current_mode->default_modules->modules[j].name) {
    483 	    if (strncmp(current_mode->default_modules->modules[j].name,
    484 			command, strlen(command)) == 0) {
    485 		printf("%s\n", current_mode->default_modules->modules[j].name);
    486 		autocomplete_add_token_to_list(current_mode->default_modules->
    487 					       modules[j].name);
    488 	    }
    489 	    j++;
    490 	}
    491     }
    492 
    493     /*
    494      * Finally, if the current_mode is not hdt, list the available
    495      * default_modules of hdt (these are always available from any mode).
    496      */
    497     if (current_mode->mode == HDT_MODE)
    498 	return;
    499 
    500     if (!hdt_mode.default_modules || !hdt_mode.default_modules->modules)
    501 	return;
    502 
    503     j = 0;
    504     while (hdt_mode.default_modules &&
    505 	   hdt_mode.default_modules->modules[j].name) {
    506 	/*
    507 	 * Any default command that is present in hdt mode but
    508 	 * not in the current mode is available. A default
    509 	 * command can be redefined in the current mode though.
    510 	 * This next call tests this use case: if it is
    511 	 * overwritten, do not print it again.
    512 	 */
    513 	find_cli_callback_descr(hdt_mode.default_modules->modules[j].name,
    514 				current_mode->default_modules,
    515 				&associated_module);
    516 	if (associated_module == NULL &&
    517 	    strncmp(command,
    518 		    hdt_mode.default_modules->modules[j].name,
    519 		    strlen(command)) == 0) {
    520 	    printf("%s\n", hdt_mode.default_modules->modules[j].name);
    521 	    autocomplete_add_token_to_list(hdt_mode.default_modules->modules[j].
    522 					   name);
    523 	}
    524 	j++;
    525     }
    526 }
    527 
    528 /**
    529  * autocomplete_module - print matching modules
    530  * @command:	Command on the command line (not NULL)
    531  * @module:	Beginning of the module
    532  *
    533  * Given a command @command and a string @module, print all availables modules
    534  * starting with @module for command @command. Commands are found within the
    535  * list of commands for the current mode and the hdt mode (if the current mode
    536  * is not hdt).
    537  **/
    538 static void autocomplete_module(char *command, char *module)
    539 {
    540     int j = 0;
    541     char autocomplete_full_line[MAX_LINE_SIZE];
    542 
    543     if (strncmp(CLI_SHOW, command, strlen(command)) == 0) {
    544 	if (!current_mode->show_modules || !current_mode->show_modules->modules)
    545 	    return;
    546 
    547 	while (current_mode->show_modules->modules[j].name) {
    548 	    if (strncmp(current_mode->show_modules->modules[j].name,
    549 			module, strlen(module)) == 0) {
    550 		printf("%s\n", current_mode->show_modules->modules[j].name);
    551 		sprintf(autocomplete_full_line, "%s %s",
    552 			CLI_SHOW, current_mode->show_modules->modules[j].name);
    553 		autocomplete_add_token_to_list(autocomplete_full_line);
    554 	    }
    555 	    j++;
    556 	}
    557     } else if (strncmp(CLI_SET, command, strlen(command)) == 0) {
    558 	j = 0;
    559 	if (!current_mode->set_modules || !current_mode->set_modules->modules)
    560 	    return;
    561 
    562 	while (current_mode->set_modules->modules[j].name) {
    563 	    if (strncmp(current_mode->set_modules->modules[j].name,
    564 			module, strlen(module)) == 0) {
    565 		printf("%s\n", current_mode->set_modules->modules[j].name);
    566 		sprintf(autocomplete_full_line, "%s %s",
    567 			CLI_SET, current_mode->set_modules->modules[j].name);
    568 		autocomplete_add_token_to_list(autocomplete_full_line);
    569 	    }
    570 	    j++;
    571 	}
    572     }
    573 }
    574 
    575 /**
    576  * autocomplete - find possible matches for a command line
    577  * @line:	command line to parse
    578  **/
    579 static void autocomplete(char *line)
    580 {
    581     int i;
    582     int argc = 0;
    583     char *command = NULL, *module = NULL;
    584     char **argv = NULL;
    585 
    586     parse_command_line(line, &command, &module, &argc, argv);
    587 
    588     dprintf("CLI DEBUG autocomplete: before checking args\n");
    589     /* If the user specified arguments, there is nothing we can complete */
    590     if (argc != 0)
    591 	goto out;
    592 
    593     /* No argument, (the start of) a module has been specified */
    594     if (module != NULL) {
    595 	autocomplete_module(command, module);
    596 	free(module);
    597 	goto out;
    598     }
    599 
    600     /* No argument, no module, (the start of) a command has been specified */
    601     if (command != NULL) {
    602 	autocomplete_command(command);
    603 	free(command);
    604 	goto out;
    605     }
    606 
    607 out:
    608     /* Let's not forget to clean ourselves */
    609     for (i = 0; i < argc; i++)
    610 	free(argv[i]);
    611     if (argc > 0)
    612 	free(argv);
    613     return;
    614 }
    615 
    616 /**
    617  * exec_command - main logic to map the command line to callbacks
    618  **/
    619 static void exec_command(char *line, struct s_hardware *hardware)
    620 {
    621     int argc, i = 0;
    622     char *command = NULL, *module = NULL;
    623     char **argv = NULL;
    624     struct cli_callback_descr *current_module = NULL;
    625 
    626     /* This will allocate memory for command and module */
    627     parse_command_line(line, &command, &module, &argc, argv);
    628 
    629     dprintf("CLI DEBUG exec: Checking for aliases\n");
    630     /*
    631      * Expand shortcuts, if needed
    632      * This will allocate memory for argc/argv
    633      */
    634     expand_aliases(line, &command, &module, &argc, argv);
    635 
    636     find_cli_callback_descr(command, current_mode->default_modules,
    637 				&current_module);
    638 
    639     if ((module == NULL) || (current_module->nomodule == true)) {
    640 	dprintf("CLI DEBUG exec : single command detected\n");
    641 	/*
    642 	 * A single word was specified: look at the list of default
    643 	 * commands in the current mode to see if there is a match.
    644 	 * If not, it may be a generic function (exit, help, ...). These
    645 	 * are stored in the list of default commands of the hdt mode.
    646 	 */
    647 
    648 	/* First of all it the command doesn't need module, let's rework the arguments */
    649 	if ((current_module->nomodule == true) && ( module != NULL)) {
    650 		dprintf("CLI_DEBUG exec: Reworking arguments with argc=%d\n",argc);
    651 		char **new_argv=NULL;
    652     		new_argv=malloc((argc + 2)*sizeof(char *));
    653 		for (int argc_iter=0; argc_iter<argc; argc_iter++) {
    654 			dprintf("CLI_DEBUG exec rework : copy %d to %d (%s)\n",argc_iter,argc_iter+1,argv[argc_iter]);
    655 			new_argv[argc_iter+1] = malloc(strlen(argv[argc_iter]));
    656 			strlcpy(new_argv[argc_iter+1], argv[argc_iter], strlen(argv[argc_iter]));
    657 			free(argv[argc_iter]);
    658 		}
    659 		new_argv[0] = malloc(strlen(module)*sizeof(char));
    660 		strlcpy(new_argv[0], module, strlen(module));
    661 		argc++;
    662 		free(argv);
    663 		argv=new_argv;
    664 	}
    665 
    666 	if (current_module != NULL)
    667 	    current_module->exec(argc, argv, hardware);
    668 	else if (!strncmp(command, CLI_SHOW, sizeof(CLI_SHOW) - 1) &&
    669 		 current_mode->show_modules != NULL &&
    670 		 current_mode->show_modules->default_callback != NULL)
    671 	    current_mode->show_modules->default_callback(argc, argv, hardware);
    672 	else if (!strncmp(command, CLI_SET, sizeof(CLI_SET) - 1) &&
    673 		 current_mode->set_modules != NULL &&
    674 		 current_mode->set_modules->default_callback != NULL)
    675 	    current_mode->set_modules->default_callback(argc, argv, hardware);
    676 	else {
    677 	    find_cli_callback_descr(command, hdt_mode.default_modules,
    678 				    &current_module);
    679 	    if (current_module != NULL)
    680 		current_module->exec(argc, argv, hardware);
    681 	    else
    682 		more_printf("unknown command: '%s'\n", command);
    683 	}
    684     } else {
    685 	/*
    686 	 * A module has been specified! We now need to find the type of command.
    687 	 *
    688 	 * The syntax of the cli is the following:
    689 	 *    <type of command> <module on which to operate> <args>
    690 	 * e.g.
    691 	 *    dmi> show system
    692 	 *    dmi> show bank 1
    693 	 *    dmi> show memory 0 1
    694 	 *    pci> show device 12
    695 	 *    hdt> set mode dmi
    696 	 */
    697 	if (!strncmp(command, CLI_SHOW, sizeof(CLI_SHOW) - 1)) {
    698 	    dprintf("CLI DEBUG exec: %s command detected\n", CLI_SHOW);
    699 	    /* Look first for a 'show' callback in the current mode */
    700 	    find_cli_callback_descr(module, current_mode->show_modules,
    701 				    &current_module);
    702 	    /* Execute the callback, if found */
    703 	    if (current_module != NULL)
    704 		current_module->exec(argc, argv, hardware);
    705 	    else {
    706 		dprintf("CLI DEBUG exec: Looking for callback\n");
    707 		/* Look now for a 'show' callback in the hdt mode */
    708 		find_cli_callback_descr(module, hdt_mode.show_modules,
    709 					&current_module);
    710 		/* Execute the callback, if found */
    711 		if (current_module != NULL)
    712 		    current_module->exec(argc, argv, hardware);
    713 		else
    714 		    printf("unknown module: '%s'\n", module);
    715 	    }
    716 	} else if (!strncmp(command, CLI_SET, sizeof(CLI_SET) - 1)) {
    717 	    dprintf("CLI DEBUG exec : %s command detected\n", CLI_SET);
    718 	    /* Look now for a 'set' callback in the hdt mode */
    719 	    find_cli_callback_descr(module, current_mode->set_modules,
    720 				    &current_module);
    721 	    /* Execute the callback, if found */
    722 	    if (current_module != NULL)
    723 		current_module->exec(argc, argv, hardware);
    724 	    else {
    725 		/* Look now for a 'set' callback in the hdt mode */
    726 		find_cli_callback_descr(module, hdt_mode.set_modules,
    727 					&current_module);
    728 		/* Execute the callback, if found */
    729 		if (current_module != NULL)
    730 		    current_module->exec(argc, argv, hardware);
    731 		else
    732 		    printf("unknown module: '%s'\n", module);
    733 	    }
    734 	}
    735     }
    736 
    737     /* Let's not forget to clean ourselves */
    738     if (command != NULL)
    739 	free(command);
    740     if (module != NULL)
    741 	free(module);
    742     for (i = 0; i < argc; i++)
    743 	free(argv[i]);
    744     if (argc > 0)
    745 	free(argv);
    746 }
    747 
    748 static void reset_prompt(void)
    749 {
    750     /* No need to display the prompt if we exit */
    751     if (hdt_cli.mode != EXIT_MODE) {
    752 	printf("%s", hdt_cli.prompt);
    753 	/* Reset the line */
    754 	hdt_cli.cursor_pos = 0;
    755     }
    756 }
    757 
    758 void start_auto_mode(struct s_hardware *hardware)
    759 {
    760     char *mypch;
    761     int nb_commands = 0;
    762     char *commands[MAX_NB_AUTO_COMMANDS];
    763 
    764     more_printf("\nEntering Auto mode\n");
    765 
    766     /* Protecting the auto_label from the strtok modifications */
    767     char *temp = strdup(hardware->auto_label);
    768 
    769     /* Searching & saving all commands */
    770     mypch = strtok(temp, AUTO_SEPARATOR);
    771     while (mypch != NULL) {
    772 	if ((strlen(remove_spaces(mypch)) > 0) &&
    773 	    (remove_spaces(mypch)[0] != AUTO_SEPARATOR[0])) {
    774 	    nb_commands++;
    775 	    if ((commands[nb_commands] = malloc(AUTO_COMMAND_SIZE)) != NULL) {
    776 		sprintf(commands[nb_commands], "%s", remove_spaces(mypch));
    777 	    } else
    778 		nb_commands--;
    779 	}
    780 	mypch = strtok(NULL, AUTO_SEPARATOR);
    781     }
    782 
    783     free(temp);
    784 
    785     /* Executing found commands */
    786     for (int i = 1; i <= nb_commands; i++) {
    787 	if (commands[i]) {
    788 	    if (!quiet)
    789 		more_printf("%s%s\n", hdt_cli.prompt, commands[i]);
    790 	    exec_command(commands[i], hardware);
    791 	    free(commands[i]);
    792 	}
    793     }
    794 
    795     if (!quiet)
    796 	more_printf("\nExiting Auto mode\n");
    797 
    798     more_printf("\n");
    799 }
    800 
    801 void print_history(int argc, char **argv, struct s_hardware * hardware)
    802 {
    803     (void)argc;
    804     (void)argv;
    805     (void)hardware;
    806 
    807     reset_more_printf();
    808     for (int i = 1; i <= MAX_HISTORY_SIZE; i++) {
    809 	if (i == hdt_cli.history_pos) {
    810 	    more_printf("*%d:'%s'\n", i, hdt_cli.history[i]);
    811 	    continue;
    812 	}
    813 	if (strlen(hdt_cli.history[i]) == 0)
    814 	    continue;
    815 	more_printf(" %d:'%s'\n", i, hdt_cli.history[i]);
    816     }
    817 }
    818 
    819 /* Code that manages the cli mode */
    820 void start_cli_mode(struct s_hardware *hardware)
    821 {
    822     int current_key = 0;
    823     int future_history_pos = 1;	/* position of the next position in the history */
    824     int current_future_history_pos = 1;	/* Temp variable */
    825     bool display_history = true;	/* Temp Variable */
    826     char temp_command[MAX_LINE_SIZE];
    827 
    828     hdt_cli.cursor_pos = 0;
    829     memset(hdt_cli.history, 0, sizeof(hdt_cli.history));
    830     hdt_cli.history_pos = 1;
    831     hdt_cli.max_history_pos = 1;
    832 
    833     /* Find the mode selected */
    834     set_mode(HDT_MODE, hardware);
    835     find_cli_mode_descr(hdt_cli.mode, &current_mode);
    836     if (current_mode == NULL) {
    837 	/* Shouldn't get here... */
    838 	more_printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli.mode);
    839 	return;
    840     }
    841 
    842     /* Start the auto mode if the command line is set */
    843     if (strlen(hardware->auto_label) > 0) {
    844 	start_auto_mode(hardware);
    845     }
    846 
    847     more_printf("Entering CLI mode\n");
    848 
    849     reset_prompt();
    850 
    851     while (hdt_cli.mode != EXIT_MODE) {
    852 
    853 	/* Display the cursor */
    854 	display_cursor(true);
    855 
    856 	/* Let's put the cursor blinking until we get an input */
    857 	set_cursor_blink(true);
    858 
    859 	/* We wait endlessly for a keyboard input */
    860 	current_key = get_key(stdin, 0);
    861 
    862 	/* We have to cancel the blinking mode to prevent
    863 	 * input text to blink */
    864 	set_cursor_blink(false);
    865 
    866 	/* Reset autocomplete buffer unless TAB is pressed */
    867 	if (current_key != KEY_TAB)
    868 	    autocomplete_destroy_list();
    869 
    870 	switch (current_key) {
    871 	    /* clear until then end of line */
    872 	case KEY_CTRL('k'):
    873 	    /* Clear the end of the line */
    874 	    clear_end_of_line();
    875 	    memset(&INPUT[hdt_cli.cursor_pos], 0,
    876 		   strlen(INPUT) - hdt_cli.cursor_pos);
    877 	    break;
    878 
    879 	case KEY_CTRL('c'):
    880 	    printf("\n");
    881 	    reset_prompt();
    882 	    break;
    883 
    884 	case KEY_LEFT:
    885 	    if (hdt_cli.cursor_pos > 0) {
    886 		move_cursor_left(1);
    887 		hdt_cli.cursor_pos--;
    888 	    }
    889 	    break;
    890 
    891 	case KEY_RIGHT:
    892 	    if (hdt_cli.cursor_pos < (int)strlen(INPUT)) {
    893 		move_cursor_right(1);
    894 		hdt_cli.cursor_pos++;
    895 	    }
    896 	    break;
    897 
    898 	case KEY_CTRL('e'):
    899 	case KEY_END:
    900 	    /* Calling with a 0 value will make the cursor move */
    901 	    /* So, let's move the cursor only if needed */
    902 	    if ((strlen(INPUT) - hdt_cli.cursor_pos) > 0) {
    903 		/* Return to the begining of line */
    904 		move_cursor_right(strlen(INPUT) - hdt_cli.cursor_pos);
    905 		hdt_cli.cursor_pos = strlen(INPUT);
    906 	    }
    907 	    break;
    908 
    909 	case KEY_CTRL('a'):
    910 	case KEY_HOME:
    911 	    /* Calling with a 0 value will make the cursor move */
    912 	    /* So, let's move the cursor only if needed */
    913 	    if (hdt_cli.cursor_pos > 0) {
    914 		/* Return to the begining of line */
    915 		move_cursor_left(hdt_cli.cursor_pos);
    916 		hdt_cli.cursor_pos = 0;
    917 	    }
    918 	    break;
    919 
    920 	case KEY_UP:
    921 
    922 	    /* Saving future position */
    923 	    current_future_history_pos = future_history_pos;
    924 
    925 	    /* We have to compute the next position */
    926 	    if (future_history_pos == 1) {
    927 		future_history_pos = MAX_HISTORY_SIZE;
    928 	    } else {
    929 		future_history_pos--;
    930 	    }
    931 
    932 	    /* Does the next position is valid */
    933 	    if (strlen(hdt_cli.history[future_history_pos]) == 0) {
    934 		/* Position is invalid, restoring position */
    935 		future_history_pos = current_future_history_pos;
    936 		break;
    937 	    }
    938 
    939 	    /* Let's make that future position the one we use */
    940 	    memset(INPUT, 0, sizeof(INPUT));
    941 	    strlcpy(INPUT, hdt_cli.history[future_history_pos], sizeof(INPUT));
    942 
    943 	    /* Clear the line */
    944 	    clear_line();
    945 
    946 	    /* Move to the begining of line */
    947 	    move_cursor_to_column(0);
    948 
    949 	    reset_prompt();
    950 	    printf("%s", INPUT);
    951 	    hdt_cli.cursor_pos = strlen(INPUT);
    952 	    break;
    953 
    954 	case KEY_DOWN:
    955 	    display_history = true;
    956 
    957 	    /* Saving future position */
    958 	    current_future_history_pos = future_history_pos;
    959 
    960 	    if (future_history_pos == MAX_HISTORY_SIZE) {
    961 		future_history_pos = 1;
    962 	    } else {
    963 		future_history_pos++;
    964 	    }
    965 
    966 	    /* Does the next position is valid */
    967 	    if (strlen(hdt_cli.history[future_history_pos]) == 0)
    968 		display_history = false;
    969 
    970 	    /* An exception is made to reach the last empty line */
    971 	    if (future_history_pos == hdt_cli.max_history_pos)
    972 		display_history = true;
    973 
    974 	    if (display_history == false) {
    975 		/* Position is invalid, restoring position */
    976 		future_history_pos = current_future_history_pos;
    977 		break;
    978 	    }
    979 
    980 	    /* Let's make that future position the one we use */
    981 	    memset(INPUT, 0, sizeof(INPUT));
    982 	    strlcpy(INPUT, hdt_cli.history[future_history_pos], sizeof(INPUT));
    983 
    984 	    /* Clear the line */
    985 	    clear_line();
    986 
    987 	    /* Move to the begining of line */
    988 	    move_cursor_to_column(0);
    989 
    990 	    reset_prompt();
    991 	    printf("%s", INPUT);
    992 	    hdt_cli.cursor_pos = strlen(INPUT);
    993 	    break;
    994 
    995 	case KEY_TAB:
    996 	    if (autocomplete_backlog) {
    997 		clear_line();
    998 		/* Move to the begining of line */
    999 		move_cursor_to_column(0);
   1000 		reset_prompt();
   1001 		printf("%s", autocomplete_last_seen->autocomplete_token);
   1002 		strlcpy(INPUT,
   1003 			autocomplete_last_seen->autocomplete_token,
   1004 			sizeof(INPUT));
   1005 		hdt_cli.cursor_pos = strlen(INPUT);
   1006 
   1007 		/* Cycle through the list */
   1008 		autocomplete_last_seen = autocomplete_last_seen->next;
   1009 		if (autocomplete_last_seen == NULL)
   1010 		    autocomplete_last_seen = autocomplete_head;
   1011 	    } else {
   1012 		printf("\n");
   1013 		autocomplete(skip_spaces(INPUT));
   1014 		autocomplete_last_seen = autocomplete_head;
   1015 
   1016 		printf("%s%s", hdt_cli.prompt, INPUT);
   1017 	    }
   1018 	    break;
   1019 
   1020 	case KEY_ENTER:
   1021 	    printf("\n");
   1022 	    if (strlen(remove_spaces(INPUT)) < 1) {
   1023 		reset_prompt();
   1024 		break;
   1025 	    }
   1026 	    exec_command(remove_spaces(INPUT), hardware);
   1027 	    hdt_cli.history_pos++;
   1028 
   1029 	    /* Did we reach the end of the history ?*/
   1030 	    if (hdt_cli.history_pos > MAX_HISTORY_SIZE) {
   1031 		/* Let's return at the beginning */
   1032 		hdt_cli.history_pos = 1;
   1033 	    }
   1034 
   1035 	    /* Does the next position is already used ?
   1036 	     * If yes, we are cycling in history */
   1037 	    if (strlen(INPUT) > 0) {
   1038 		/* Let's clean that entry */
   1039 		memset(&INPUT,0,sizeof(INPUT));
   1040 	    }
   1041 
   1042 	    future_history_pos = hdt_cli.history_pos;
   1043 	    if (hdt_cli.history_pos > hdt_cli.max_history_pos)
   1044 		hdt_cli.max_history_pos = hdt_cli.history_pos;
   1045 	    reset_prompt();
   1046 	    break;
   1047 
   1048 	case KEY_CTRL('d'):
   1049 	case KEY_DELETE:
   1050 	    /* No need to delete when input is empty */
   1051 	    if (strlen(INPUT) == 0)
   1052 		break;
   1053 	    /* Don't delete when cursor is at the end of the line */
   1054 	    if (hdt_cli.cursor_pos >= strlen(INPUT))
   1055 		break;
   1056 
   1057 	    for (int c = hdt_cli.cursor_pos; c < (int)strlen(INPUT) - 1; c++)
   1058 		INPUT[c] = INPUT[c + 1];
   1059 	    INPUT[strlen(INPUT) - 1] = '\0';
   1060 
   1061 	    /* Clear the end of the line */
   1062 	    clear_end_of_line();
   1063 
   1064 	    /* Print the resulting buffer */
   1065 	    printf("%s", INPUT + hdt_cli.cursor_pos);
   1066 
   1067 	    /* Replace the cursor at the proper place */
   1068 	    if (strlen(INPUT + hdt_cli.cursor_pos) > 0)
   1069 		move_cursor_left(strlen(INPUT + hdt_cli.cursor_pos));
   1070 	    break;
   1071 
   1072 	case KEY_DEL:
   1073 	case KEY_BACKSPACE:
   1074 	    /* Don't delete prompt */
   1075 	    if (hdt_cli.cursor_pos == 0)
   1076 		break;
   1077 
   1078 	    for (int c = hdt_cli.cursor_pos - 1;
   1079 		 c < (int)strlen(INPUT) - 1; c++)
   1080 		INPUT[c] = INPUT[c + 1];
   1081 	    INPUT[strlen(INPUT) - 1] = '\0';
   1082 
   1083 	    /* Get one char back */
   1084 	    move_cursor_left(1);
   1085 
   1086 	    /* Clear the end of the line */
   1087 	    clear_end_of_line();
   1088 
   1089 	    /* Print the resulting buffer */
   1090 	    printf("%s", INPUT + hdt_cli.cursor_pos - 1);
   1091 
   1092 	    /* Realing to a char before the place we were */
   1093 	    hdt_cli.cursor_pos--;
   1094 	    move_cursor_to_column(strlen(hdt_cli.prompt) + hdt_cli.cursor_pos +
   1095 				  1);
   1096 
   1097 	    break;
   1098 
   1099 	case KEY_F1:
   1100 	    printf("\n");
   1101 	    exec_command(CLI_HELP, hardware);
   1102 	    reset_prompt();
   1103 	    break;
   1104 
   1105 	default:
   1106 	    if ((current_key < 0x20) || (current_key > 0x7e))
   1107 		break;
   1108 	    /* Prevent overflow */
   1109 	    if (hdt_cli.cursor_pos > MAX_LINE_SIZE - 2)
   1110 		break;
   1111 	    /* If we aren't at the end of the input line, let's insert */
   1112 	    if (hdt_cli.cursor_pos < (int)strlen(INPUT)) {
   1113 		char key[2];
   1114 		int trailing_chars = strlen(INPUT) - hdt_cli.cursor_pos;
   1115 		memset(temp_command, 0, sizeof(temp_command));
   1116 		strlcpy(temp_command, INPUT, hdt_cli.cursor_pos);
   1117 		sprintf(key, "%c", current_key);
   1118 		strncat(temp_command, key, 1);
   1119 		strncat(temp_command,
   1120 			INPUT + hdt_cli.cursor_pos, trailing_chars);
   1121 		memset(INPUT, 0, sizeof(INPUT));
   1122 		snprintf(INPUT, sizeof(INPUT), "%s", temp_command);
   1123 
   1124 		/* Clear the end of the line */
   1125 		clear_end_of_line();
   1126 
   1127 		/* Print the resulting buffer */
   1128 		printf("%s", INPUT + hdt_cli.cursor_pos);
   1129 
   1130 		/* Return where we must put the new char */
   1131 		move_cursor_left(trailing_chars);
   1132 
   1133 	    } else {
   1134 		putchar(current_key);
   1135 		INPUT[hdt_cli.cursor_pos] = current_key;
   1136 	    }
   1137 	    hdt_cli.cursor_pos++;
   1138 	    break;
   1139 	}
   1140     }
   1141 }
   1142