source: mainline/kernel/generic/src/console/kconsole.c@ 35fd816

Last change on this file since 35fd816 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 18.7 KB
RevLine 
[2677758]1/*
[df4ed85]2 * Copyright (c) 2005 Jakub Jermar
[2677758]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
[06e1e95]29/** @addtogroup genericconsole
[b45c443]30 * @{
31 */
32
[cf26ba9]33/**
[d6c8ff6]34 * @file kconsole.c
35 * @brief Kernel console.
[cf26ba9]36 *
37 * This file contains kernel thread managing the kernel console.
[d6c8ff6]38 *
[cf26ba9]39 */
40
[63e27ef]41#include <assert.h>
[f4338d2]42#include <console/kconsole.h>
[2677758]43#include <console/console.h>
44#include <console/chardev.h>
[442d0ae]45#include <console/cmd.h>
[f0d7bd9]46#include <console/prompt.h>
[2677758]47#include <print.h>
[ff3b3197]48#include <panic.h>
[d99c1d2]49#include <typedefs.h>
[5c9a08b]50#include <adt/list.h>
[ff3b3197]51#include <arch.h>
52#include <macros.h>
[f4338d2]53#include <debug.h>
[b2e121a]54#include <halt.h>
[19f857a]55#include <str.h>
[3ad953c]56#include <sysinfo/sysinfo.h>
[e2b762ec]57#include <symtab.h>
[e16e0d59]58#include <errno.h>
[eec616b]59#include <putchar.h>
[1066041]60#include <mm/slab.h>
[e2b762ec]61
[ff3b3197]62/** Simple kernel console.
63 *
64 * The console is realized by kernel thread kconsole.
[f4338d2]65 * It doesn't understand any useful command on its own,
66 * but makes it possible for other kernel subsystems to
[ff3b3197]67 * register their own commands.
68 */
[d6c8ff6]69
[ff3b3197]70/** Locking.
71 *
72 * There is a list of cmd_info_t structures. This list
73 * is protected by cmd_lock spinlock. Note that specially
74 * the link elements of cmd_info_t are protected by
75 * this lock.
76 *
77 * Each cmd_info_t also has its own lock, which protects
78 * all elements thereof except the link element.
79 *
80 * cmd_lock must be acquired before any cmd_info lock.
81 * When locking two cmd info structures, structure with
82 * lower address must be locked first.
83 */
84
[d6c8ff6]85SPINLOCK_INITIALIZE(cmd_lock); /**< Lock protecting command list. */
[55b77d9]86LIST_INITIALIZE(cmd_list); /**< Command list. */
[d6c8ff6]87
88static wchar_t history[KCONSOLE_HISTORY][MAX_CMDLINE] = {};
[98000fb]89static size_t history_pos = 0;
[ff3b3197]90
[3ad953c]91/** Initialize kconsole data structures
92 *
93 * This is the most basic initialization, almost no
94 * other kernel subsystem is ready yet.
95 *
96 */
[ff3b3197]97void kconsole_init(void)
98{
[3ad953c]99 unsigned int i;
[a35b458]100
[442d0ae]101 cmd_init();
[cf5ddf6]102 for (i = 0; i < KCONSOLE_HISTORY; i++)
[d6c8ff6]103 history[i][0] = 0;
[ff3b3197]104}
105
106/** Register kconsole command.
107 *
108 * @param cmd Structure describing the command.
109 *
[d6c8ff6]110 * @return False on failure, true on success.
111 *
[ff3b3197]112 */
[d6c8ff6]113bool cmd_register(cmd_info_t *cmd)
[ff3b3197]114{
115 spinlock_lock(&cmd_lock);
[a35b458]116
[ff3b3197]117 /*
118 * Make sure the command is not already listed.
119 */
[feeac0d]120 list_foreach(cmd_list, link, cmd_info_t, hlp) {
[ff3b3197]121 if (hlp == cmd) {
122 /* The command is already there. */
123 spinlock_unlock(&cmd_lock);
[d6c8ff6]124 return false;
[ff3b3197]125 }
[a35b458]126
[ff3b3197]127 /* Avoid deadlock. */
128 if (hlp < cmd) {
129 spinlock_lock(&hlp->lock);
130 spinlock_lock(&cmd->lock);
131 } else {
132 spinlock_lock(&cmd->lock);
133 spinlock_lock(&hlp->lock);
134 }
[a35b458]135
[d6c8ff6]136 if (str_cmp(hlp->name, cmd->name) == 0) {
[ff3b3197]137 /* The command is already there. */
138 spinlock_unlock(&hlp->lock);
139 spinlock_unlock(&cmd->lock);
140 spinlock_unlock(&cmd_lock);
[d6c8ff6]141 return false;
[ff3b3197]142 }
[a35b458]143
[ff3b3197]144 spinlock_unlock(&hlp->lock);
145 spinlock_unlock(&cmd->lock);
146 }
[a35b458]147
[ff3b3197]148 /*
149 * Now the command can be added.
150 */
[55b77d9]151 list_append(&cmd->link, &cmd_list);
[a35b458]152
[ff3b3197]153 spinlock_unlock(&cmd_lock);
[d6c8ff6]154 return true;
[ff3b3197]155}
[2677758]156
[07bd114e]157/** Print count times a character */
[7a0359b]158NO_TRACE static void print_cc(wchar_t ch, size_t count)
[0c8e692]159{
[98000fb]160 size_t i;
[cf5ddf6]161 for (i = 0; i < count; i++)
[0c8e692]162 putchar(ch);
163}
164
[2cf87e50]165/** Try to find a command beginning with prefix */
[3266412]166const char *cmdtab_enum(const char *name, const char **h, void **ctx)
[0c8e692]167{
[e98f1c3e]168 link_t **startpos = (link_t**) ctx;
[98000fb]169 size_t namelen = str_length(name);
[a35b458]170
[0c8e692]171 spinlock_lock(&cmd_lock);
[a35b458]172
[d6c8ff6]173 if (*startpos == NULL)
[55b77d9]174 *startpos = cmd_list.head.next;
[a35b458]175
[55b77d9]176 for (; *startpos != &cmd_list.head; *startpos = (*startpos)->next) {
[d6c8ff6]177 cmd_info_t *hlp = list_get_instance(*startpos, cmd_info_t, link);
[a35b458]178
[d6c8ff6]179 const char *curname = hlp->name;
180 if (str_length(curname) < namelen)
[0c8e692]181 continue;
[a35b458]182
[d6c8ff6]183 if (str_lcmp(curname, name, namelen) == 0) {
[36b0490e]184 *startpos = (*startpos)->next;
[e98f1c3e]185 if (h)
[36b0490e]186 *h = hlp->description;
[a35b458]187
[d6c8ff6]188 spinlock_unlock(&cmd_lock);
189 return (curname + str_lsize(curname, namelen));
[0c8e692]190 }
191 }
[a35b458]192
[d6c8ff6]193 spinlock_unlock(&cmd_lock);
[0c8e692]194 return NULL;
195}
196
[d6c8ff6]197/** Command completion of the commands
198 *
199 * @param name String to match, changed to hint on exit
200 * @param size Input buffer size
201 *
202 * @return Number of found matches
[0c8e692]203 *
204 */
[36b0490e]205NO_TRACE static int cmdtab_compl(char *input, size_t size, indev_t *indev,
206 hints_enum_func_t hints_enum)
[0c8e692]207{
[d6c8ff6]208 const char *name = input;
[a35b458]209
[98000fb]210 size_t found = 0;
[a35b458]211
[e435537]212 /*
213 * Maximum Match Length: Length of longest matching common
214 * substring in case more than one match is found.
215 */
[1e01a35]216 size_t max_match_len = size;
217 size_t max_match_len_tmp = size;
[36b0490e]218 void *pos = NULL;
[d6c8ff6]219 const char *hint;
[36b0490e]220 const char *help;
[a7199c2]221 char *output = malloc(MAX_CMDLINE, 0);
[1e01a35]222 size_t hints_to_show = MAX_TAB_HINTS - 1;
223 size_t total_hints_shown = 0;
[f0d7bd9]224 bool continue_showing_hints = true;
[a35b458]225
[d6c8ff6]226 output[0] = 0;
[a35b458]227
[36b0490e]228 while ((hint = hints_enum(name, NULL, &pos))) {
[dc0e41c]229 if ((found == 0) || (str_length(hint) > str_length(output)))
[f4b1535]230 str_cpy(output, MAX_CMDLINE, hint);
[a35b458]231
[0c8e692]232 found++;
233 }
[a35b458]234
[e435537]235 /*
236 * If the number of possible completions is more than MAX_TAB_HINTS,
237 * ask the user whether to display them or not.
238 */
[1e01a35]239 if (found > MAX_TAB_HINTS) {
[aca4a04]240 printf("\n");
[e435537]241 continue_showing_hints =
242 console_prompt_display_all_hints(indev, found);
[1e01a35]243 }
[a35b458]244
[d6c8ff6]245 if ((found > 1) && (str_length(output) != 0)) {
[0c8e692]246 printf("\n");
[d6c8ff6]247 pos = NULL;
[36b0490e]248 while ((hint = hints_enum(name, &help, &pos))) {
[a35b458]249
[f0d7bd9]250 if (continue_showing_hints) {
[36b0490e]251 if (help)
252 printf("%s%s (%s)\n", name, hint, help);
253 else
254 printf("%s%s\n", name, hint);
[a35b458]255
[1e01a35]256 --hints_to_show;
257 ++total_hints_shown;
[a35b458]258
[e435537]259 if ((hints_to_show == 0) && (total_hints_shown != found)) {
260 /* Ask user to continue */
261 continue_showing_hints =
262 console_prompt_more_hints(indev, &hints_to_show);
[1e01a35]263 }
264 }
[a35b458]265
[e435537]266 for (max_match_len_tmp = 0;
267 (output[max_match_len_tmp] ==
[36b0490e]268 hint[max_match_len_tmp]) &&
[e435537]269 (max_match_len_tmp < max_match_len); ++max_match_len_tmp);
[a35b458]270
[1e01a35]271 max_match_len = max_match_len_tmp;
[0c8e692]272 }
[a35b458]273
[e435537]274 /* Keep only the characters common in all completions */
[1e01a35]275 output[max_match_len] = 0;
[0c8e692]276 }
[a35b458]277
[d6c8ff6]278 if (found > 0)
[f4b1535]279 str_cpy(input, size, output);
[a35b458]280
[a7199c2]281 free(output);
[0c8e692]282 return found;
283}
284
[6a75c134]285NO_TRACE static cmd_info_t *parse_cmd(const wchar_t *cmdline)
286{
287 size_t start = 0;
288 size_t end;
289 char *tmp;
[a35b458]290
[6a75c134]291 while (isspace(cmdline[start]))
292 start++;
[a35b458]293
[6a75c134]294 end = start + 1;
[a35b458]295
[6a75c134]296 while (!isspace(cmdline[end]))
297 end++;
[a35b458]298
[6a75c134]299 tmp = malloc(STR_BOUNDS(end - start + 1), 0);
[a35b458]300
[6a75c134]301 wstr_to_str(tmp, end - start + 1, &cmdline[start]);
[a35b458]302
[6a75c134]303 spinlock_lock(&cmd_lock);
[a35b458]304
[6a75c134]305 list_foreach(cmd_list, link, cmd_info_t, hlp) {
306 spinlock_lock(&hlp->lock);
[a35b458]307
[6a75c134]308 if (str_cmp(hlp->name, tmp) == 0) {
309 spinlock_unlock(&hlp->lock);
310 spinlock_unlock(&cmd_lock);
311 free(tmp);
312 return hlp;
313 }
[a35b458]314
[6a75c134]315 spinlock_unlock(&hlp->lock);
316 }
[a35b458]317
[6a75c134]318 free(tmp);
319 spinlock_unlock(&cmd_lock);
[a35b458]320
[6a75c134]321 return NULL;
322}
323
[7a0359b]324NO_TRACE static wchar_t *clever_readline(const char *prompt, indev_t *indev)
[0c8e692]325{
326 printf("%s> ", prompt);
[a35b458]327
[98000fb]328 size_t position = 0;
[d6c8ff6]329 wchar_t *current = history[history_pos];
330 current[0] = 0;
[a7199c2]331 char *tmp = malloc(STR_BOUNDS(MAX_CMDLINE), 0);
[a35b458]332
[d6c8ff6]333 while (true) {
[44b7783]334 wchar_t ch = indev_pop_character(indev);
[a35b458]335
[d6c8ff6]336 if (ch == '\n') {
337 /* Enter */
338 putchar(ch);
[0c8e692]339 break;
[5d67baa]340 }
[a35b458]341
[d6c8ff6]342 if (ch == '\b') {
343 /* Backspace */
[0c8e692]344 if (position == 0)
345 continue;
[a35b458]346
[d6c8ff6]347 if (wstr_remove(current, position - 1)) {
348 position--;
[c8bf88d]349 putchar('\b');
350 printf("%ls ", current + position);
351 print_cc('\b', wstr_length(current) - position + 1);
[d6c8ff6]352 continue;
353 }
[0c8e692]354 }
[a35b458]355
[d6c8ff6]356 if (ch == '\t') {
357 /* Tab completion */
[a35b458]358
[0c8e692]359 /* Move to the end of the word */
[d6c8ff6]360 for (; (current[position] != 0) && (!isspace(current[position]));
[cf5ddf6]361 position++)
[0c8e692]362 putchar(current[position]);
[a35b458]363
364
[e435537]365 /*
366 * Find the beginning of the word
367 * and copy it to tmp
368 */
[98000fb]369 size_t beg;
[d9ffc54]370 unsigned narg = 0;
[6b00876]371 if (position == 0) {
372 tmp[0] = '\0';
373 beg = 0;
[d9ffc54]374 } else {
375 for (beg = position - 1;
376 (beg > 0) && (!isspace(current[beg]));
[e98f1c3e]377 beg--);
[a35b458]378
[6b00876]379 if (isspace(current[beg]))
380 beg++;
[a35b458]381
[6b00876]382 wstr_to_str(tmp, position - beg + 1, current + beg);
383 }
[a35b458]384
[0cfc18d3]385 /* Count which argument number are we tabbing (narg=0 is cmd) */
[d9ffc54]386 bool sp = false;
[0cfc18d3]387 for (; beg > 0; beg--) {
388 if (isspace(current[beg])) {
389 if (!sp) {
390 narg++;
[d9ffc54]391 sp = true;
[0cfc18d3]392 }
[d9ffc54]393 } else
394 sp = false;
[0cfc18d3]395 }
[a35b458]396
[0cfc18d3]397 if (narg && isspace(current[0]))
398 narg--;
[a35b458]399
[d6c8ff6]400 int found;
[0cfc18d3]401 if (narg == 0) {
[d6c8ff6]402 /* Command completion */
[6a75c134]403 found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev,
404 cmdtab_enum);
[d6c8ff6]405 } else {
[6a75c134]406 /* Arguments completion */
407 cmd_info_t *cmd = parse_cmd(current);
[0cfc18d3]408 if (!cmd || !cmd->hints_enum || cmd->argc < narg)
[6a75c134]409 continue;
410 found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev,
411 cmd->hints_enum);
[0c8e692]412 }
[a35b458]413
[d6c8ff6]414 if (found == 0)
[0c8e692]415 continue;
[1e01a35]416
[e435537]417 /*
418 * We have hints, possibly many. In case of more than one hint,
419 * tmp will contain the common prefix.
420 */
[1e01a35]421 size_t off = 0;
422 size_t i = 0;
423 while ((ch = str_decode(tmp, &off, STR_NO_LIMIT)) != 0) {
424 if (!wstr_linsert(current, ch, position + i, MAX_CMDLINE))
425 break;
[a35b458]426
[1e01a35]427 i++;
428 }
[a35b458]429
[37c312a]430 if (found > 1) {
431 /* No unique hint, list was printed */
432 printf("%s> ", prompt);
433 printf("%ls", current);
[1e01a35]434 position += str_length(tmp);
[37c312a]435 print_cc('\b', wstr_length(current) - position);
436 continue;
437 }
[a35b458]438
[37c312a]439 /* We have a hint */
[a35b458]440
[37c312a]441 printf("%ls", current + position);
442 position += str_length(tmp);
443 print_cc('\b', wstr_length(current) - position);
[a35b458]444
[37c312a]445 if (position == wstr_length(current)) {
446 /* Insert a space after the last completed argument */
447 if (wstr_linsert(current, ' ', position, MAX_CMDLINE)) {
448 printf("%ls", current + position);
449 position++;
[0c8e692]450 }
451 }
452 continue;
453 }
[a35b458]454
[c8bf88d]455 if (ch == U_LEFT_ARROW) {
456 /* Left */
457 if (position > 0) {
458 putchar('\b');
459 position--;
460 }
461 continue;
462 }
[a35b458]463
[c8bf88d]464 if (ch == U_RIGHT_ARROW) {
465 /* Right */
466 if (position < wstr_length(current)) {
467 putchar(current[position]);
468 position++;
469 }
470 continue;
471 }
[a35b458]472
[c8bf88d]473 if ((ch == U_UP_ARROW) || (ch == U_DOWN_ARROW)) {
474 /* Up, down */
475 print_cc('\b', position);
476 print_cc(' ', wstr_length(current));
477 print_cc('\b', wstr_length(current));
[a35b458]478
[c8bf88d]479 if (ch == U_UP_ARROW) {
480 /* Up */
481 if (history_pos == 0)
482 history_pos = KCONSOLE_HISTORY - 1;
483 else
484 history_pos--;
485 } else {
486 /* Down */
487 history_pos++;
488 history_pos = history_pos % KCONSOLE_HISTORY;
489 }
490 current = history[history_pos];
491 printf("%ls", current);
492 position = wstr_length(current);
493 continue;
494 }
[a35b458]495
[c8bf88d]496 if (ch == U_HOME_ARROW) {
497 /* Home */
498 print_cc('\b', position);
499 position = 0;
500 continue;
501 }
[a35b458]502
[c8bf88d]503 if (ch == U_END_ARROW) {
504 /* End */
505 printf("%ls", current + position);
506 position = wstr_length(current);
507 continue;
508 }
[a35b458]509
[c8bf88d]510 if (ch == U_DELETE) {
511 /* Delete */
512 if (position == wstr_length(current))
[0c8e692]513 continue;
[a35b458]514
[c8bf88d]515 if (wstr_remove(current, position)) {
516 printf("%ls ", current + position);
517 print_cc('\b', wstr_length(current) - position + 1);
[0c8e692]518 }
519 continue;
520 }
[a35b458]521
[d6c8ff6]522 if (wstr_linsert(current, ch, position, MAX_CMDLINE)) {
523 printf("%ls", current + position);
524 position++;
525 print_cc('\b', wstr_length(current) - position);
526 }
[ba276f7]527 }
[a35b458]528
[d6c8ff6]529 if (wstr_length(current) > 0) {
530 history_pos++;
531 history_pos = history_pos % KCONSOLE_HISTORY;
[2677758]532 }
[a35b458]533
[a7199c2]534 free(tmp);
[d6c8ff6]535 return current;
[2677758]536}
[ff3b3197]537
[d6c8ff6]538bool kconsole_check_poll(void)
[76fca31]539{
[d6c8ff6]540 return check_poll(stdin);
[76fca31]541}
542
[7a0359b]543NO_TRACE static bool parse_int_arg(const char *text, size_t len,
[96b02eb9]544 sysarg_t *result)
[91c78c9]545{
546 bool isaddr = false;
[e5fcf00]547 bool isptr = false;
[a35b458]548
[91c78c9]549 /* If we get a name, try to find it in symbol table */
[d0da921]550 if (text[0] == '&') {
551 isaddr = true;
[cf5ddf6]552 text++;
553 len--;
[d0da921]554 } else if (text[0] == '*') {
555 isptr = true;
[cf5ddf6]556 text++;
557 len--;
[d0da921]558 }
[a35b458]559
[d6c8ff6]560 if ((text[0] < '0') || (text[0] > '9')) {
561 char symname[MAX_SYMBOL_NAME];
[f4b1535]562 str_ncpy(symname, MAX_SYMBOL_NAME, text, len + 1);
[a35b458]563
[d6c8ff6]564 uintptr_t symaddr;
[b7fd2a0]565 errno_t rc = symtab_addr_lookup(symname, &symaddr);
[e16e0d59]566 switch (rc) {
567 case ENOENT:
[cf5ddf6]568 printf("Symbol %s not found.\n", symname);
[d6c8ff6]569 return false;
[e16e0d59]570 case EOVERFLOW:
[cf5ddf6]571 printf("Duplicate symbol %s.\n", symname);
[91c78c9]572 symtab_print_search(symname);
[d6c8ff6]573 return false;
574 case ENOTSUP:
[e16e0d59]575 printf("No symbol information available.\n");
[d6c8ff6]576 return false;
[4ce914d4]577 case EOK:
578 if (isaddr)
[96b02eb9]579 *result = (sysarg_t) symaddr;
[4ce914d4]580 else if (isptr)
[96b02eb9]581 *result = **((sysarg_t **) symaddr);
[4ce914d4]582 else
[96b02eb9]583 *result = *((sysarg_t *) symaddr);
[4ce914d4]584 break;
585 default:
586 printf("Unknown error.\n");
587 return false;
[91c78c9]588 }
[d6c8ff6]589 } else {
590 /* It's a number - convert it */
[4ce914d4]591 uint64_t value;
[9b11a971]592 char *end;
[b7fd2a0]593 errno_t rc = str_uint64_t(text, &end, 0, false, &value);
[9b11a971]594 if (end != text + len)
595 rc = EINVAL;
[4ce914d4]596 switch (rc) {
597 case EINVAL:
[a7d8739]598 printf("Invalid number '%s'.\n", text);
[4ce914d4]599 return false;
600 case EOVERFLOW:
[a7d8739]601 printf("Integer overflow in '%s'.\n", text);
[4ce914d4]602 return false;
603 case EOK:
[96b02eb9]604 *result = (sysarg_t) value;
[4ce914d4]605 if (isptr)
[96b02eb9]606 *result = *((sysarg_t *) *result);
[4ce914d4]607 break;
608 default:
[a7d8739]609 printf("Unknown error parsing '%s'.\n", text);
[4ce914d4]610 return false;
611 }
[c102a5c8]612 }
[a35b458]613
[d6c8ff6]614 return true;
615}
[d0da921]616
[d6c8ff6]617/** Parse argument.
618 *
619 * Find start and end positions of command line argument.
620 *
621 * @param cmdline Command line as read from the input device.
622 * @param size Size (in bytes) of the string.
623 * @param start On entry, 'start' contains pointer to the offset
624 * of the first unprocessed character of cmdline.
625 * On successful exit, it marks beginning of the next argument.
626 * @param end Undefined on entry. On exit, 'end' is the offset of the first
627 * character behind the next argument.
628 *
629 * @return False on failure, true on success.
630 *
631 */
[7a0359b]632NO_TRACE static bool parse_argument(const char *cmdline, size_t size,
633 size_t *start, size_t *end)
[d6c8ff6]634{
[63e27ef]635 assert(start != NULL);
636 assert(end != NULL);
[a35b458]637
[d6c8ff6]638 bool found_start = false;
639 size_t offset = *start;
640 size_t prev = *start;
641 wchar_t ch;
[a35b458]642
[d6c8ff6]643 while ((ch = str_decode(cmdline, &offset, size)) != 0) {
644 if (!found_start) {
645 if (!isspace(ch)) {
646 *start = prev;
647 found_start = true;
648 }
649 } else {
650 if (isspace(ch))
651 break;
652 }
[a35b458]653
[d6c8ff6]654 prev = offset;
655 }
[a7b1071]656 *end = prev;
[a35b458]657
[d6c8ff6]658 return found_start;
[91c78c9]659}
660
[ff3b3197]661/** Parse command line.
662 *
[1e01a35]663 * @param cmdline Command line as read from input device.
[d6c8ff6]664 * @param size Size (in bytes) of the string.
[ff3b3197]665 *
666 * @return Structure describing the command.
[d6c8ff6]667 *
[ff3b3197]668 */
[7a0359b]669NO_TRACE static cmd_info_t *parse_cmdline(const char *cmdline, size_t size)
[ff3b3197]670{
[d6c8ff6]671 size_t start = 0;
672 size_t end = 0;
673 if (!parse_argument(cmdline, size, &start, &end)) {
[ff3b3197]674 /* Command line did not contain alphanumeric word. */
675 return NULL;
676 }
677 spinlock_lock(&cmd_lock);
[a35b458]678
[d6c8ff6]679 cmd_info_t *cmd = NULL;
[a35b458]680
[feeac0d]681 list_foreach(cmd_list, link, cmd_info_t, hlp) {
[ff3b3197]682 spinlock_lock(&hlp->lock);
[a35b458]683
[d6c8ff6]684 if (str_lcmp(hlp->name, cmdline + start,
685 max(str_length(hlp->name),
[563d6077]686 str_nlength(cmdline + start, (size_t) (end - start)))) == 0) {
[ff3b3197]687 cmd = hlp;
688 break;
689 }
[a35b458]690
[ff3b3197]691 spinlock_unlock(&hlp->lock);
692 }
[a35b458]693
[d6c8ff6]694 spinlock_unlock(&cmd_lock);
[a35b458]695
[ff3b3197]696 if (!cmd) {
697 /* Unknown command. */
[f4338d2]698 printf("Unknown command.\n");
[ff3b3197]699 return NULL;
700 }
[a35b458]701
[ff3b3197]702 /* cmd == hlp is locked */
[a35b458]703
[ff3b3197]704 /*
705 * The command line must be further analyzed and
706 * the parameters therefrom must be matched and
707 * converted to those specified in the cmd info
708 * structure.
709 */
[a35b458]710
[d6c8ff6]711 bool error = false;
[98000fb]712 size_t i;
[f4338d2]713 for (i = 0; i < cmd->argc; i++) {
[c0f13d2]714 char *buf;
[a35b458]715
[d6c8ff6]716 start = end;
717 if (!parse_argument(cmdline, size, &start, &end)) {
[c0f13d2]718 if (cmd->argv[i].type == ARG_TYPE_STRING_OPTIONAL) {
719 buf = (char *) cmd->argv[i].buffer;
720 str_cpy(buf, cmd->argv[i].len, "");
721 continue;
722 }
[a35b458]723
[f4338d2]724 printf("Too few arguments.\n");
725 spinlock_unlock(&cmd->lock);
726 return NULL;
727 }
[a35b458]728
[f4338d2]729 switch (cmd->argv[i].type) {
[6e716a59]730 case ARG_TYPE_STRING:
[c0f13d2]731 case ARG_TYPE_STRING_OPTIONAL:
[093752c]732 buf = (char *) cmd->argv[i].buffer;
[f4b1535]733 str_ncpy(buf, cmd->argv[i].len, cmdline + start,
[87d71bf]734 end - start);
[f4338d2]735 break;
[d6c8ff6]736 case ARG_TYPE_INT:
737 if (!parse_int_arg(cmdline + start, end - start,
[cf5ddf6]738 &cmd->argv[i].intval))
[d6c8ff6]739 error = true;
[6e716a59]740 break;
[91c78c9]741 case ARG_TYPE_VAR:
[d6c8ff6]742 if ((start < end - 1) && (cmdline[start] == '"')) {
743 if (cmdline[end - 1] == '"') {
744 buf = (char *) cmd->argv[i].buffer;
[f4b1535]745 str_ncpy(buf, cmd->argv[i].len,
746 cmdline + start + 1,
747 (end - start) - 1);
[96b02eb9]748 cmd->argv[i].intval = (sysarg_t) buf;
[d6c8ff6]749 cmd->argv[i].vartype = ARG_TYPE_STRING;
750 } else {
[b62d5614]751 printf("Wrong syntax.\n");
[d6c8ff6]752 error = true;
753 }
754 } else if (parse_int_arg(cmdline + start,
755 end - start, &cmd->argv[i].intval)) {
[91c78c9]756 cmd->argv[i].vartype = ARG_TYPE_INT;
[cf5ddf6]757 } else {
[91c78c9]758 printf("Unrecognized variable argument.\n");
[d6c8ff6]759 error = true;
[6e716a59]760 }
[91c78c9]761 break;
[6e716a59]762 case ARG_TYPE_INVALID:
763 default:
[d6c8ff6]764 printf("Invalid argument type\n");
765 error = true;
[f4338d2]766 break;
767 }
768 }
[a35b458]769
[80bff342]770 if (error) {
771 spinlock_unlock(&cmd->lock);
772 return NULL;
773 }
[a35b458]774
[d6c8ff6]775 start = end;
776 if (parse_argument(cmdline, size, &start, &end)) {
[f4338d2]777 printf("Too many arguments.\n");
778 spinlock_unlock(&cmd->lock);
779 return NULL;
780 }
[a35b458]781
[ff3b3197]782 spinlock_unlock(&cmd->lock);
783 return cmd;
784}
785
[d6c8ff6]786/** Kernel console prompt.
[f4338d2]787 *
[d6c8ff6]788 * @param prompt Kernel console prompt (e.g kconsole/panic).
789 * @param msg Message to display in the beginning.
790 * @param kcon Wait for keypress to show the prompt
791 * and never exit.
[f4338d2]792 *
793 */
[a000878c]794void kconsole(const char *prompt, const char *msg, bool kcon)
[f4338d2]795{
[d6c8ff6]796 if (!stdin) {
797 LOG("No stdin for kernel console");
798 return;
799 }
[a35b458]800
[d6c8ff6]801 if (msg)
802 printf("%s", msg);
[a35b458]803
[d6c8ff6]804 if (kcon)
[44b7783]805 indev_pop_character(stdin);
[d6c8ff6]806 else
807 printf("Type \"exit\" to leave the console.\n");
[a35b458]808
[a7199c2]809 char *cmdline = malloc(STR_BOUNDS(MAX_CMDLINE), 0);
[d6c8ff6]810 while (true) {
811 wchar_t *tmp = clever_readline((char *) prompt, stdin);
[98000fb]812 size_t len = wstr_length(tmp);
[d6c8ff6]813 if (!len)
814 continue;
[a35b458]815
[0f06dbc]816 wstr_to_str(cmdline, STR_BOUNDS(MAX_CMDLINE), tmp);
[a35b458]817
[d6c8ff6]818 if ((!kcon) && (len == 4) && (str_lcmp(cmdline, "exit", 4) == 0))
819 break;
[a35b458]820
[d6c8ff6]821 cmd_info_t *cmd_info = parse_cmdline(cmdline, STR_BOUNDS(MAX_CMDLINE));
822 if (!cmd_info)
823 continue;
[a35b458]824
[d6c8ff6]825 (void) cmd_info->func(cmd_info->argv);
[f4338d2]826 }
[a7199c2]827 free(cmdline);
[d6c8ff6]828}
[f4338d2]829
[d6c8ff6]830/** Kernel console managing thread.
831 *
832 */
833void kconsole_thread(void *data)
834{
835 kconsole("kconsole", "Kernel console ready (press any key to activate)\n", true);
[f4338d2]836}
[b45c443]837
[06e1e95]838/** @}
[b45c443]839 */
Note: See TracBrowser for help on using the repository browser.