[5f8c41c] | 1 | /** |
---|
| 2 | * @file |
---|
[8425e67] | 3 | * |
---|
[5f8c41c] | 4 | * @brief Instantatiate a new terminal shell. |
---|
| 5 | */ |
---|
| 6 | |
---|
[dd74e612] | 7 | /* |
---|
[5f8c41c] | 8 | * Copyright (c) 2001 Fernando Ruiz Casas <fruizcasas@gmail.com> |
---|
[dd74e612] | 9 | * |
---|
[4e5299f] | 10 | * The license and distribution terms for this file may be |
---|
| 11 | * found in the file LICENSE in this distribution or at |
---|
[c499856] | 12 | * http://www.rtems.org/license/LICENSE. |
---|
[dd74e612] | 13 | */ |
---|
[814d9588] | 14 | |
---|
[b2712e3] | 15 | #ifdef HAVE_CONFIG_H |
---|
| 16 | #include "config.h" |
---|
| 17 | #endif |
---|
[dd74e612] | 18 | |
---|
| 19 | #include <stdio.h> |
---|
[84206479] | 20 | #include <time.h> |
---|
[dd74e612] | 21 | |
---|
| 22 | #include <rtems.h> |
---|
[d007cc2] | 23 | #include <rtems/error.h> |
---|
[dd74e612] | 24 | #include <rtems/libio.h> |
---|
[aed742c] | 25 | #include <rtems/libio_.h> |
---|
[b2712e3] | 26 | #include <rtems/shell.h> |
---|
[4e5299f] | 27 | #include <rtems/shellconfig.h> |
---|
[06f8e558] | 28 | #include <rtems/console.h> |
---|
[4e5299f] | 29 | #include "internal.h" |
---|
[dd74e612] | 30 | |
---|
| 31 | #include <termios.h> |
---|
| 32 | #include <string.h> |
---|
| 33 | #include <stdlib.h> |
---|
| 34 | #include <ctype.h> |
---|
[70d689a] | 35 | #include <sys/stat.h> |
---|
[dd74e612] | 36 | #include <unistd.h> |
---|
| 37 | #include <errno.h> |
---|
[b2712e3] | 38 | #include <pwd.h> |
---|
[6cd4a5c] | 39 | #include <pthread.h> |
---|
| 40 | #include <assert.h> |
---|
[dd74e612] | 41 | |
---|
[d007cc2] | 42 | #define SHELL_STD_DEBUG 0 |
---|
| 43 | |
---|
| 44 | #if SHELL_STD_DEBUG |
---|
| 45 | #include <rtems/bspIo.h> |
---|
| 46 | #define shell_std_debug(...) \ |
---|
| 47 | do { printk("shell[%08x]: ", rtems_task_self()); printk(__VA_ARGS__); } while (0) |
---|
| 48 | #else |
---|
| 49 | #define shell_std_debug(...) |
---|
| 50 | #endif |
---|
| 51 | |
---|
[3407a3b] | 52 | #define SHELL_MAGIC rtems_build_name('S', 'E', 'N', 'V') |
---|
| 53 | |
---|
[5f0ab5cf] | 54 | const rtems_shell_env_t rtems_global_shell_env = { |
---|
[3407a3b] | 55 | .magic = SHELL_MAGIC, |
---|
[d007cc2] | 56 | .managed = false, |
---|
[06f8e558] | 57 | .devname = CONSOLE_DEVICE_NAME, |
---|
[e765cfb] | 58 | .taskname = "RTSH", |
---|
[06f8e558] | 59 | .exit_shell = false, |
---|
| 60 | .forever = true, |
---|
| 61 | .echo = false, |
---|
| 62 | .cwd = "/", |
---|
| 63 | .input = NULL, |
---|
| 64 | .output = NULL, |
---|
| 65 | .output_append = false, |
---|
[d007cc2] | 66 | .parent_stdin = NULL, |
---|
| 67 | .parent_stdout = NULL, |
---|
| 68 | .parent_stderr = NULL, |
---|
[06f8e558] | 69 | .wake_on_end = RTEMS_ID_NONE, |
---|
[d007cc2] | 70 | .exit_code = NULL, |
---|
| 71 | .login_check = NULL, |
---|
| 72 | .uid = 0, |
---|
| 73 | .gid = 0 |
---|
[06f8e558] | 74 | }; |
---|
| 75 | |
---|
[d007cc2] | 76 | typedef struct rtems_shell_env_key_handle |
---|
| 77 | { |
---|
| 78 | bool managed; |
---|
| 79 | rtems_shell_env_t* env; |
---|
| 80 | } rtems_shell_env_key_handle; |
---|
| 81 | |
---|
[373ccbb9] | 82 | static pthread_once_t rtems_shell_once = PTHREAD_ONCE_INIT; |
---|
| 83 | |
---|
[6cd4a5c] | 84 | static pthread_key_t rtems_shell_current_env_key; |
---|
[4e5299f] | 85 | |
---|
| 86 | /* |
---|
[814d9588] | 87 | * Initialize the shell user/process environment information |
---|
[4e5299f] | 88 | */ |
---|
[94547d1] | 89 | static rtems_shell_env_t *rtems_shell_init_env( |
---|
[d007cc2] | 90 | rtems_shell_env_t *shell_env_parent |
---|
[4e5299f] | 91 | ) |
---|
| 92 | { |
---|
[13c37ad] | 93 | rtems_shell_env_t *shell_env; |
---|
| 94 | |
---|
| 95 | shell_env = malloc(sizeof(rtems_shell_env_t)); |
---|
| 96 | if ( !shell_env ) |
---|
| 97 | return NULL; |
---|
[d007cc2] | 98 | |
---|
| 99 | if ( shell_env_parent == NULL ) { |
---|
| 100 | shell_env_parent = rtems_shell_get_current_env(); |
---|
| 101 | } |
---|
| 102 | if ( shell_env_parent == NULL ) { |
---|
[1ff9922] | 103 | *shell_env = rtems_global_shell_env; |
---|
[13c37ad] | 104 | } else { |
---|
[d007cc2] | 105 | *shell_env = *shell_env_parent; |
---|
[4e5299f] | 106 | } |
---|
[d007cc2] | 107 | shell_env->managed = true; |
---|
| 108 | shell_env->taskname = NULL; |
---|
[4e5299f] | 109 | |
---|
[814d9588] | 110 | return shell_env; |
---|
[dd74e612] | 111 | } |
---|
[4e5299f] | 112 | |
---|
[798ff5a] | 113 | /* |
---|
| 114 | * Completely free a shell_env_t and all associated memory |
---|
| 115 | */ |
---|
[94547d1] | 116 | static void rtems_shell_env_free( |
---|
[798ff5a] | 117 | void *ptr |
---|
| 118 | ) |
---|
| 119 | { |
---|
[d007cc2] | 120 | if ( ptr != NULL ) { |
---|
| 121 | rtems_shell_env_key_handle *handle = (rtems_shell_env_key_handle *) ptr; |
---|
| 122 | rtems_shell_env_t *shell_env = handle->env; |
---|
| 123 | |
---|
| 124 | if ( handle->managed ) { |
---|
| 125 | if ( shell_env->input ) |
---|
| 126 | free((void *)shell_env->input); |
---|
| 127 | if ( shell_env->output ) |
---|
| 128 | free((void *)shell_env->output); |
---|
| 129 | free( shell_env ); |
---|
| 130 | } |
---|
[798ff5a] | 131 | |
---|
[d007cc2] | 132 | free( handle ); |
---|
| 133 | } |
---|
[798ff5a] | 134 | } |
---|
| 135 | |
---|
[373ccbb9] | 136 | static void rtems_shell_create_file(const char *name, const char *content) |
---|
[6cd4a5c] | 137 | { |
---|
[373ccbb9] | 138 | FILE *fp = fopen(name, "wx"); |
---|
| 139 | |
---|
| 140 | if (fp != NULL) { |
---|
| 141 | fputs(content, fp); |
---|
| 142 | fclose(fp); |
---|
| 143 | } |
---|
| 144 | } |
---|
| 145 | |
---|
[7840b66] | 146 | static void rtems_shell_init_commands(void) |
---|
| 147 | { |
---|
| 148 | rtems_shell_cmd_t * const *c; |
---|
| 149 | rtems_shell_alias_t * const *a; |
---|
| 150 | |
---|
| 151 | for ( c = rtems_shell_Initial_commands ; *c ; c++ ) { |
---|
| 152 | rtems_shell_add_cmd_struct( *c ); |
---|
| 153 | } |
---|
| 154 | |
---|
| 155 | for ( a = rtems_shell_Initial_aliases ; *a ; a++ ) { |
---|
| 156 | rtems_shell_alias_cmd( (*a)->name, (*a)->alias ); |
---|
| 157 | } |
---|
| 158 | } |
---|
| 159 | |
---|
[373ccbb9] | 160 | static void rtems_shell_init_once(void) |
---|
| 161 | { |
---|
| 162 | struct passwd pwd; |
---|
| 163 | struct passwd *pwd_res; |
---|
| 164 | |
---|
| 165 | pthread_key_create(&rtems_shell_current_env_key, rtems_shell_env_free); |
---|
| 166 | |
---|
| 167 | /* dummy call to init /etc dir */ |
---|
| 168 | getpwuid_r(0, &pwd, NULL, 0, &pwd_res); |
---|
| 169 | |
---|
| 170 | rtems_shell_create_file("etc/issue", |
---|
| 171 | "\n" |
---|
| 172 | "Welcome to @V\\n" |
---|
| 173 | "Login into @S\\n"); |
---|
| 174 | |
---|
| 175 | rtems_shell_create_file("/etc/issue.net", |
---|
| 176 | "\n" |
---|
| 177 | "Welcome to %v\n" |
---|
| 178 | "running on %m\n"); |
---|
[7840b66] | 179 | |
---|
| 180 | rtems_shell_init_commands(); |
---|
[2465c01] | 181 | rtems_shell_register_monitor_commands(); |
---|
| 182 | } |
---|
| 183 | |
---|
| 184 | void rtems_shell_init_environment(void) |
---|
| 185 | { |
---|
| 186 | assert(pthread_once(&rtems_shell_once, rtems_shell_init_once) == 0); |
---|
[6cd4a5c] | 187 | } |
---|
| 188 | |
---|
[d007cc2] | 189 | /* |
---|
| 190 | * Set the shell env into the current thread's shell key. |
---|
| 191 | */ |
---|
| 192 | static bool rtems_shell_set_shell_env( |
---|
| 193 | rtems_shell_env_t* shell_env |
---|
| 194 | ) |
---|
| 195 | { |
---|
| 196 | /* |
---|
| 197 | * The shell environment can be managed or it can be provided by a |
---|
| 198 | * user. We need to create a handle to hold the env pointer. |
---|
| 199 | */ |
---|
| 200 | rtems_shell_env_key_handle *handle; |
---|
| 201 | int eno; |
---|
| 202 | |
---|
[a800e4de] | 203 | rtems_shell_init_environment(); |
---|
| 204 | |
---|
[d007cc2] | 205 | handle = malloc(sizeof(rtems_shell_env_key_handle)); |
---|
| 206 | if (handle == NULL) { |
---|
| 207 | rtems_error(0, "no memory for shell env key handle)"); |
---|
| 208 | return false; |
---|
| 209 | } |
---|
| 210 | |
---|
| 211 | handle->managed = shell_env->managed; |
---|
| 212 | handle->env = shell_env; |
---|
| 213 | |
---|
| 214 | eno = pthread_setspecific(rtems_shell_current_env_key, handle); |
---|
| 215 | if (eno != 0) { |
---|
| 216 | rtems_error(0, "pthread_setspecific(shell_current_env_key): set"); |
---|
| 217 | return false; |
---|
| 218 | } |
---|
| 219 | |
---|
| 220 | return true; |
---|
| 221 | } |
---|
| 222 | |
---|
| 223 | /* |
---|
| 224 | * Clear the current thread's shell key. |
---|
| 225 | */ |
---|
| 226 | static void rtems_shell_clear_shell_env(void) |
---|
| 227 | { |
---|
| 228 | int eno; |
---|
| 229 | |
---|
| 230 | /* |
---|
| 231 | * Run the destructor manually. |
---|
| 232 | */ |
---|
| 233 | rtems_shell_env_free(pthread_getspecific(rtems_shell_current_env_key)); |
---|
| 234 | |
---|
| 235 | /* |
---|
| 236 | * Clear the key |
---|
| 237 | */ |
---|
| 238 | eno = pthread_setspecific(rtems_shell_current_env_key, NULL); |
---|
| 239 | if (eno != 0) |
---|
| 240 | rtems_error(0, "pthread_setspecific(shell_current_env_key): clear"); |
---|
[20b1bdb] | 241 | } |
---|
[d007cc2] | 242 | |
---|
[20b1bdb] | 243 | /* |
---|
| 244 | * Clear stdin, stdout and stderr file pointers so they will not be closed. |
---|
| 245 | */ |
---|
| 246 | static void rtems_shell_clear_shell_std_handles(void) |
---|
| 247 | { |
---|
[d007cc2] | 248 | stdin = NULL; |
---|
| 249 | stdout = NULL; |
---|
[20b1bdb] | 250 | stderr = NULL; |
---|
[d007cc2] | 251 | } |
---|
| 252 | |
---|
[6cd4a5c] | 253 | /* |
---|
| 254 | * Return the current shell environment |
---|
| 255 | */ |
---|
| 256 | rtems_shell_env_t *rtems_shell_get_current_env(void) |
---|
| 257 | { |
---|
[d007cc2] | 258 | rtems_shell_env_key_handle *handle; |
---|
| 259 | handle = (rtems_shell_env_key_handle*) |
---|
| 260 | pthread_getspecific(rtems_shell_current_env_key); |
---|
| 261 | return handle == NULL ? NULL : handle->env; |
---|
[bb58190] | 262 | } |
---|
| 263 | |
---|
| 264 | /* |
---|
| 265 | * Duplication the current shell environment and if none is set |
---|
| 266 | * clear it. |
---|
| 267 | */ |
---|
| 268 | void rtems_shell_dup_current_env(rtems_shell_env_t *copy) |
---|
| 269 | { |
---|
| 270 | rtems_shell_env_t *env = rtems_shell_get_current_env(); |
---|
[d007cc2] | 271 | if (env != NULL) { |
---|
| 272 | shell_std_debug("dup: existing parent\n"); |
---|
[bb58190] | 273 | *copy = *env; |
---|
[e765cfb] | 274 | |
---|
| 275 | /* |
---|
| 276 | * Duplicated environments are not managed. |
---|
| 277 | */ |
---|
| 278 | copy->managed = false; |
---|
| 279 | } else { |
---|
[d007cc2] | 280 | *copy = rtems_global_shell_env; |
---|
| 281 | copy->parent_stdout = stdout; |
---|
| 282 | copy->parent_stdin = stdin; |
---|
| 283 | copy->parent_stderr = stderr; |
---|
| 284 | shell_std_debug("dup: global: copy: %p out: %d (%p) in: %d (%p)\n", |
---|
| 285 | copy, |
---|
| 286 | fileno(copy->parent_stdout), copy->parent_stdout, |
---|
| 287 | fileno(copy->parent_stdin), copy->parent_stdin); |
---|
[bb58190] | 288 | } |
---|
[6cd4a5c] | 289 | } |
---|
| 290 | |
---|
[529402f5] | 291 | /* |
---|
| 292 | * Move a string in a buffer to the left (e.g. when a character |
---|
| 293 | * is deleted). The string must be NUL-terminated and the |
---|
| 294 | * NUL-character will be moved too. |
---|
| 295 | */ |
---|
| 296 | static void rtems_shell_move_left(char *start, size_t offset) |
---|
| 297 | { |
---|
| 298 | memmove(start, start + offset, strlen(start + offset) + 1); |
---|
| 299 | } |
---|
| 300 | |
---|
[814d9588] | 301 | /* |
---|
| 302 | * Get a line of user input with modest features |
---|
| 303 | */ |
---|
[94547d1] | 304 | static int rtems_shell_line_editor( |
---|
[ea90df23] | 305 | char *cmds[], |
---|
| 306 | int count, |
---|
| 307 | int size, |
---|
| 308 | const char *prompt, |
---|
| 309 | FILE *in, |
---|
| 310 | FILE *out |
---|
| 311 | ) |
---|
| 312 | { |
---|
| 313 | unsigned int extended_key; |
---|
[7c4cdeb9] | 314 | int c; |
---|
[ea90df23] | 315 | int col; |
---|
| 316 | int last_col; |
---|
| 317 | char line[size]; |
---|
| 318 | char new_line[size]; |
---|
| 319 | int up; |
---|
| 320 | int cmd = -1; |
---|
| 321 | int inserting = 1; |
---|
[d007cc2] | 322 | int in_fileno = fileno(in); |
---|
[ea90df23] | 323 | |
---|
| 324 | col = last_col = 0; |
---|
[8a775c27] | 325 | |
---|
[d007cc2] | 326 | tcdrain(in_fileno); |
---|
[9320c7ec] | 327 | if (out != NULL) { |
---|
| 328 | tcdrain(fileno(out)); |
---|
| 329 | } |
---|
[ea90df23] | 330 | |
---|
[9320c7ec] | 331 | if (out != NULL && prompt != NULL) |
---|
[ea90df23] | 332 | fprintf(out, "\r%s", prompt); |
---|
[8a775c27] | 333 | |
---|
[ea90df23] | 334 | line[0] = 0; |
---|
| 335 | new_line[0] = 0; |
---|
[8a775c27] | 336 | |
---|
[ea90df23] | 337 | for (;;) { |
---|
[8a775c27] | 338 | |
---|
[9320c7ec] | 339 | if (out != NULL) |
---|
[ea90df23] | 340 | fflush(out); |
---|
| 341 | |
---|
| 342 | extended_key = rtems_shell_getchar(in); |
---|
| 343 | |
---|
| 344 | if (extended_key == EOF) |
---|
| 345 | return -2; |
---|
[8a775c27] | 346 | |
---|
[ea90df23] | 347 | c = extended_key & RTEMS_SHELL_KEYS_NORMAL_MASK; |
---|
[8a775c27] | 348 | |
---|
[ea90df23] | 349 | /* |
---|
| 350 | * Make the extended_key usable as a boolean. |
---|
| 351 | */ |
---|
| 352 | extended_key &= ~RTEMS_SHELL_KEYS_NORMAL_MASK; |
---|
[8a775c27] | 353 | |
---|
[ea90df23] | 354 | up = 0; |
---|
[8a775c27] | 355 | |
---|
[ea90df23] | 356 | if (extended_key) |
---|
| 357 | { |
---|
| 358 | switch (c) |
---|
| 359 | { |
---|
| 360 | case RTEMS_SHELL_KEYS_END: |
---|
[9320c7ec] | 361 | if (out != NULL) |
---|
[8bca4fc] | 362 | fprintf(out, "%s", line + col); |
---|
[ea90df23] | 363 | col = (int) strlen (line); |
---|
| 364 | break; |
---|
| 365 | |
---|
| 366 | case RTEMS_SHELL_KEYS_HOME: |
---|
[9320c7ec] | 367 | if (out != NULL && prompt != NULL) { |
---|
| 368 | fprintf(out,"\r%s", prompt); |
---|
[ea90df23] | 369 | } |
---|
| 370 | col = 0; |
---|
| 371 | break; |
---|
| 372 | |
---|
| 373 | case RTEMS_SHELL_KEYS_LARROW: |
---|
[22e98377] | 374 | c = 2; |
---|
| 375 | extended_key = 0; |
---|
[ea90df23] | 376 | break; |
---|
| 377 | |
---|
[22e98377] | 378 | case RTEMS_SHELL_KEYS_RARROW: |
---|
| 379 | c = 6; |
---|
| 380 | extended_key = 0; |
---|
| 381 | break; |
---|
[ea90df23] | 382 | |
---|
| 383 | case RTEMS_SHELL_KEYS_UARROW: |
---|
[22e98377] | 384 | c = 16; |
---|
| 385 | extended_key = 0; |
---|
| 386 | break; |
---|
[ea90df23] | 387 | |
---|
| 388 | case RTEMS_SHELL_KEYS_DARROW: |
---|
[22e98377] | 389 | c = 14; |
---|
| 390 | extended_key = 0; |
---|
| 391 | break; |
---|
[ea90df23] | 392 | |
---|
| 393 | case RTEMS_SHELL_KEYS_DEL: |
---|
| 394 | if (line[col] != '\0') |
---|
| 395 | { |
---|
| 396 | int end; |
---|
| 397 | int bs; |
---|
[529402f5] | 398 | rtems_shell_move_left(line + col, 1); |
---|
[9320c7ec] | 399 | if (out != NULL) { |
---|
[ea90df23] | 400 | fprintf(out,"\r%s%s ", prompt, line); |
---|
| 401 | end = (int) strlen (line); |
---|
| 402 | for (bs = 0; bs < ((end - col) + 1); bs++) |
---|
| 403 | fputc('\b', out); |
---|
| 404 | } |
---|
| 405 | } |
---|
| 406 | break; |
---|
| 407 | |
---|
| 408 | case RTEMS_SHELL_KEYS_INS: |
---|
| 409 | inserting = inserting ? 0 : 1; |
---|
| 410 | break; |
---|
| 411 | } |
---|
| 412 | } |
---|
[22e98377] | 413 | if (!extended_key) |
---|
[ea90df23] | 414 | { |
---|
| 415 | switch (c) |
---|
| 416 | { |
---|
[22e98377] | 417 | case 1: /*Control-a*/ |
---|
[9320c7ec] | 418 | if (out != NULL && prompt != NULL) { |
---|
| 419 | fprintf(out,"\r%s", prompt); |
---|
[ea90df23] | 420 | } |
---|
| 421 | col = 0; |
---|
| 422 | break; |
---|
[8a775c27] | 423 | |
---|
[22e98377] | 424 | case 2: /* Control-B */ |
---|
| 425 | if (col > 0) |
---|
| 426 | { |
---|
| 427 | col--; |
---|
[9320c7ec] | 428 | if (out != NULL) |
---|
[22e98377] | 429 | fputc('\b', out); |
---|
| 430 | } |
---|
| 431 | break; |
---|
| 432 | |
---|
| 433 | case 4: /* Control-D */ |
---|
| 434 | if (strlen(line)) { |
---|
| 435 | if (col < strlen(line)) { |
---|
[529402f5] | 436 | rtems_shell_move_left(line + col, 1); |
---|
[9320c7ec] | 437 | if (out != NULL) { |
---|
[22e98377] | 438 | int bs; |
---|
| 439 | fprintf(out,"%s \b", line + col); |
---|
| 440 | for (bs = 0; bs < ((int) strlen (line) - col); bs++) |
---|
| 441 | fputc('\b', out); |
---|
| 442 | } |
---|
| 443 | } |
---|
| 444 | break; |
---|
| 445 | } |
---|
| 446 | /* Fall through */ |
---|
| 447 | |
---|
| 448 | case EOF: |
---|
[9320c7ec] | 449 | if (out != NULL) |
---|
[22e98377] | 450 | fputc('\n', out); |
---|
| 451 | return -2; |
---|
| 452 | |
---|
| 453 | case 5: /*Control-e*/ |
---|
[9320c7ec] | 454 | if (out != NULL) |
---|
[8bca4fc] | 455 | fprintf(out, "%s", line + col); |
---|
[ea90df23] | 456 | col = (int) strlen (line); |
---|
| 457 | break; |
---|
| 458 | |
---|
[22e98377] | 459 | case 6: /* Control-F */ |
---|
| 460 | if ((col < size) && (line[col] != '\0')) { |
---|
[9320c7ec] | 461 | if (out != NULL) |
---|
[22e98377] | 462 | fputc(line[col], out); |
---|
| 463 | col++; |
---|
| 464 | } |
---|
| 465 | break; |
---|
| 466 | |
---|
| 467 | case 7: /* Control-G */ |
---|
[9320c7ec] | 468 | if (out != NULL) { |
---|
[06ac8b71] | 469 | /* |
---|
| 470 | * The (int) cast is needed because the width specifier (%*) |
---|
| 471 | * must be an int, but strlen() returns a size_t. Without |
---|
| 472 | * the case, the result is a printf() format warning. |
---|
| 473 | */ |
---|
| 474 | fprintf(out,"\r%s%*c", prompt, (int) strlen (line), ' '); |
---|
[22e98377] | 475 | fprintf(out,"\r%s\x7", prompt); |
---|
| 476 | } |
---|
| 477 | memset (line, '\0', strlen(line)); |
---|
| 478 | col = 0; |
---|
| 479 | break; |
---|
| 480 | |
---|
| 481 | case 11: /*Control-k*/ |
---|
[ea90df23] | 482 | if (line[col]) { |
---|
[9320c7ec] | 483 | if (out != NULL) { |
---|
[ea90df23] | 484 | int end = strlen(line); |
---|
| 485 | int bs; |
---|
| 486 | fprintf(out,"%*c", end - col, ' '); |
---|
| 487 | for (bs = 0; bs < (end - col); bs++) |
---|
| 488 | fputc('\b', out); |
---|
| 489 | } |
---|
| 490 | line[col] = '\0'; |
---|
| 491 | } |
---|
| 492 | break; |
---|
[8a775c27] | 493 | |
---|
[ea90df23] | 494 | case '\f': |
---|
[9320c7ec] | 495 | if (out != NULL) { |
---|
[ea90df23] | 496 | int end; |
---|
| 497 | int bs; |
---|
| 498 | fputc('\f',out); |
---|
| 499 | fprintf(out,"\r%s%s", prompt, line); |
---|
| 500 | end = (int) strlen (line); |
---|
| 501 | for (bs = 0; bs < (end - col); bs++) |
---|
| 502 | fputc('\b', out); |
---|
| 503 | } |
---|
| 504 | break; |
---|
| 505 | |
---|
| 506 | case '\b': |
---|
| 507 | case '\x7f': |
---|
| 508 | if (col > 0) |
---|
| 509 | { |
---|
| 510 | int bs; |
---|
| 511 | col--; |
---|
[529402f5] | 512 | rtems_shell_move_left(line + col, 1); |
---|
[9320c7ec] | 513 | if (out != NULL) { |
---|
[ea90df23] | 514 | fprintf(out,"\b%s \b", line + col); |
---|
| 515 | for (bs = 0; bs < ((int) strlen (line) - col); bs++) |
---|
| 516 | fputc('\b', out); |
---|
| 517 | } |
---|
| 518 | } |
---|
| 519 | break; |
---|
| 520 | |
---|
| 521 | case '\n': |
---|
| 522 | case '\r': |
---|
| 523 | { |
---|
| 524 | /* |
---|
| 525 | * Process the command. |
---|
| 526 | */ |
---|
[9320c7ec] | 527 | if (out != NULL) |
---|
[ea90df23] | 528 | fprintf(out,"\n"); |
---|
[8a775c27] | 529 | |
---|
[ea90df23] | 530 | /* |
---|
| 531 | * Only process the command if we have a command and it is not |
---|
| 532 | * repeated in the history. |
---|
| 533 | */ |
---|
| 534 | if (strlen(line) == 0) { |
---|
| 535 | cmd = -1; |
---|
| 536 | } else { |
---|
| 537 | if ((cmd < 0) || (strcmp(line, cmds[cmd]) != 0)) { |
---|
| 538 | if (count > 1) |
---|
| 539 | memmove(cmds[1], cmds[0], (count - 1) * size); |
---|
| 540 | memmove (cmds[0], line, size); |
---|
| 541 | cmd = 0; |
---|
[22e98377] | 542 | } else { |
---|
| 543 | if ((cmd > 1) && (strcmp(line, cmds[cmd]) == 0)) { |
---|
| 544 | memmove(cmds[1], cmds[0], cmd * size); |
---|
| 545 | memmove (cmds[0], line, size); |
---|
| 546 | cmd = 0; |
---|
| 547 | } |
---|
[ea90df23] | 548 | } |
---|
| 549 | } |
---|
| 550 | } |
---|
| 551 | return cmd; |
---|
| 552 | |
---|
[22e98377] | 553 | case 16: /* Control-P */ |
---|
| 554 | if ((cmd >= (count - 1)) || (strlen(cmds[cmd + 1]) == 0)) { |
---|
[9320c7ec] | 555 | if (out != NULL) |
---|
[22e98377] | 556 | fputc('\x7', out); |
---|
| 557 | break; |
---|
| 558 | } |
---|
| 559 | |
---|
| 560 | up = 1; |
---|
| 561 | /* drop through */ |
---|
| 562 | |
---|
| 563 | case 14: /* Control-N */ |
---|
| 564 | { |
---|
| 565 | int last_cmd = cmd; |
---|
| 566 | int clen = strlen (line); |
---|
| 567 | |
---|
| 568 | if (prompt) |
---|
| 569 | clen += strlen(prompt); |
---|
| 570 | |
---|
| 571 | if (up) { |
---|
| 572 | cmd++; |
---|
| 573 | } else { |
---|
| 574 | if (cmd < 0) { |
---|
[9320c7ec] | 575 | if (out != NULL) |
---|
[22e98377] | 576 | fprintf(out, "\x7"); |
---|
| 577 | break; |
---|
| 578 | } |
---|
| 579 | else |
---|
| 580 | cmd--; |
---|
| 581 | } |
---|
| 582 | |
---|
| 583 | if ((last_cmd < 0) || (strcmp(cmds[last_cmd], line) != 0)) |
---|
| 584 | memcpy (new_line, line, size); |
---|
| 585 | |
---|
| 586 | if (cmd < 0) |
---|
| 587 | memcpy (line, new_line, size); |
---|
| 588 | else |
---|
| 589 | memcpy (line, cmds[cmd], size); |
---|
| 590 | |
---|
| 591 | col = strlen (line); |
---|
| 592 | |
---|
[9320c7ec] | 593 | if (out != NULL) { |
---|
[22e98377] | 594 | fprintf(out,"\r%s%*c", prompt, clen, ' '); |
---|
| 595 | fprintf(out,"\r%s%s", prompt, line); |
---|
| 596 | } |
---|
| 597 | } |
---|
| 598 | break; |
---|
| 599 | |
---|
| 600 | case 20: /* Control-T */ |
---|
| 601 | if (col > 0) |
---|
| 602 | { |
---|
| 603 | char tmp; |
---|
| 604 | if (col == strlen(line)) { |
---|
| 605 | col--; |
---|
[9320c7ec] | 606 | if (out != NULL) |
---|
[22e98377] | 607 | fprintf(out,"\b"); |
---|
| 608 | } |
---|
| 609 | tmp = line[col]; |
---|
| 610 | line[col] = line[col - 1]; |
---|
| 611 | line[col - 1] = tmp; |
---|
[9320c7ec] | 612 | if (out != NULL) |
---|
[22e98377] | 613 | fprintf(out,"\b%c%c", line[col - 1], line[col]); |
---|
| 614 | col++; |
---|
| 615 | } else { |
---|
[9320c7ec] | 616 | if (out != NULL) |
---|
[22e98377] | 617 | fputc('\x7', out); |
---|
| 618 | } |
---|
| 619 | break; |
---|
| 620 | |
---|
| 621 | case 21: /* Control-U */ |
---|
| 622 | if (col > 0) |
---|
| 623 | { |
---|
[2361b2c] | 624 | /* strlen() returns size_t but fprintf("%*...") below requires |
---|
| 625 | * int! */ |
---|
| 626 | int clen = (int) strlen (line); |
---|
[ffc928b] | 627 | int bs; |
---|
[22e98377] | 628 | |
---|
[529402f5] | 629 | rtems_shell_move_left(line, col); |
---|
[9320c7ec] | 630 | if (out != NULL) { |
---|
[22e98377] | 631 | fprintf(out,"\r%s%*c", prompt, clen, ' '); |
---|
| 632 | fprintf(out,"\r%s%s", prompt, line); |
---|
[ffc928b] | 633 | |
---|
| 634 | for (bs = 0; bs < strlen(line); bs++) { |
---|
| 635 | fputc('\b', out); |
---|
| 636 | } |
---|
[22e98377] | 637 | } |
---|
| 638 | col = 0; |
---|
| 639 | } |
---|
| 640 | break; |
---|
| 641 | |
---|
[ea90df23] | 642 | default: |
---|
[7311863] | 643 | if ((col < (size - 1)) && (c >= ' ') && (c <= '~')) { |
---|
[ea90df23] | 644 | int end = strlen (line); |
---|
| 645 | if (inserting && (col < end) && (end < size)) { |
---|
| 646 | int ch, bs; |
---|
| 647 | for (ch = end + 1; ch > col; ch--) |
---|
| 648 | line[ch] = line[ch - 1]; |
---|
[9320c7ec] | 649 | if (out != NULL) { |
---|
[8bca4fc] | 650 | fprintf(out, "%s", line + col); |
---|
[ea90df23] | 651 | for (bs = 0; bs < (end - col + 1); bs++) |
---|
| 652 | fputc('\b', out); |
---|
| 653 | } |
---|
| 654 | } |
---|
| 655 | line[col++] = c; |
---|
| 656 | if (col > end) |
---|
| 657 | line[col] = '\0'; |
---|
[9320c7ec] | 658 | if (out != NULL) |
---|
[ea90df23] | 659 | fputc(c, out); |
---|
| 660 | } |
---|
| 661 | break; |
---|
| 662 | } |
---|
| 663 | } |
---|
| 664 | } |
---|
| 665 | return -2; |
---|
| 666 | } |
---|
| 667 | |
---|
[fa028bb] | 668 | static bool rtems_shell_login(rtems_shell_env_t *env, FILE * in,FILE * out) |
---|
| 669 | { |
---|
[d007cc2] | 670 | FILE *fd; |
---|
| 671 | int c; |
---|
| 672 | time_t t; |
---|
[bb58190] | 673 | |
---|
[6dd411aa] | 674 | if (out) { |
---|
[bb58190] | 675 | if ((env->devname[5]!='p')|| |
---|
| 676 | (env->devname[6]!='t')|| |
---|
| 677 | (env->devname[7]!='y')) { |
---|
[6dd411aa] | 678 | fd = fopen("/etc/issue","r"); |
---|
| 679 | if (fd) { |
---|
[d007cc2] | 680 | while ((c = fgetc(fd)) != EOF) { |
---|
[6dd411aa] | 681 | if (c=='@') { |
---|
[d007cc2] | 682 | switch (c = fgetc(fd)) { |
---|
[6dd411aa] | 683 | case 'L': |
---|
[bb58190] | 684 | fprintf(out,"%s", env->devname); |
---|
[6dd411aa] | 685 | break; |
---|
| 686 | case 'B': |
---|
| 687 | fprintf(out,"0"); |
---|
| 688 | break; |
---|
[70d689a] | 689 | case 'T': |
---|
[6dd411aa] | 690 | case 'D': |
---|
| 691 | time(&t); |
---|
| 692 | fprintf(out,"%s",ctime(&t)); |
---|
| 693 | break; |
---|
| 694 | case 'S': |
---|
| 695 | fprintf(out,"RTEMS"); |
---|
| 696 | break; |
---|
| 697 | case 'V': |
---|
[1af8e45b] | 698 | fprintf( |
---|
| 699 | out, |
---|
| 700 | "%s\n%s", |
---|
| 701 | rtems_get_version_string(), |
---|
| 702 | rtems_get_copyright_notice() |
---|
| 703 | ); |
---|
[6dd411aa] | 704 | break; |
---|
| 705 | case '@': |
---|
| 706 | fprintf(out,"@"); |
---|
| 707 | break; |
---|
| 708 | default : |
---|
| 709 | fprintf(out,"@%c",c); |
---|
| 710 | break; |
---|
| 711 | } |
---|
| 712 | } else if (c=='\\') { |
---|
| 713 | switch(c=fgetc(fd)) { |
---|
| 714 | case '\\': fprintf(out,"\\"); break; |
---|
| 715 | case 'b': fprintf(out,"\b"); break; |
---|
| 716 | case 'f': fprintf(out,"\f"); break; |
---|
| 717 | case 'n': fprintf(out,"\n"); break; |
---|
| 718 | case 'r': fprintf(out,"\r"); break; |
---|
| 719 | case 's': fprintf(out," "); break; |
---|
| 720 | case 't': fprintf(out,"\t"); break; |
---|
| 721 | case '@': fprintf(out,"@"); break; |
---|
| 722 | } |
---|
| 723 | } else { |
---|
| 724 | fputc(c,out); |
---|
| 725 | } |
---|
| 726 | } |
---|
| 727 | fclose(fd); |
---|
| 728 | } |
---|
| 729 | } else { |
---|
| 730 | fd = fopen("/etc/issue.net","r"); |
---|
| 731 | if (fd) { |
---|
| 732 | while ((c=fgetc(fd))!=EOF) { |
---|
| 733 | if (c=='%') { |
---|
| 734 | switch(c=fgetc(fd)) { |
---|
| 735 | case 't': |
---|
[bb58190] | 736 | fprintf(out,"%s", env->devname); |
---|
[6dd411aa] | 737 | break; |
---|
| 738 | case 'h': |
---|
| 739 | fprintf(out,"0"); |
---|
| 740 | break; |
---|
| 741 | case 'D': |
---|
| 742 | fprintf(out," "); |
---|
| 743 | break; |
---|
| 744 | case 'd': |
---|
| 745 | time(&t); |
---|
| 746 | fprintf(out,"%s",ctime(&t)); |
---|
| 747 | break; |
---|
| 748 | case 's': |
---|
| 749 | fprintf(out,"RTEMS"); |
---|
| 750 | break; |
---|
| 751 | case 'm': |
---|
| 752 | fprintf(out,"(" CPU_NAME "/" CPU_MODEL_NAME ")"); |
---|
| 753 | break; |
---|
| 754 | case 'r': |
---|
[4b9b6dd] | 755 | fprintf(out,rtems_get_version_string()); |
---|
[6dd411aa] | 756 | break; |
---|
| 757 | case 'v': |
---|
[1af8e45b] | 758 | fprintf( |
---|
| 759 | out, |
---|
| 760 | "%s\n%s", |
---|
| 761 | rtems_get_version_string(), |
---|
| 762 | rtems_get_copyright_notice() |
---|
| 763 | ); |
---|
[6dd411aa] | 764 | break; |
---|
| 765 | case '%':fprintf(out,"%%"); |
---|
| 766 | break; |
---|
| 767 | default: |
---|
| 768 | fprintf(out,"%%%c",c); |
---|
| 769 | break; |
---|
| 770 | } |
---|
| 771 | } else { |
---|
| 772 | fputc(c,out); |
---|
| 773 | } |
---|
| 774 | } |
---|
| 775 | fclose(fd); |
---|
| 776 | } |
---|
| 777 | } |
---|
| 778 | } |
---|
| 779 | |
---|
[bb58190] | 780 | return rtems_shell_login_prompt(in, out, env->devname, env->login_check); |
---|
[b2712e3] | 781 | } |
---|
| 782 | |
---|
[814d9588] | 783 | #if defined(SHELL_DEBUG) |
---|
[2eeb648c] | 784 | void rtems_shell_print_env( |
---|
| 785 | rtems_shell_env_t * shell_env |
---|
[6dd411aa] | 786 | ) |
---|
| 787 | { |
---|
| 788 | if ( !shell_env ) { |
---|
| 789 | printk( "shell_env is NULL\n" ); |
---|
[20b1bdb] | 790 | |
---|
[6dd411aa] | 791 | return; |
---|
| 792 | } |
---|
| 793 | printk( "shell_env=%p\n" |
---|
| 794 | "shell_env->magic=0x%08x\t" |
---|
| 795 | "shell_env->devname=%s\n" |
---|
| 796 | "shell_env->taskname=%s\t" |
---|
| 797 | "shell_env->exit_shell=%d\t" |
---|
| 798 | "shell_env->forever=%d\n", |
---|
| 799 | shell_env->magic, |
---|
| 800 | shell_env->devname, |
---|
| 801 | ((shell_env->taskname) ? shell_env->taskname : "NOT SET"), |
---|
| 802 | shell_env->exit_shell, |
---|
| 803 | shell_env->forever |
---|
| 804 | ); |
---|
| 805 | } |
---|
| 806 | #endif |
---|
[dd74e612] | 807 | |
---|
[7260887] | 808 | /* |
---|
| 809 | * Wait for the string to return or timeout. |
---|
| 810 | */ |
---|
| 811 | static bool rtems_shell_term_wait_for(const int fd, const char* str, const int timeout) |
---|
| 812 | { |
---|
| 813 | int msec = timeout; |
---|
| 814 | int i = 0; |
---|
| 815 | while (msec-- > 0 && str[i] != '\0') { |
---|
| 816 | char ch[2]; |
---|
| 817 | if (read(fd, &ch[0], 1) == 1) { |
---|
| 818 | fflush(stdout); |
---|
| 819 | if (ch[0] != str[i++]) { |
---|
| 820 | return false; |
---|
| 821 | } |
---|
| 822 | msec = timeout; |
---|
| 823 | } else { |
---|
| 824 | usleep(1000); |
---|
| 825 | } |
---|
| 826 | } |
---|
| 827 | if (msec == 0) { |
---|
| 828 | return false; |
---|
| 829 | } |
---|
| 830 | return true; |
---|
| 831 | } |
---|
| 832 | |
---|
| 833 | /* |
---|
| 834 | * Buffer a string up to the end string |
---|
| 835 | */ |
---|
| 836 | static int rtems_shell_term_buffer_until(const int fd, |
---|
| 837 | char* buf, |
---|
| 838 | const int size, |
---|
| 839 | const char* end, |
---|
| 840 | const int timeout) |
---|
| 841 | { |
---|
| 842 | int msec = timeout; |
---|
| 843 | int i = 0; |
---|
| 844 | int e = 0; |
---|
| 845 | memset(&buf[0], 0, size); |
---|
| 846 | while (msec-- > 0 && i < size && end[e] != '\0') { |
---|
| 847 | char ch[2]; |
---|
| 848 | if (read(fd, &ch[0], 1) == 1) { |
---|
| 849 | fflush(stdout); |
---|
| 850 | buf[i++] = ch[0]; |
---|
| 851 | if (ch[0] == end[e]) { |
---|
| 852 | e++; |
---|
| 853 | } else { |
---|
| 854 | e = 0; |
---|
| 855 | } |
---|
| 856 | msec = timeout; |
---|
| 857 | } else { |
---|
| 858 | usleep(1000); |
---|
| 859 | } |
---|
| 860 | } |
---|
| 861 | if (msec == 0 || end[e] != '\0') { |
---|
| 862 | return -1; |
---|
| 863 | } |
---|
| 864 | i -= e; |
---|
| 865 | if (i < size) { |
---|
| 866 | buf[i] = '\0'; |
---|
| 867 | } |
---|
| 868 | return i; |
---|
| 869 | } |
---|
| 870 | |
---|
| 871 | /* |
---|
| 872 | * Determine if the terminal has the row and column values |
---|
| 873 | * swapped |
---|
| 874 | * |
---|
| 875 | * https://github.com/tmux/tmux/issues/3457 |
---|
| 876 | * |
---|
| 877 | * Tmux has a bug where the lines and cols are swapped. There is a lag |
---|
| 878 | * in the time it takes to get the fix into code so see if tmux is |
---|
| 879 | * running and which version and work around the bug. |
---|
| 880 | * |
---|
| 881 | * The terminal device needs to have VMIN=0, and VTIME=0 |
---|
| 882 | */ |
---|
| 883 | static bool rtems_shell_term_row_column_swapped(const int fd, const int timeout) { |
---|
| 884 | char buf[64]; |
---|
| 885 | memset(&buf[0], 0, sizeof(buf)); |
---|
| 886 | /* |
---|
| 887 | * CSI > Ps q |
---|
| 888 | * Ps = 0 => DCS > | text ST |
---|
| 889 | */ |
---|
| 890 | fputs("\033[>0q", stdout); |
---|
| 891 | fflush(stdout); |
---|
| 892 | if (rtems_shell_term_wait_for(fd, "\033P>|", timeout)) { |
---|
| 893 | int len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), "\033\\", timeout); |
---|
| 894 | if (len > 0) { |
---|
| 895 | if (memcmp(buf, "tmux ", 5) == 0) { |
---|
| 896 | static const char* bad_versions[] = { |
---|
| 897 | "3.2", "3.2a", "3.3", "3.3a" |
---|
| 898 | }; |
---|
| 899 | size_t i; |
---|
| 900 | for (i = 0; i < RTEMS_ARRAY_SIZE(bad_versions); ++i) { |
---|
| 901 | if (strcmp(bad_versions[i], buf + 5) == 0) { |
---|
| 902 | return true; |
---|
| 903 | } |
---|
| 904 | } |
---|
| 905 | } |
---|
| 906 | } |
---|
| 907 | } |
---|
| 908 | return false; |
---|
| 909 | } |
---|
| 910 | |
---|
[8425e67] | 911 | /* |
---|
| 912 | * Direct method to get the size of an XTERM window. |
---|
| 913 | * |
---|
| 914 | * If you do not use an XTERM the env variables are not define. |
---|
| 915 | */ |
---|
| 916 | static void rtems_shell_winsize( void ) |
---|
| 917 | { |
---|
| 918 | const int fd = fileno(stdin); |
---|
| 919 | struct winsize ws; |
---|
[7260887] | 920 | const int timeout = 150; |
---|
[8425e67] | 921 | char buf[64]; |
---|
| 922 | bool ok = false; |
---|
| 923 | int lines = 0; |
---|
| 924 | int cols = 0; |
---|
| 925 | int r; |
---|
| 926 | r = ioctl(fd, TIOCGWINSZ, &ws); |
---|
| 927 | if (r == 0) { |
---|
| 928 | ok = true; |
---|
| 929 | lines = ws.ws_row; |
---|
| 930 | cols = ws.ws_col; |
---|
| 931 | } else if (isatty(fd)) { |
---|
| 932 | struct termios cterm; |
---|
| 933 | if (tcgetattr(fd, &cterm) >= 0) { |
---|
| 934 | struct termios term = cterm; |
---|
| 935 | term.c_cc[VMIN] = 0; |
---|
| 936 | term.c_cc[VTIME] = 0; |
---|
| 937 | if (tcsetattr (fd, TCSADRAIN, &term) >= 0) { |
---|
| 938 | memset(&buf[0], 0, sizeof(buf)); |
---|
| 939 | /* |
---|
| 940 | * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Miscellaneous |
---|
| 941 | * |
---|
| 942 | * CSI 1 8 t |
---|
| 943 | */ |
---|
| 944 | fputs("\033[18t", stdout); |
---|
| 945 | fflush(stdout); |
---|
[7260887] | 946 | if (rtems_shell_term_wait_for(fd, "\033[8;", timeout)) { |
---|
| 947 | int len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), ";", timeout); |
---|
| 948 | if (len > 0) { |
---|
| 949 | int i; |
---|
| 950 | lines = 0; |
---|
| 951 | i = 0; |
---|
| 952 | while (i < len) { |
---|
[8425e67] | 953 | lines *= 10; |
---|
| 954 | lines += buf[i++] - '0'; |
---|
| 955 | } |
---|
[7260887] | 956 | len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), "t", timeout); |
---|
| 957 | if (len > 0) { |
---|
| 958 | cols = 0; |
---|
| 959 | i = 0; |
---|
| 960 | while (i < len) { |
---|
| 961 | cols *= 10; |
---|
| 962 | cols += buf[i++] - '0'; |
---|
| 963 | } |
---|
| 964 | ok = true; |
---|
[8425e67] | 965 | } |
---|
| 966 | } |
---|
| 967 | } |
---|
| 968 | } |
---|
[7260887] | 969 | if (rtems_shell_term_row_column_swapped(fd, timeout)) { |
---|
| 970 | int tmp = lines; |
---|
| 971 | lines = cols; |
---|
| 972 | cols = tmp; |
---|
| 973 | } |
---|
[8425e67] | 974 | tcsetattr (fd, TCSADRAIN, &cterm); |
---|
| 975 | } |
---|
| 976 | } |
---|
| 977 | if (ok) { |
---|
| 978 | snprintf(buf, sizeof(buf) - 1, "%d", lines); |
---|
| 979 | setenv("LINES", buf, 1); |
---|
| 980 | snprintf(buf, sizeof(buf) - 1, "%d", cols); |
---|
| 981 | setenv("COLUMNS", buf, 1); |
---|
| 982 | } |
---|
| 983 | } |
---|
| 984 | |
---|
[94547d1] | 985 | static rtems_task rtems_shell_task(rtems_task_argument task_argument) |
---|
[6dd411aa] | 986 | { |
---|
[1ff9922] | 987 | rtems_shell_env_t *shell_env = (rtems_shell_env_t*) task_argument; |
---|
| 988 | rtems_id wake_on_end = shell_env->wake_on_end; |
---|
| 989 | rtems_shell_main_loop( shell_env ); |
---|
[20b1bdb] | 990 | rtems_shell_clear_shell_std_handles(); |
---|
[1ff9922] | 991 | if (wake_on_end != RTEMS_INVALID_ID) |
---|
| 992 | rtems_event_send (wake_on_end, RTEMS_EVENT_1); |
---|
[f004b2b8] | 993 | rtems_task_exit(); |
---|
[6dd411aa] | 994 | } |
---|
[dd74e612] | 995 | |
---|
[fa028bb] | 996 | static bool rtems_shell_init_user_env(void) |
---|
| 997 | { |
---|
| 998 | rtems_status_code sc; |
---|
| 999 | |
---|
| 1000 | /* Make sure we have a private user environment */ |
---|
| 1001 | sc = rtems_libio_set_private_env(); |
---|
| 1002 | if (sc != RTEMS_SUCCESSFUL) { |
---|
[d007cc2] | 1003 | rtems_error(sc, "rtems_libio_set_private_env():"); |
---|
[fa028bb] | 1004 | return false; |
---|
| 1005 | } |
---|
| 1006 | |
---|
| 1007 | /* Make an effective root user */ |
---|
| 1008 | seteuid(0); |
---|
| 1009 | setegid(0); |
---|
| 1010 | |
---|
| 1011 | return chroot("/") == 0; |
---|
| 1012 | } |
---|
| 1013 | |
---|
[ea90df23] | 1014 | #define RTEMS_SHELL_MAXIMUM_ARGUMENTS (128) |
---|
| 1015 | #define RTEMS_SHELL_CMD_SIZE (128) |
---|
| 1016 | #define RTEMS_SHELL_CMD_COUNT (32) |
---|
| 1017 | #define RTEMS_SHELL_PROMPT_SIZE (128) |
---|
[aed742c] | 1018 | |
---|
[1a8ad7e] | 1019 | static bool shell_main_loop( |
---|
| 1020 | rtems_shell_env_t *shell_env, |
---|
| 1021 | bool interactive, |
---|
| 1022 | FILE *line_editor_output |
---|
[798ff5a] | 1023 | ) |
---|
[6dd411aa] | 1024 | { |
---|
[1a8ad7e] | 1025 | bool result = false; |
---|
| 1026 | int line = 0; |
---|
| 1027 | int cmd_count; |
---|
| 1028 | char *cmds[RTEMS_SHELL_CMD_COUNT]; |
---|
| 1029 | char *cmd_argv; |
---|
| 1030 | char *prompt; |
---|
| 1031 | |
---|
| 1032 | if (interactive) { |
---|
| 1033 | prompt = malloc(RTEMS_SHELL_PROMPT_SIZE); |
---|
| 1034 | if (prompt == NULL) { |
---|
| 1035 | fprintf(stderr, "shell: cannot allocate prompt memory\n"); |
---|
[1167235] | 1036 | return false; |
---|
[1ff9922] | 1037 | } |
---|
[d007cc2] | 1038 | |
---|
[ea90df23] | 1039 | cmd_count = RTEMS_SHELL_CMD_COUNT; |
---|
[9320c7ec] | 1040 | } else { |
---|
[1a8ad7e] | 1041 | prompt = NULL; |
---|
| 1042 | cmd_count = 1; |
---|
[9320c7ec] | 1043 | } |
---|
| 1044 | |
---|
[ea90df23] | 1045 | /* |
---|
| 1046 | * Allocate the command line buffers. |
---|
| 1047 | */ |
---|
[8c422e2] | 1048 | cmd_argv = malloc (RTEMS_SHELL_CMD_SIZE); |
---|
| 1049 | if (!cmd_argv) { |
---|
| 1050 | fprintf(stderr, "no memory for command line buffers\n" ); |
---|
| 1051 | } |
---|
[8a775c27] | 1052 | |
---|
[ea90df23] | 1053 | cmds[0] = calloc (cmd_count, RTEMS_SHELL_CMD_SIZE); |
---|
| 1054 | if (!cmds[0]) { |
---|
| 1055 | fprintf(stderr, "no memory for command line buffers\n" ); |
---|
| 1056 | } |
---|
[8c422e2] | 1057 | |
---|
| 1058 | if (cmd_argv && cmds[0]) { |
---|
[1a8ad7e] | 1059 | size_t cmd; |
---|
[ea90df23] | 1060 | |
---|
| 1061 | memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE); |
---|
| 1062 | |
---|
| 1063 | for (cmd = 1; cmd < cmd_count; cmd++) { |
---|
| 1064 | cmds[cmd] = cmds[cmd - 1] + RTEMS_SHELL_CMD_SIZE; |
---|
[6dd411aa] | 1065 | } |
---|
[8a775c27] | 1066 | |
---|
[ea90df23] | 1067 | do { |
---|
[fa028bb] | 1068 | result = rtems_shell_init_user_env(); |
---|
| 1069 | |
---|
| 1070 | if (result) { |
---|
| 1071 | /* |
---|
| 1072 | * By using result here, we can fall to the bottom of the |
---|
| 1073 | * loop when the connection is dropped during login and |
---|
| 1074 | * keep on trucking. |
---|
| 1075 | */ |
---|
| 1076 | if (shell_env->login_check != NULL) { |
---|
[20b1bdb] | 1077 | result = rtems_shell_login(shell_env, stdin, stdout); |
---|
[fa028bb] | 1078 | } else { |
---|
[ffd5285] | 1079 | setuid(shell_env->uid); |
---|
| 1080 | setgid(shell_env->gid); |
---|
| 1081 | seteuid(shell_env->uid); |
---|
| 1082 | setegid(shell_env->gid); |
---|
| 1083 | rtems_current_user_env_getgroups(); |
---|
| 1084 | |
---|
[fa028bb] | 1085 | result = true; |
---|
| 1086 | } |
---|
[7c4cdeb9] | 1087 | } |
---|
| 1088 | |
---|
| 1089 | if (result) { |
---|
[ea90df23] | 1090 | memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE); |
---|
[1a8ad7e] | 1091 | |
---|
| 1092 | if (interactive) { |
---|
[ea90df23] | 1093 | rtems_shell_cat_file(stdout,"/etc/motd"); |
---|
| 1094 | fprintf(stdout, "\n" |
---|
[a2097c5] | 1095 | "RTEMS Shell on %s. Use 'help' to list commands.\n", |
---|
[ea90df23] | 1096 | shell_env->devname); |
---|
[55c64fc9] | 1097 | chdir("/"); /* XXX: chdir to getpwent homedir */ |
---|
[1a8ad7e] | 1098 | } else { |
---|
| 1099 | chdir(shell_env->cwd); |
---|
| 1100 | } |
---|
[8a775c27] | 1101 | |
---|
[1167235] | 1102 | shell_env->exit_shell = false; |
---|
[ea90df23] | 1103 | |
---|
| 1104 | for (;;) { |
---|
[1a8ad7e] | 1105 | const char *c; |
---|
| 1106 | int argc; |
---|
| 1107 | char *argv[RTEMS_SHELL_MAXIMUM_ARGUMENTS]; |
---|
| 1108 | |
---|
[ea90df23] | 1109 | /* Prompt section */ |
---|
| 1110 | if (prompt) { |
---|
| 1111 | rtems_shell_get_prompt(shell_env, prompt, |
---|
| 1112 | RTEMS_SHELL_PROMPT_SIZE); |
---|
| 1113 | } |
---|
[8a775c27] | 1114 | |
---|
[ea90df23] | 1115 | /* getcmd section */ |
---|
| 1116 | cmd = rtems_shell_line_editor(cmds, cmd_count, |
---|
| 1117 | RTEMS_SHELL_CMD_SIZE, prompt, |
---|
[9320c7ec] | 1118 | stdin, line_editor_output); |
---|
[ea90df23] | 1119 | |
---|
| 1120 | if (cmd == -1) |
---|
| 1121 | continue; /* empty line */ |
---|
[8a775c27] | 1122 | |
---|
[d007cc2] | 1123 | if (cmd == -2) { |
---|
| 1124 | result = false; |
---|
[ea90df23] | 1125 | break; /*EOF*/ |
---|
[d007cc2] | 1126 | } |
---|
[ea90df23] | 1127 | |
---|
| 1128 | line++; |
---|
| 1129 | |
---|
[55c64fc9] | 1130 | if (shell_env->echo) |
---|
| 1131 | fprintf(stdout, "%d: %s\n", line, cmds[cmd]); |
---|
[8a775c27] | 1132 | |
---|
[ea90df23] | 1133 | /* evaluate cmd section */ |
---|
| 1134 | c = cmds[cmd]; |
---|
| 1135 | while (*c) { |
---|
[bab5c5fa] | 1136 | if (!isblank((unsigned char)*c)) |
---|
[ea90df23] | 1137 | break; |
---|
| 1138 | c++; |
---|
| 1139 | } |
---|
[1ff9922] | 1140 | |
---|
[ea90df23] | 1141 | if (*c == '\0') /* empty line */ |
---|
| 1142 | continue; |
---|
[a5de1ef] | 1143 | |
---|
[ea90df23] | 1144 | if (*c == '#') { /* comment character */ |
---|
| 1145 | cmds[cmd][0] = 0; |
---|
| 1146 | continue; |
---|
| 1147 | } |
---|
[1ff9922] | 1148 | |
---|
[ea90df23] | 1149 | if (!strcmp(cmds[cmd],"bye") || !strcmp(cmds[cmd],"exit")) { |
---|
| 1150 | fprintf(stdout, "Shell exiting\n" ); |
---|
| 1151 | break; |
---|
| 1152 | } |
---|
[6dd411aa] | 1153 | |
---|
[ea90df23] | 1154 | /* exec cmd section */ |
---|
| 1155 | /* TODO: |
---|
| 1156 | * To avoid user crash catch the signals. |
---|
| 1157 | * Open a new stdio files with posibility of redirection * |
---|
| 1158 | * Run in a new shell task background. (unix &) |
---|
| 1159 | * Resuming. A little bash. |
---|
| 1160 | */ |
---|
[8c422e2] | 1161 | memcpy (cmd_argv, cmds[cmd], RTEMS_SHELL_CMD_SIZE); |
---|
| 1162 | if (!rtems_shell_make_args(cmd_argv, &argc, argv, |
---|
[ea90df23] | 1163 | RTEMS_SHELL_MAXIMUM_ARGUMENTS)) { |
---|
[8425e67] | 1164 | int exit_code; |
---|
| 1165 | rtems_shell_winsize(); |
---|
| 1166 | exit_code = rtems_shell_execute_cmd(argv[0], argc, argv); |
---|
[d007cc2] | 1167 | if (shell_env->exit_code != NULL) |
---|
| 1168 | *shell_env->exit_code = exit_code; |
---|
| 1169 | if (exit_code != 0 && shell_env->exit_on_error) |
---|
| 1170 | shell_env->exit_shell = true; |
---|
[6dd411aa] | 1171 | } |
---|
[ea90df23] | 1172 | |
---|
| 1173 | /* end exec cmd section */ |
---|
| 1174 | if (shell_env->exit_shell) |
---|
| 1175 | break; |
---|
[6dd411aa] | 1176 | } |
---|
| 1177 | |
---|
[ea90df23] | 1178 | fflush( stdout ); |
---|
| 1179 | fflush( stderr ); |
---|
[6dd411aa] | 1180 | } |
---|
[d007cc2] | 1181 | shell_std_debug("end: %d %d\n", result, shell_env->forever); |
---|
[ea90df23] | 1182 | } while (result && shell_env->forever); |
---|
[1a8ad7e] | 1183 | } |
---|
| 1184 | |
---|
| 1185 | free(cmds[0]); |
---|
| 1186 | free(cmd_argv); |
---|
| 1187 | free(prompt); |
---|
| 1188 | |
---|
| 1189 | return result; |
---|
| 1190 | } |
---|
| 1191 | |
---|
[2342625] | 1192 | bool rtems_shell_run_main_loop( |
---|
| 1193 | rtems_shell_env_t *shell_env, |
---|
| 1194 | bool interactive, |
---|
| 1195 | FILE *line_editor_output |
---|
| 1196 | ) |
---|
| 1197 | { |
---|
| 1198 | bool result; |
---|
| 1199 | |
---|
| 1200 | if (shell_env->magic != SHELL_MAGIC) { |
---|
| 1201 | return false; |
---|
| 1202 | } |
---|
| 1203 | |
---|
| 1204 | if (!rtems_shell_init_user_env()) { |
---|
| 1205 | return false; |
---|
| 1206 | } |
---|
| 1207 | |
---|
| 1208 | if (!rtems_shell_set_shell_env(shell_env)) { |
---|
| 1209 | return false; |
---|
| 1210 | } |
---|
| 1211 | |
---|
| 1212 | result = shell_main_loop(shell_env, interactive, line_editor_output); |
---|
| 1213 | rtems_shell_clear_shell_env(); |
---|
| 1214 | return result; |
---|
| 1215 | } |
---|
| 1216 | |
---|
[1a8ad7e] | 1217 | bool rtems_shell_main_loop( |
---|
| 1218 | rtems_shell_env_t *shell_env |
---|
| 1219 | ) |
---|
| 1220 | { |
---|
| 1221 | struct termios term; |
---|
| 1222 | struct termios previous_term; |
---|
| 1223 | bool result; |
---|
| 1224 | bool interactive = true; |
---|
| 1225 | FILE *stdinToClose = NULL; |
---|
| 1226 | FILE *stdoutToClose = NULL; |
---|
| 1227 | FILE *line_editor_output; |
---|
| 1228 | |
---|
[3407a3b] | 1229 | if (shell_env->magic != SHELL_MAGIC) { |
---|
[1a8ad7e] | 1230 | rtems_error(0, "invalid shell environment passed to the main loop)"); |
---|
| 1231 | return false; |
---|
| 1232 | } |
---|
| 1233 | |
---|
| 1234 | if (!rtems_shell_set_shell_env(shell_env)) |
---|
| 1235 | return false; |
---|
| 1236 | |
---|
| 1237 | if (!rtems_shell_init_user_env()) { |
---|
| 1238 | rtems_error(0, "rtems_shell_init_user_env"); |
---|
| 1239 | rtems_shell_clear_shell_env(); |
---|
| 1240 | return false; |
---|
| 1241 | } |
---|
| 1242 | |
---|
| 1243 | shell_std_debug("env: %p\n", shell_env); |
---|
| 1244 | |
---|
| 1245 | if (shell_env->output == NULL || strcmp(shell_env->output, "stdout") == 0) { |
---|
| 1246 | if (shell_env->parent_stdout != NULL) |
---|
| 1247 | stdout = shell_env->parent_stdout; |
---|
| 1248 | } |
---|
| 1249 | else if (strcmp(shell_env->output, "stderr") == 0) { |
---|
| 1250 | if (shell_env->parent_stderr != NULL) |
---|
| 1251 | stdout = shell_env->parent_stderr; |
---|
| 1252 | else |
---|
| 1253 | stdout = stderr; |
---|
| 1254 | } else if (strcmp(shell_env->output, "/dev/null") == 0) { |
---|
| 1255 | if (stdout == NULL) { |
---|
| 1256 | fprintf(stderr, "shell: stdout is NULLs\n"); |
---|
| 1257 | rtems_shell_clear_shell_env(); |
---|
| 1258 | return false; |
---|
| 1259 | } |
---|
| 1260 | fclose (stdout); |
---|
| 1261 | } else { |
---|
| 1262 | FILE *output = fopen(shell_env->output, |
---|
| 1263 | shell_env->output_append ? "a" : "w"); |
---|
| 1264 | if (output == NULL) { |
---|
| 1265 | fprintf(stderr, "shell: open output %s failed: %s\n", |
---|
| 1266 | shell_env->output, strerror(errno)); |
---|
| 1267 | rtems_shell_clear_shell_env(); |
---|
| 1268 | return false; |
---|
| 1269 | } |
---|
| 1270 | stdout = output; |
---|
| 1271 | stdoutToClose = output; |
---|
| 1272 | } |
---|
[ea90df23] | 1273 | |
---|
[1a8ad7e] | 1274 | if (shell_env->input == NULL || strcmp(shell_env->input, "stdin") == 0) { |
---|
| 1275 | if (shell_env->parent_stdin != NULL) |
---|
| 1276 | stdin = shell_env->parent_stdin; |
---|
| 1277 | } else { |
---|
| 1278 | FILE *input = fopen(shell_env->input, "r"); |
---|
| 1279 | if (input == NULL) { |
---|
| 1280 | fprintf(stderr, "shell: open input %s failed: %s\n", |
---|
| 1281 | shell_env->input, strerror(errno)); |
---|
| 1282 | if (stdoutToClose != NULL) |
---|
| 1283 | fclose(stdoutToClose); |
---|
| 1284 | rtems_shell_clear_shell_env(); |
---|
| 1285 | return false; |
---|
| 1286 | } |
---|
| 1287 | stdin = input; |
---|
| 1288 | stdinToClose = input; |
---|
| 1289 | shell_env->forever = false; |
---|
| 1290 | interactive = false; |
---|
[ea90df23] | 1291 | } |
---|
| 1292 | |
---|
[1a8ad7e] | 1293 | if (interactive) { |
---|
| 1294 | if (stdin == NULL) { |
---|
| 1295 | fprintf(stderr, "shell: stdin is NULLs\n"); |
---|
| 1296 | if (stdoutToClose != NULL) |
---|
| 1297 | fclose(stdoutToClose); |
---|
| 1298 | rtems_shell_clear_shell_env(); |
---|
| 1299 | return false; |
---|
| 1300 | } |
---|
| 1301 | /* Make a raw terminal, Linux Manuals */ |
---|
| 1302 | if (tcgetattr(fileno(stdin), &previous_term) >= 0) { |
---|
| 1303 | term = previous_term; |
---|
| 1304 | term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); |
---|
| 1305 | term.c_oflag &= ~OPOST; |
---|
| 1306 | term.c_oflag |= (OPOST|ONLCR); /* But with cr+nl on output */ |
---|
| 1307 | term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); |
---|
| 1308 | term.c_cflag |= CLOCAL | CREAD; |
---|
| 1309 | term.c_cc[VMIN] = 1; |
---|
| 1310 | term.c_cc[VTIME] = 0; |
---|
| 1311 | if (tcsetattr (fileno(stdin), TCSADRAIN, &term) < 0) { |
---|
| 1312 | fprintf(stderr, |
---|
| 1313 | "shell: cannot set terminal attributes(%s)\n",shell_env->devname); |
---|
| 1314 | } |
---|
| 1315 | } |
---|
| 1316 | } |
---|
| 1317 | |
---|
| 1318 | shell_std_debug("child out: %d (%p)\n", fileno(stdout), stdout); |
---|
| 1319 | shell_std_debug("child in: %d (%p)\n", fileno(stdin), stdin); |
---|
| 1320 | |
---|
| 1321 | /* Do not buffer if interactive else leave buffered */ |
---|
| 1322 | if (interactive) |
---|
| 1323 | setvbuf(stdin, NULL, _IONBF, 0); |
---|
| 1324 | setvbuf(stdout, NULL, _IONBF, 0); |
---|
| 1325 | |
---|
| 1326 | if (isatty(fileno(stdin))) { |
---|
| 1327 | line_editor_output = stdout; |
---|
| 1328 | } else { |
---|
| 1329 | line_editor_output = NULL; |
---|
| 1330 | } |
---|
[798ff5a] | 1331 | |
---|
[1a8ad7e] | 1332 | result = shell_main_loop(shell_env, interactive, line_editor_output); |
---|
[d007cc2] | 1333 | shell_std_debug("child in-to-close: %p\n", stdinToClose); |
---|
| 1334 | shell_std_debug("child out-to-close: %p\n", stdoutToClose); |
---|
| 1335 | |
---|
[8084ce80] | 1336 | if (stdinToClose) { |
---|
[a3ddb08b] | 1337 | fclose( stdinToClose ); |
---|
[8084ce80] | 1338 | } else { |
---|
[798ff5a] | 1339 | if (tcsetattr(fileno(stdin), TCSADRAIN, &previous_term) < 0) { |
---|
[8084ce80] | 1340 | fprintf( |
---|
| 1341 | stderr, |
---|
| 1342 | "shell: cannot reset terminal attributes (%s)\n", |
---|
| 1343 | shell_env->devname |
---|
| 1344 | ); |
---|
| 1345 | } |
---|
| 1346 | } |
---|
[a3ddb08b] | 1347 | if ( stdoutToClose ) |
---|
| 1348 | fclose( stdoutToClose ); |
---|
[d007cc2] | 1349 | rtems_shell_clear_shell_env(); |
---|
[1ff9922] | 1350 | return result; |
---|
[dd74e612] | 1351 | } |
---|
[6dd411aa] | 1352 | |
---|
[dd74e612] | 1353 | /* ----------------------------------------------- */ |
---|
[cbd1e87] | 1354 | static rtems_status_code rtems_shell_run ( |
---|
| 1355 | const char *task_name, |
---|
| 1356 | size_t task_stacksize, |
---|
| 1357 | rtems_task_priority task_priority, |
---|
| 1358 | const char *devname, |
---|
| 1359 | bool forever, |
---|
| 1360 | bool wait, |
---|
| 1361 | const char *input, |
---|
| 1362 | const char *output, |
---|
| 1363 | bool output_append, |
---|
| 1364 | rtems_id wake_on_end, |
---|
| 1365 | bool echo, |
---|
| 1366 | rtems_shell_login_check_t login_check |
---|
[6dd411aa] | 1367 | ) |
---|
| 1368 | { |
---|
| 1369 | rtems_id task_id; |
---|
| 1370 | rtems_status_code sc; |
---|
[2eeb648c] | 1371 | rtems_shell_env_t *shell_env; |
---|
[4e5299f] | 1372 | rtems_name name; |
---|
| 1373 | |
---|
[d007cc2] | 1374 | rtems_shell_init_environment(); |
---|
| 1375 | |
---|
[e41eaa88] | 1376 | if ( task_name && strlen(task_name) >= 4) |
---|
[814d9588] | 1377 | name = rtems_build_name( |
---|
| 1378 | task_name[0], task_name[1], task_name[2], task_name[3]); |
---|
[4e5299f] | 1379 | else |
---|
[3407a3b] | 1380 | name = SHELL_MAGIC; |
---|
[6dd411aa] | 1381 | |
---|
| 1382 | sc = rtems_task_create( |
---|
[4e5299f] | 1383 | name, |
---|
[6dd411aa] | 1384 | task_priority, |
---|
[4e5299f] | 1385 | task_stacksize, |
---|
[3899a537] | 1386 | RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR, |
---|
[6dd411aa] | 1387 | RTEMS_LOCAL | RTEMS_FLOATING_POINT, |
---|
| 1388 | &task_id |
---|
| 1389 | ); |
---|
| 1390 | if (sc != RTEMS_SUCCESSFUL) { |
---|
[d007cc2] | 1391 | rtems_error(sc,"creating task %s in shell_init()",task_name); |
---|
[6dd411aa] | 1392 | return sc; |
---|
| 1393 | } |
---|
| 1394 | |
---|
[2eeb648c] | 1395 | shell_env = rtems_shell_init_env( NULL ); |
---|
[6dd411aa] | 1396 | if ( !shell_env ) { |
---|
[d007cc2] | 1397 | rtems_error(RTEMS_NO_MEMORY, |
---|
| 1398 | "allocating shell_env %s in shell_init()",task_name); |
---|
[6dd411aa] | 1399 | return RTEMS_NO_MEMORY; |
---|
| 1400 | } |
---|
[d007cc2] | 1401 | |
---|
| 1402 | shell_std_debug("run: env: %p\n", shell_env); |
---|
| 1403 | |
---|
[1ff9922] | 1404 | shell_env->devname = devname; |
---|
| 1405 | shell_env->taskname = task_name; |
---|
[d007cc2] | 1406 | |
---|
[1167235] | 1407 | shell_env->exit_shell = false; |
---|
[1ff9922] | 1408 | shell_env->forever = forever; |
---|
[55c64fc9] | 1409 | shell_env->echo = echo; |
---|
[d007cc2] | 1410 | shell_env->input = input == NULL ? NULL : strdup (input); |
---|
| 1411 | shell_env->output = output == NULL ? NULL : strdup (output); |
---|
[1ff9922] | 1412 | shell_env->output_append = output_append; |
---|
[d007cc2] | 1413 | shell_env->parent_stdin = stdin; |
---|
| 1414 | shell_env->parent_stdout = stdout; |
---|
| 1415 | shell_env->parent_stderr = stderr; |
---|
[1ff9922] | 1416 | shell_env->wake_on_end = wake_on_end; |
---|
[8a775c27] | 1417 | shell_env->login_check = login_check; |
---|
[ffd5285] | 1418 | shell_env->uid = getuid(); |
---|
| 1419 | shell_env->gid = getgid(); |
---|
[6dd411aa] | 1420 | |
---|
[55c64fc9] | 1421 | getcwd(shell_env->cwd, sizeof(shell_env->cwd)); |
---|
| 1422 | |
---|
[d007cc2] | 1423 | shell_std_debug("run out: %d (%p)\n", |
---|
| 1424 | fileno(shell_env->parent_stdout), shell_env->parent_stdout); |
---|
| 1425 | shell_std_debug("run in: %d (%p)\n", |
---|
| 1426 | fileno(shell_env->parent_stdin), shell_env->parent_stdin); |
---|
| 1427 | |
---|
[798ff5a] | 1428 | sc = rtems_task_start(task_id, rtems_shell_task, |
---|
[d007cc2] | 1429 | (rtems_task_argument) shell_env); |
---|
[798ff5a] | 1430 | if (sc != RTEMS_SUCCESSFUL) { |
---|
[d007cc2] | 1431 | rtems_error(sc,"starting task %s in shell_init()",task_name); |
---|
| 1432 | free( (void*) shell_env->input ); |
---|
| 1433 | free( (void*) shell_env->output ); |
---|
| 1434 | free( shell_env ); |
---|
[798ff5a] | 1435 | return sc; |
---|
| 1436 | } |
---|
| 1437 | |
---|
| 1438 | if (wait) { |
---|
| 1439 | rtems_event_set out; |
---|
| 1440 | sc = rtems_event_receive (RTEMS_EVENT_1, RTEMS_WAIT, 0, &out); |
---|
| 1441 | } |
---|
| 1442 | |
---|
[b837c83] | 1443 | shell_std_debug("run: end: sc:%d\n", sc); |
---|
[d007cc2] | 1444 | |
---|
| 1445 | return sc; |
---|
[6dd411aa] | 1446 | } |
---|
[1ff9922] | 1447 | |
---|
[798ff5a] | 1448 | rtems_status_code rtems_shell_init( |
---|
[cbd1e87] | 1449 | const char *task_name, |
---|
| 1450 | size_t task_stacksize, |
---|
| 1451 | rtems_task_priority task_priority, |
---|
| 1452 | const char *devname, |
---|
| 1453 | bool forever, |
---|
| 1454 | bool wait, |
---|
| 1455 | rtems_shell_login_check_t login_check |
---|
[1ff9922] | 1456 | ) |
---|
| 1457 | { |
---|
[06f8e558] | 1458 | rtems_id to_wake = RTEMS_ID_NONE; |
---|
[798ff5a] | 1459 | |
---|
| 1460 | if ( wait ) |
---|
| 1461 | to_wake = rtems_task_self(); |
---|
| 1462 | |
---|
| 1463 | return rtems_shell_run( |
---|
| 1464 | task_name, /* task_name */ |
---|
| 1465 | task_stacksize, /* task_stacksize */ |
---|
| 1466 | task_priority, /* task_priority */ |
---|
| 1467 | devname, /* devname */ |
---|
| 1468 | forever, /* forever */ |
---|
| 1469 | wait, /* wait */ |
---|
| 1470 | "stdin", /* input */ |
---|
| 1471 | "stdout", /* output */ |
---|
[06f8e558] | 1472 | false, /* output_append */ |
---|
[798ff5a] | 1473 | to_wake, /* wake_on_end */ |
---|
[06f8e558] | 1474 | false, /* echo */ |
---|
[8a775c27] | 1475 | login_check /* login check */ |
---|
[798ff5a] | 1476 | ); |
---|
[1ff9922] | 1477 | } |
---|
| 1478 | |
---|
[d007cc2] | 1479 | rtems_status_code rtems_shell_script ( |
---|
[e41eaa88] | 1480 | const char *task_name, |
---|
[06f8e558] | 1481 | size_t task_stacksize, |
---|
[1ff9922] | 1482 | rtems_task_priority task_priority, |
---|
| 1483 | const char* input, |
---|
| 1484 | const char* output, |
---|
[06f8e558] | 1485 | bool output_append, |
---|
| 1486 | bool wait, |
---|
| 1487 | bool echo |
---|
[1ff9922] | 1488 | ) |
---|
| 1489 | { |
---|
[d007cc2] | 1490 | rtems_id to_wake = RTEMS_ID_NONE; |
---|
[1ff9922] | 1491 | rtems_status_code sc; |
---|
| 1492 | |
---|
[d007cc2] | 1493 | shell_std_debug("script: in: %s out: %s\n", input, output); |
---|
| 1494 | |
---|
| 1495 | if ( wait ) |
---|
| 1496 | to_wake = rtems_task_self(); |
---|
[8a775c27] | 1497 | |
---|
[798ff5a] | 1498 | sc = rtems_shell_run( |
---|
| 1499 | task_name, /* task_name */ |
---|
| 1500 | task_stacksize, /* task_stacksize */ |
---|
| 1501 | task_priority, /* task_priority */ |
---|
| 1502 | NULL, /* devname */ |
---|
| 1503 | 0, /* forever */ |
---|
| 1504 | wait, /* wait */ |
---|
| 1505 | input, /* input */ |
---|
| 1506 | output, /* output */ |
---|
| 1507 | output_append, /* output_append */ |
---|
[d007cc2] | 1508 | to_wake, /* wake_on_end */ |
---|
[06f8e558] | 1509 | echo, /* echo */ |
---|
[8a775c27] | 1510 | NULL /* login check */ |
---|
[798ff5a] | 1511 | ); |
---|
[d007cc2] | 1512 | |
---|
| 1513 | if (sc == RTEMS_SUCCESSFUL) |
---|
| 1514 | { |
---|
| 1515 | /* Place holder until RTEMS 5 is released then the interface for |
---|
| 1516 | * this call will change. */ |
---|
| 1517 | } |
---|
| 1518 | |
---|
| 1519 | shell_std_debug("script: end: %d\n", sc); |
---|
[1ff9922] | 1520 | |
---|
| 1521 | return sc; |
---|
| 1522 | } |
---|