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
Line 
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/** @addtogroup genericconsole
30 * @{
31 */
32
33/**
34 * @file kconsole.c
35 * @brief Kernel console.
36 *
37 * This file contains kernel thread managing the kernel console.
38 *
39 */
40
41#include <assert.h>
42#include <console/kconsole.h>
43#include <console/console.h>
44#include <console/chardev.h>
45#include <console/cmd.h>
46#include <console/prompt.h>
47#include <print.h>
48#include <panic.h>
49#include <typedefs.h>
50#include <adt/list.h>
51#include <arch.h>
52#include <macros.h>
53#include <debug.h>
54#include <halt.h>
55#include <str.h>
56#include <sysinfo/sysinfo.h>
57#include <symtab.h>
58#include <errno.h>
59#include <putchar.h>
60#include <mm/slab.h>
61
62/** Simple kernel console.
63 *
64 * The console is realized by kernel thread kconsole.
65 * It doesn't understand any useful command on its own,
66 * but makes it possible for other kernel subsystems to
67 * register their own commands.
68 */
69
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
85SPINLOCK_INITIALIZE(cmd_lock); /**< Lock protecting command list. */
86LIST_INITIALIZE(cmd_list); /**< Command list. */
87
88static wchar_t history[KCONSOLE_HISTORY][MAX_CMDLINE] = {};
89static size_t history_pos = 0;
90
91/** Initialize kconsole data structures
92 *
93 * This is the most basic initialization, almost no
94 * other kernel subsystem is ready yet.
95 *
96 */
97void kconsole_init(void)
98{
99 unsigned int i;
100
101 cmd_init();
102 for (i = 0; i < KCONSOLE_HISTORY; i++)
103 history[i][0] = 0;
104}
105
106/** Register kconsole command.
107 *
108 * @param cmd Structure describing the command.
109 *
110 * @return False on failure, true on success.
111 *
112 */
113bool cmd_register(cmd_info_t *cmd)
114{
115 spinlock_lock(&cmd_lock);
116
117 /*
118 * Make sure the command is not already listed.
119 */
120 list_foreach(cmd_list, link, cmd_info_t, hlp) {
121 if (hlp == cmd) {
122 /* The command is already there. */
123 spinlock_unlock(&cmd_lock);
124 return false;
125 }
126
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 }
135
136 if (str_cmp(hlp->name, cmd->name) == 0) {
137 /* The command is already there. */
138 spinlock_unlock(&hlp->lock);
139 spinlock_unlock(&cmd->lock);
140 spinlock_unlock(&cmd_lock);
141 return false;
142 }
143
144 spinlock_unlock(&hlp->lock);
145 spinlock_unlock(&cmd->lock);
146 }
147
148 /*
149 * Now the command can be added.
150 */
151 list_append(&cmd->link, &cmd_list);
152
153 spinlock_unlock(&cmd_lock);
154 return true;
155}
156
157/** Print count times a character */
158NO_TRACE static void print_cc(wchar_t ch, size_t count)
159{
160 size_t i;
161 for (i = 0; i < count; i++)
162 putchar(ch);
163}
164
165/** Try to find a command beginning with prefix */
166const char *cmdtab_enum(const char *name, const char **h, void **ctx)
167{
168 link_t **startpos = (link_t**) ctx;
169 size_t namelen = str_length(name);
170
171 spinlock_lock(&cmd_lock);
172
173 if (*startpos == NULL)
174 *startpos = cmd_list.head.next;
175
176 for (; *startpos != &cmd_list.head; *startpos = (*startpos)->next) {
177 cmd_info_t *hlp = list_get_instance(*startpos, cmd_info_t, link);
178
179 const char *curname = hlp->name;
180 if (str_length(curname) < namelen)
181 continue;
182
183 if (str_lcmp(curname, name, namelen) == 0) {
184 *startpos = (*startpos)->next;
185 if (h)
186 *h = hlp->description;
187
188 spinlock_unlock(&cmd_lock);
189 return (curname + str_lsize(curname, namelen));
190 }
191 }
192
193 spinlock_unlock(&cmd_lock);
194 return NULL;
195}
196
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
203 *
204 */
205NO_TRACE static int cmdtab_compl(char *input, size_t size, indev_t *indev,
206 hints_enum_func_t hints_enum)
207{
208 const char *name = input;
209
210 size_t found = 0;
211
212 /*
213 * Maximum Match Length: Length of longest matching common
214 * substring in case more than one match is found.
215 */
216 size_t max_match_len = size;
217 size_t max_match_len_tmp = size;
218 void *pos = NULL;
219 const char *hint;
220 const char *help;
221 char *output = malloc(MAX_CMDLINE, 0);
222 size_t hints_to_show = MAX_TAB_HINTS - 1;
223 size_t total_hints_shown = 0;
224 bool continue_showing_hints = true;
225
226 output[0] = 0;
227
228 while ((hint = hints_enum(name, NULL, &pos))) {
229 if ((found == 0) || (str_length(hint) > str_length(output)))
230 str_cpy(output, MAX_CMDLINE, hint);
231
232 found++;
233 }
234
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 */
239 if (found > MAX_TAB_HINTS) {
240 printf("\n");
241 continue_showing_hints =
242 console_prompt_display_all_hints(indev, found);
243 }
244
245 if ((found > 1) && (str_length(output) != 0)) {
246 printf("\n");
247 pos = NULL;
248 while ((hint = hints_enum(name, &help, &pos))) {
249
250 if (continue_showing_hints) {
251 if (help)
252 printf("%s%s (%s)\n", name, hint, help);
253 else
254 printf("%s%s\n", name, hint);
255
256 --hints_to_show;
257 ++total_hints_shown;
258
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);
263 }
264 }
265
266 for (max_match_len_tmp = 0;
267 (output[max_match_len_tmp] ==
268 hint[max_match_len_tmp]) &&
269 (max_match_len_tmp < max_match_len); ++max_match_len_tmp);
270
271 max_match_len = max_match_len_tmp;
272 }
273
274 /* Keep only the characters common in all completions */
275 output[max_match_len] = 0;
276 }
277
278 if (found > 0)
279 str_cpy(input, size, output);
280
281 free(output);
282 return found;
283}
284
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;
290
291 while (isspace(cmdline[start]))
292 start++;
293
294 end = start + 1;
295
296 while (!isspace(cmdline[end]))
297 end++;
298
299 tmp = malloc(STR_BOUNDS(end - start + 1), 0);
300
301 wstr_to_str(tmp, end - start + 1, &cmdline[start]);
302
303 spinlock_lock(&cmd_lock);
304
305 list_foreach(cmd_list, link, cmd_info_t, hlp) {
306 spinlock_lock(&hlp->lock);
307
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 }
314
315 spinlock_unlock(&hlp->lock);
316 }
317
318 free(tmp);
319 spinlock_unlock(&cmd_lock);
320
321 return NULL;
322}
323
324NO_TRACE static wchar_t *clever_readline(const char *prompt, indev_t *indev)
325{
326 printf("%s> ", prompt);
327
328 size_t position = 0;
329 wchar_t *current = history[history_pos];
330 current[0] = 0;
331 char *tmp = malloc(STR_BOUNDS(MAX_CMDLINE), 0);
332
333 while (true) {
334 wchar_t ch = indev_pop_character(indev);
335
336 if (ch == '\n') {
337 /* Enter */
338 putchar(ch);
339 break;
340 }
341
342 if (ch == '\b') {
343 /* Backspace */
344 if (position == 0)
345 continue;
346
347 if (wstr_remove(current, position - 1)) {
348 position--;
349 putchar('\b');
350 printf("%ls ", current + position);
351 print_cc('\b', wstr_length(current) - position + 1);
352 continue;
353 }
354 }
355
356 if (ch == '\t') {
357 /* Tab completion */
358
359 /* Move to the end of the word */
360 for (; (current[position] != 0) && (!isspace(current[position]));
361 position++)
362 putchar(current[position]);
363
364
365 /*
366 * Find the beginning of the word
367 * and copy it to tmp
368 */
369 size_t beg;
370 unsigned narg = 0;
371 if (position == 0) {
372 tmp[0] = '\0';
373 beg = 0;
374 } else {
375 for (beg = position - 1;
376 (beg > 0) && (!isspace(current[beg]));
377 beg--);
378
379 if (isspace(current[beg]))
380 beg++;
381
382 wstr_to_str(tmp, position - beg + 1, current + beg);
383 }
384
385 /* Count which argument number are we tabbing (narg=0 is cmd) */
386 bool sp = false;
387 for (; beg > 0; beg--) {
388 if (isspace(current[beg])) {
389 if (!sp) {
390 narg++;
391 sp = true;
392 }
393 } else
394 sp = false;
395 }
396
397 if (narg && isspace(current[0]))
398 narg--;
399
400 int found;
401 if (narg == 0) {
402 /* Command completion */
403 found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev,
404 cmdtab_enum);
405 } else {
406 /* Arguments completion */
407 cmd_info_t *cmd = parse_cmd(current);
408 if (!cmd || !cmd->hints_enum || cmd->argc < narg)
409 continue;
410 found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev,
411 cmd->hints_enum);
412 }
413
414 if (found == 0)
415 continue;
416
417 /*
418 * We have hints, possibly many. In case of more than one hint,
419 * tmp will contain the common prefix.
420 */
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;
426
427 i++;
428 }
429
430 if (found > 1) {
431 /* No unique hint, list was printed */
432 printf("%s> ", prompt);
433 printf("%ls", current);
434 position += str_length(tmp);
435 print_cc('\b', wstr_length(current) - position);
436 continue;
437 }
438
439 /* We have a hint */
440
441 printf("%ls", current + position);
442 position += str_length(tmp);
443 print_cc('\b', wstr_length(current) - position);
444
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++;
450 }
451 }
452 continue;
453 }
454
455 if (ch == U_LEFT_ARROW) {
456 /* Left */
457 if (position > 0) {
458 putchar('\b');
459 position--;
460 }
461 continue;
462 }
463
464 if (ch == U_RIGHT_ARROW) {
465 /* Right */
466 if (position < wstr_length(current)) {
467 putchar(current[position]);
468 position++;
469 }
470 continue;
471 }
472
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));
478
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 }
495
496 if (ch == U_HOME_ARROW) {
497 /* Home */
498 print_cc('\b', position);
499 position = 0;
500 continue;
501 }
502
503 if (ch == U_END_ARROW) {
504 /* End */
505 printf("%ls", current + position);
506 position = wstr_length(current);
507 continue;
508 }
509
510 if (ch == U_DELETE) {
511 /* Delete */
512 if (position == wstr_length(current))
513 continue;
514
515 if (wstr_remove(current, position)) {
516 printf("%ls ", current + position);
517 print_cc('\b', wstr_length(current) - position + 1);
518 }
519 continue;
520 }
521
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 }
527 }
528
529 if (wstr_length(current) > 0) {
530 history_pos++;
531 history_pos = history_pos % KCONSOLE_HISTORY;
532 }
533
534 free(tmp);
535 return current;
536}
537
538bool kconsole_check_poll(void)
539{
540 return check_poll(stdin);
541}
542
543NO_TRACE static bool parse_int_arg(const char *text, size_t len,
544 sysarg_t *result)
545{
546 bool isaddr = false;
547 bool isptr = false;
548
549 /* If we get a name, try to find it in symbol table */
550 if (text[0] == '&') {
551 isaddr = true;
552 text++;
553 len--;
554 } else if (text[0] == '*') {
555 isptr = true;
556 text++;
557 len--;
558 }
559
560 if ((text[0] < '0') || (text[0] > '9')) {
561 char symname[MAX_SYMBOL_NAME];
562 str_ncpy(symname, MAX_SYMBOL_NAME, text, len + 1);
563
564 uintptr_t symaddr;
565 errno_t rc = symtab_addr_lookup(symname, &symaddr);
566 switch (rc) {
567 case ENOENT:
568 printf("Symbol %s not found.\n", symname);
569 return false;
570 case EOVERFLOW:
571 printf("Duplicate symbol %s.\n", symname);
572 symtab_print_search(symname);
573 return false;
574 case ENOTSUP:
575 printf("No symbol information available.\n");
576 return false;
577 case EOK:
578 if (isaddr)
579 *result = (sysarg_t) symaddr;
580 else if (isptr)
581 *result = **((sysarg_t **) symaddr);
582 else
583 *result = *((sysarg_t *) symaddr);
584 break;
585 default:
586 printf("Unknown error.\n");
587 return false;
588 }
589 } else {
590 /* It's a number - convert it */
591 uint64_t value;
592 char *end;
593 errno_t rc = str_uint64_t(text, &end, 0, false, &value);
594 if (end != text + len)
595 rc = EINVAL;
596 switch (rc) {
597 case EINVAL:
598 printf("Invalid number '%s'.\n", text);
599 return false;
600 case EOVERFLOW:
601 printf("Integer overflow in '%s'.\n", text);
602 return false;
603 case EOK:
604 *result = (sysarg_t) value;
605 if (isptr)
606 *result = *((sysarg_t *) *result);
607 break;
608 default:
609 printf("Unknown error parsing '%s'.\n", text);
610 return false;
611 }
612 }
613
614 return true;
615}
616
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 */
632NO_TRACE static bool parse_argument(const char *cmdline, size_t size,
633 size_t *start, size_t *end)
634{
635 assert(start != NULL);
636 assert(end != NULL);
637
638 bool found_start = false;
639 size_t offset = *start;
640 size_t prev = *start;
641 wchar_t ch;
642
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 }
653
654 prev = offset;
655 }
656 *end = prev;
657
658 return found_start;
659}
660
661/** Parse command line.
662 *
663 * @param cmdline Command line as read from input device.
664 * @param size Size (in bytes) of the string.
665 *
666 * @return Structure describing the command.
667 *
668 */
669NO_TRACE static cmd_info_t *parse_cmdline(const char *cmdline, size_t size)
670{
671 size_t start = 0;
672 size_t end = 0;
673 if (!parse_argument(cmdline, size, &start, &end)) {
674 /* Command line did not contain alphanumeric word. */
675 return NULL;
676 }
677 spinlock_lock(&cmd_lock);
678
679 cmd_info_t *cmd = NULL;
680
681 list_foreach(cmd_list, link, cmd_info_t, hlp) {
682 spinlock_lock(&hlp->lock);
683
684 if (str_lcmp(hlp->name, cmdline + start,
685 max(str_length(hlp->name),
686 str_nlength(cmdline + start, (size_t) (end - start)))) == 0) {
687 cmd = hlp;
688 break;
689 }
690
691 spinlock_unlock(&hlp->lock);
692 }
693
694 spinlock_unlock(&cmd_lock);
695
696 if (!cmd) {
697 /* Unknown command. */
698 printf("Unknown command.\n");
699 return NULL;
700 }
701
702 /* cmd == hlp is locked */
703
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 */
710
711 bool error = false;
712 size_t i;
713 for (i = 0; i < cmd->argc; i++) {
714 char *buf;
715
716 start = end;
717 if (!parse_argument(cmdline, size, &start, &end)) {
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 }
723
724 printf("Too few arguments.\n");
725 spinlock_unlock(&cmd->lock);
726 return NULL;
727 }
728
729 switch (cmd->argv[i].type) {
730 case ARG_TYPE_STRING:
731 case ARG_TYPE_STRING_OPTIONAL:
732 buf = (char *) cmd->argv[i].buffer;
733 str_ncpy(buf, cmd->argv[i].len, cmdline + start,
734 end - start);
735 break;
736 case ARG_TYPE_INT:
737 if (!parse_int_arg(cmdline + start, end - start,
738 &cmd->argv[i].intval))
739 error = true;
740 break;
741 case ARG_TYPE_VAR:
742 if ((start < end - 1) && (cmdline[start] == '"')) {
743 if (cmdline[end - 1] == '"') {
744 buf = (char *) cmd->argv[i].buffer;
745 str_ncpy(buf, cmd->argv[i].len,
746 cmdline + start + 1,
747 (end - start) - 1);
748 cmd->argv[i].intval = (sysarg_t) buf;
749 cmd->argv[i].vartype = ARG_TYPE_STRING;
750 } else {
751 printf("Wrong syntax.\n");
752 error = true;
753 }
754 } else if (parse_int_arg(cmdline + start,
755 end - start, &cmd->argv[i].intval)) {
756 cmd->argv[i].vartype = ARG_TYPE_INT;
757 } else {
758 printf("Unrecognized variable argument.\n");
759 error = true;
760 }
761 break;
762 case ARG_TYPE_INVALID:
763 default:
764 printf("Invalid argument type\n");
765 error = true;
766 break;
767 }
768 }
769
770 if (error) {
771 spinlock_unlock(&cmd->lock);
772 return NULL;
773 }
774
775 start = end;
776 if (parse_argument(cmdline, size, &start, &end)) {
777 printf("Too many arguments.\n");
778 spinlock_unlock(&cmd->lock);
779 return NULL;
780 }
781
782 spinlock_unlock(&cmd->lock);
783 return cmd;
784}
785
786/** Kernel console prompt.
787 *
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.
792 *
793 */
794void kconsole(const char *prompt, const char *msg, bool kcon)
795{
796 if (!stdin) {
797 LOG("No stdin for kernel console");
798 return;
799 }
800
801 if (msg)
802 printf("%s", msg);
803
804 if (kcon)
805 indev_pop_character(stdin);
806 else
807 printf("Type \"exit\" to leave the console.\n");
808
809 char *cmdline = malloc(STR_BOUNDS(MAX_CMDLINE), 0);
810 while (true) {
811 wchar_t *tmp = clever_readline((char *) prompt, stdin);
812 size_t len = wstr_length(tmp);
813 if (!len)
814 continue;
815
816 wstr_to_str(cmdline, STR_BOUNDS(MAX_CMDLINE), tmp);
817
818 if ((!kcon) && (len == 4) && (str_lcmp(cmdline, "exit", 4) == 0))
819 break;
820
821 cmd_info_t *cmd_info = parse_cmdline(cmdline, STR_BOUNDS(MAX_CMDLINE));
822 if (!cmd_info)
823 continue;
824
825 (void) cmd_info->func(cmd_info->argv);
826 }
827 free(cmdline);
828}
829
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);
836}
837
838/** @}
839 */
Note: See TracBrowser for help on using the repository browser.