7 * Copyright (c) 2008, Swedish Institute of Computer Science.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the Institute nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * This file is part of the Contiki operating system.
36 * $Id: shell.c,v 1.13 2009/03/02 20:44:15 adamdunkels Exp $
41 * The shell application
43 * Adam Dunkels <adam@sics.se>
47 #include "contiki-lib.h"
59 int shell_event_input
;
61 static struct process
*front_process
;
63 static unsigned long time_offset
;
65 PROCESS(shell_process
, "Shell");
66 PROCESS(shell_server_process
, "Shell server");
67 /*---------------------------------------------------------------------------*/
68 PROCESS(help_command_process
, "help");
69 SHELL_COMMAND(help_command
, "help", "help: shows this help",
70 &help_command_process
);
71 SHELL_COMMAND(question_command
, "?", "?: shows this help",
72 &help_command_process
);
73 PROCESS(shell_killall_process
, "killall");
74 SHELL_COMMAND(killall_command
, "killall", "killall: stop all running commands",
75 &shell_killall_process
);
76 PROCESS(shell_kill_process
, "kill");
77 SHELL_COMMAND(kill_command
, "kill", "kill <command>: stop a specific command",
79 PROCESS(shell_null_process
, "null");
80 SHELL_COMMAND(null_command
,
82 "null: discard input",
84 /*---------------------------------------------------------------------------*/
85 PROCESS_THREAD(shell_null_process
, ev
, data
)
87 struct shell_input
*input
;
90 PROCESS_WAIT_EVENT_UNTIL(ev
== shell_event_input
);
93 if(input
->len1
+ input
->len2
== 0) {
99 /*---------------------------------------------------------------------------*/
101 command_kill(struct shell_command
*c
)
104 shell_output_str(&killall_command
, "Stopping command ", c
->command
);
105 process_exit(c
->process
);
108 /*---------------------------------------------------------------------------*/
112 struct shell_command
*c
;
113 for(c
= list_head(commands
);
116 if(c
!= &killall_command
&& process_is_running(c
->process
)) {
121 /*---------------------------------------------------------------------------*/
122 PROCESS_THREAD(shell_killall_process
, ev
, data
)
131 /*---------------------------------------------------------------------------*/
132 PROCESS_THREAD(shell_kill_process
, ev
, data
)
134 struct shell_command
*c
;
139 if(name
== NULL
|| strlen(name
) == 0) {
140 shell_output_str(&kill_command
,
141 "kill <command>: command name must be given", "");
144 for(c
= list_head(commands
);
147 if(strcmp(name
, c
->command
) == 0 &&
148 c
!= &kill_command
&&
149 process_is_running(c
->process
)) {
155 shell_output_str(&kill_command
, "Command not found: ", name
);
159 /*---------------------------------------------------------------------------*/
160 PROCESS_THREAD(help_command_process
, ev
, data
)
162 struct shell_command
*c
;
165 shell_output_str(&help_command
, "Available commands:", "");
166 for(c
= list_head(commands
);
169 shell_output_str(&help_command
, c
->description
, "");
174 /*---------------------------------------------------------------------------*/
176 replace_braces(char *commandline
)
181 for(ptr
= commandline
; *ptr
!= 0; ++ptr
) {
187 } else if(*ptr
== '}') {
195 /*---------------------------------------------------------------------------*/
197 find_pipe(char *commandline
)
202 for(ptr
= commandline
; *ptr
!= 0; ++ptr
) {
205 } else if(*ptr
== '}') {
207 } else if(*ptr
== '|') {
215 /*---------------------------------------------------------------------------*/
216 static struct shell_command
*
217 start_command(char *commandline
, struct shell_command
*child
)
221 struct shell_command
*c
;
223 /* Shave off any leading spaces. */
224 while(*commandline
== ' ') {
228 /* Find the next command in a pipeline and start it. */
229 next
= find_pipe(commandline
);
232 child
= start_command(next
+ 1, child
);
235 /* Separate the command arguments, and remove braces. */
236 replace_braces(commandline
);
237 args
= strchr(commandline
, ' ');
242 /* Shave off any trailing spaces. */
243 command_len
= (int)strlen(commandline
);
244 while(command_len
> 0 && commandline
[command_len
- 1] == ' ') {
245 commandline
[command_len
- 1] = 0;
250 command_len
= (int)strlen(commandline
);
251 args
= &commandline
[command_len
];
253 command_len
= (int)(args
- commandline
- 1);
258 /* Go through list of commands to find a match for the first word in
260 for(c
= list_head(commands
);
262 !(strncmp(c
->command
, commandline
, command_len
) == 0 &&
263 c
->command
[command_len
] == 0);
267 shell_output_str(NULL
, commandline
, ": command not found (try 'help')");
270 } else if(process_is_running(c
->process
) || child
== c
) {
271 shell_output_str(NULL
, commandline
, ": command already running");
276 /* printf("shell: start_command starting '%s'\n", c->process->name);*/
277 /* Start a new process for the command. */
278 process_start(c
->process
, args
);
283 /*---------------------------------------------------------------------------*/
285 shell_start_command(char *commandline
, int commandline_len
,
286 struct shell_command
*child
,
287 struct process
**started_process
)
289 struct shell_command
*c
;
292 if(commandline_len
== 0) {
293 if(started_process
!= NULL
) {
294 *started_process
= NULL
;
296 return SHELL_NOTHING
;
299 if(commandline
[commandline_len
- 1] == '&') {
300 commandline
[commandline_len
- 1] = 0;
305 c
= start_command(commandline
, child
);
307 /* Return a pointer to the started process, so that the caller can
308 wait for the process to complete. */
309 if(c
!= NULL
&& started_process
!= NULL
) {
310 *started_process
= c
->process
;
312 return SHELL_BACKGROUND
;
314 return SHELL_FOREGROUND
;
317 return SHELL_NOTHING
;
319 /*---------------------------------------------------------------------------*/
321 input_to_child_command(struct shell_command
*c
,
322 char *data1
, int len1
,
323 const char *data2
, int len2
)
325 struct shell_input input
;
326 if(process_is_running(c
->process
)) {
331 process_post_synch(c
->process
, shell_event_input
, &input
);
334 /*---------------------------------------------------------------------------*/
336 shell_input(char *commandline
, int commandline_len
)
338 struct shell_input input
;
340 /* printf("shell_input front_process '%s'\n", front_process->name);*/
342 if(commandline
[0] == '~' &&
343 commandline
[1] == 'K') {
344 /* process_start(&shell_killall_process, commandline);*/
345 if(front_process
!= &shell_process
) {
346 process_exit(front_process
);
349 if(process_is_running(front_process
)) {
350 input
.data1
= commandline
;
351 input
.len1
= commandline_len
;
354 process_post_synch(front_process
, shell_event_input
, &input
);
358 /*---------------------------------------------------------------------------*/
360 shell_output_str(struct shell_command
*c
, char *text1
, const char *text2
)
362 if(c
!= NULL
&& c
->child
!= NULL
) {
363 input_to_child_command(c
->child
, text1
, (int)strlen(text1
),
364 text2
, (int)strlen(text2
));
366 shell_default_output(text1
, (int)strlen(text1
),
367 text2
, (int)strlen(text2
));
370 /*---------------------------------------------------------------------------*/
372 shell_output(struct shell_command
*c
,
373 void *data1
, int len1
,
374 const void *data2
, int len2
)
376 if(c
!= NULL
&& c
->child
!= NULL
) {
377 input_to_child_command(c
->child
, data1
, len1
, data2
, len2
);
379 shell_default_output(data1
, len1
, data2
, len2
);
382 /*---------------------------------------------------------------------------*/
384 shell_unregister_command(struct shell_command
*c
)
386 list_remove(commands
, c
);
388 /*---------------------------------------------------------------------------*/
390 shell_register_command(struct shell_command
*c
)
392 struct shell_command
*i
, *p
;
395 for(i
= list_head(commands
);
397 strcmp(i
->command
, c
->command
) < 0;
402 list_push(commands
, c
);
403 } else if(i
== NULL
) {
404 list_add(commands
, c
);
406 list_insert(commands
, p
, c
);
409 /*---------------------------------------------------------------------------*/
410 PROCESS_THREAD(shell_process
, ev
, data
)
412 static struct process
*started_process
;
415 /* Let the system start up before showing the prompt. */
419 shell_prompt("Contiki> ");
421 PROCESS_WAIT_EVENT_UNTIL(ev
== shell_event_input
);
423 struct shell_input
*input
= data
;
426 ret
= shell_start_command(input
->data1
, input
->len1
, NULL
,
429 if(started_process
!= NULL
&&
430 ret
== SHELL_FOREGROUND
&&
431 process_is_running(started_process
)) {
432 front_process
= started_process
;
433 PROCESS_WAIT_EVENT_UNTIL(ev
== PROCESS_EVENT_EXITED
&&
434 data
== started_process
);
436 front_process
= &shell_process
;
442 /*---------------------------------------------------------------------------*/
443 PROCESS_THREAD(shell_server_process
, ev
, data
)
446 struct shell_command
*c
;
447 static struct etimer etimer
;
450 etimer_set(&etimer
, CLOCK_SECOND
* 10);
452 PROCESS_WAIT_EVENT();
453 if(ev
== PROCESS_EVENT_EXITED
) {
455 /* printf("process exited '%s' (front '%s')\n", p->name,
456 front_process->name);*/
457 for(c
= list_head(commands
);
458 c
!= NULL
&& c
->process
!= p
;
461 if(c
->child
!= NULL
&& c
->child
->process
!= NULL
) {
462 /* printf("Killing '%s'\n", c->process->name);*/
463 input_to_child_command(c
->child
, "", 0, "", 0);
464 /* process_exit(c->process);*/
468 } else if(ev
== PROCESS_EVENT_TIMER
) {
469 etimer_reset(&etimer
);
470 shell_set_time(shell_time());
476 /*---------------------------------------------------------------------------*/
481 shell_register_command(&help_command
);
482 shell_register_command(&question_command
);
483 shell_register_command(&killall_command
);
484 shell_register_command(&kill_command
);
485 shell_register_command(&null_command
);
487 shell_event_input
= process_alloc_event();
489 process_start(&shell_process
, NULL
);
490 process_start(&shell_server_process
, NULL
);
492 front_process
= &shell_process
;
494 /*---------------------------------------------------------------------------*/
496 shell_strtolong(const char *str
, const char **retstr
)
499 unsigned long num
= 0;
500 const char *strptr
= str
;
506 while(*strptr
== ' ') {
510 for(i
= 0; i
< 10 && isdigit(strptr
[i
]); ++i
) {
511 num
= num
* 10 + strptr
[i
] - '0';
517 *retstr
= strptr
+ i
;
523 /*---------------------------------------------------------------------------*/
527 return clock_seconds() + time_offset
;
529 /*---------------------------------------------------------------------------*/
531 shell_set_time(unsigned long seconds
)
533 time_offset
= seconds
- clock_seconds();
535 /*---------------------------------------------------------------------------*/
539 shell_output_str(NULL
, "Contiki command shell", "");
540 shell_output_str(NULL
, "Type '?' and return for help", "");
541 shell_prompt("Contiki> ");
543 /*---------------------------------------------------------------------------*/
548 process_exit(&shell_process
);
549 process_exit(&shell_server_process
);
551 /*---------------------------------------------------------------------------*/