Subversion Repositories HelenOS-historic

Rev

Rev 512 | Rev 518 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
510 jermar 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 <main/kconsole.h>
30
#include <console/console.h>
31
#include <console/chardev.h>
32
#include <print.h>
517 jermar 33
#include <panic.h>
510 jermar 34
#include <typedefs.h>
35
#include <arch/types.h>
517 jermar 36
#include <list.h>
37
#include <arch.h>
38
#include <func.h>
39
#include <macros.h>
510 jermar 40
 
517 jermar 41
#define MAX_CMDLINE 256
42
 
43
/** Simple kernel console.
44
 *
45
 * The console is realized by kernel thread kconsole.
46
 * It doesn't understand any commands on its own, but
47
 * makes it possible for other kernel subsystems to
48
 * register their own commands.
49
 */
50
 
51
/** Locking.
52
 *
53
 * There is a list of cmd_info_t structures. This list
54
 * is protected by cmd_lock spinlock. Note that specially
55
 * the link elements of cmd_info_t are protected by
56
 * this lock.
57
 *
58
 * Each cmd_info_t also has its own lock, which protects
59
 * all elements thereof except the link element.
60
 *
61
 * cmd_lock must be acquired before any cmd_info lock.
62
 * When locking two cmd info structures, structure with
63
 * lower address must be locked first.
64
 */
65
 
66
spinlock_t cmd_lock;    /**< Lock protecting command list. */
67
link_t cmd_head;    /**< Command list. */
68
 
69
static cmd_info_t *parse_cmdline(char *cmdline, size_t len);
70
static int cmd_help(cmd_arg_t *cmd);
71
 
72
static cmd_info_t help_info;
73
 
74
/** Initialize kconsole data structures. */
75
void kconsole_init(void)
76
{
77
    spinlock_initialize(&cmd_lock);
78
    list_initialize(&cmd_head);
79
 
80
    help_info.name = "help";
81
    help_info.description = "List supported commands.";
82
    help_info.func = cmd_help;
83
    help_info.argc = 0;
84
    help_info.argv = NULL;
85
 
86
    spinlock_initialize(&help_info.lock);
87
    link_initialize(&help_info.link);
88
 
89
    if (!cmd_register(&help_info))
90
        panic("could not register command\n");
91
}
92
 
93
 
94
/** Register kconsole command.
95
 *
96
 * @param cmd Structure describing the command.
97
 *
98
 * @return 0 on failure, 1 on success.
99
 */
100
int cmd_register(cmd_info_t *cmd)
101
{
102
    ipl_t ipl;
103
    link_t *cur;
104
 
105
    ipl = interrupts_disable();
106
    spinlock_lock(&cmd_lock);
107
 
108
    /*
109
     * Make sure the command is not already listed.
110
     */
111
    for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
112
        cmd_info_t *hlp;
113
 
114
        hlp = list_get_instance(cur, cmd_info_t, link);
115
 
116
        if (hlp == cmd) {
117
            /* The command is already there. */
118
            spinlock_unlock(&cmd_lock);
119
            interrupts_restore(ipl);
120
            return 0;
121
        }
122
 
123
        /* Avoid deadlock. */
124
        if (hlp < cmd) {
125
            spinlock_lock(&hlp->lock);
126
            spinlock_lock(&cmd->lock);
127
        } else {
128
            spinlock_lock(&cmd->lock);
129
            spinlock_lock(&hlp->lock);
130
        }
131
 
132
        if ((strcmp(hlp->name, cmd->name, strlen(cmd->name)) == 0)) {
133
            /* The command is already there. */
134
            spinlock_unlock(&hlp->lock);
135
            spinlock_unlock(&cmd->lock);
136
            spinlock_unlock(&cmd_lock);
137
            interrupts_restore(ipl);
138
            return 0;
139
        }
140
 
141
        spinlock_unlock(&hlp->lock);
142
        spinlock_unlock(&cmd->lock);
143
    }
144
 
145
    /*
146
     * Now the command can be added.
147
     */
148
    list_append(&cmd->link, &cmd_head);
149
 
150
    spinlock_unlock(&cmd_lock);
151
    interrupts_restore(ipl);
152
    return 1;
153
}
154
 
510 jermar 155
/** Kernel console managing thread.
156
 *
157
 * @param arg Not used.
158
 */
159
void kconsole(void *arg)
160
{
517 jermar 161
    char cmdline[MAX_CMDLINE+1];
162
    cmd_info_t *cmd_info;
163
    count_t len;
510 jermar 164
 
165
    if (!stdin) {
166
        printf("%s: no stdin\n", __FUNCTION__);
167
        return;
168
    }
169
 
170
    while (true) {
171
        printf("%s> ", __FUNCTION__);
517 jermar 172
        len = gets(stdin, cmdline, sizeof(cmdline));
173
        cmdline[len] = '\0';
174
        cmd_info = parse_cmdline(cmdline, len);
175
        if (!cmd_info) {
176
            printf("?\n");
177
            continue;
178
        }
179
        (void) cmd_info->func(cmd_info->argv);
510 jermar 180
    }
181
}
517 jermar 182
 
183
/** Parse command line.
184
 *
185
 * @param cmdline Command line as read from input device.
186
 * @param len Command line length.
187
 *
188
 * @return Structure describing the command.
189
 */
190
cmd_info_t *parse_cmdline(char *cmdline, size_t len)
191
{
192
    index_t start = 0, end = 0;
193
    bool found_start = false;
194
    cmd_info_t *cmd = NULL;
195
    link_t *cur;
196
    ipl_t ipl;
197
    int i;
198
 
199
    for (i = 0; i < len; i++) {
200
        if (!found_start) {
201
            if (is_white(cmdline[i]))
202
                start++;
203
            else
204
                found_start = true;
205
        } else {
206
            if (is_white(cmdline[i]))
207
                break;
208
        }
209
    }
210
    end = i - 1;
211
 
212
    if (!found_start) {
213
        /* Command line did not contain alphanumeric word. */
214
        return NULL;
215
    }
216
 
217
    ipl = interrupts_disable();
218
    spinlock_lock(&cmd_lock);
219
 
220
    for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
221
        cmd_info_t *hlp;
222
 
223
        hlp = list_get_instance(cur, cmd_info_t, link);
224
        spinlock_lock(&hlp->lock);
225
 
226
        if (strcmp(hlp->name, &cmdline[start], (end - start) + 1) == 0) {
227
            cmd = hlp;
228
            break;
229
        }
230
 
231
        spinlock_unlock(&hlp->lock);
232
    }
233
 
234
    spinlock_unlock(&cmd_lock);
235
 
236
    if (!cmd) {
237
        /* Unknown command. */
238
        interrupts_restore(ipl);
239
        return NULL;
240
    }
241
 
242
    /* cmd == hlp is locked */
243
 
244
    /*
245
     * TODO:
246
     * The command line must be further analyzed and
247
     * the parameters therefrom must be matched and
248
     * converted to those specified in the cmd info
249
     * structure.
250
     */
251
 
252
    spinlock_unlock(&cmd->lock);
253
    interrupts_restore(ipl);
254
    return cmd;
255
}
256
 
257
/** List supported commands.
258
 *
259
 * @param cmd Argument vector.
260
 *
261
 * @return 0 on failure, 1 on success.
262
 */
263
int cmd_help(cmd_arg_t *cmd)
264
{
265
    link_t *cur;
266
    ipl_t ipl;
267
 
268
    ipl = interrupts_disable();
269
    spinlock_lock(&cmd_lock);
270
 
271
    for (cur = cmd_head.next; cur != &cmd_head; cur = cur->next) {
272
        cmd_info_t *hlp;
273
 
274
        hlp = list_get_instance(cur, cmd_info_t, link);
275
        spinlock_lock(&hlp->lock);
276
 
277
        printf("%s\t%s\n", hlp->name, hlp->description);
278
 
279
        spinlock_unlock(&hlp->lock);
280
    }
281
 
282
    spinlock_unlock(&cmd_lock);
283
    interrupts_restore(ipl);
284
 
285
    return 1;
286
}