[dd74e612] | 1 | /* |
---|
| 2 | * |
---|
| 3 | * Instantatiate a new terminal shell. |
---|
| 4 | * |
---|
[aed742c] | 5 | * Author: |
---|
[dd74e612] | 6 | * |
---|
[aed742c] | 7 | * WORK: fernando.ruiz@ctv.es |
---|
[dd74e612] | 8 | * HOME: correo@fernando-ruiz.com |
---|
| 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 | |
---|
[5f0ab5cf] | 52 | const rtems_shell_env_t rtems_global_shell_env = { |
---|
[06f8e558] | 53 | .magic = rtems_build_name('S', 'E', 'N', 'V'), |
---|
[d007cc2] | 54 | .managed = false, |
---|
[06f8e558] | 55 | .devname = CONSOLE_DEVICE_NAME, |
---|
| 56 | .taskname = "SHGL", |
---|
| 57 | .exit_shell = false, |
---|
| 58 | .forever = true, |
---|
| 59 | .echo = false, |
---|
| 60 | .cwd = "/", |
---|
| 61 | .input = NULL, |
---|
| 62 | .output = NULL, |
---|
| 63 | .output_append = false, |
---|
[d007cc2] | 64 | .parent_stdin = NULL, |
---|
| 65 | .parent_stdout = NULL, |
---|
| 66 | .parent_stderr = NULL, |
---|
[06f8e558] | 67 | .wake_on_end = RTEMS_ID_NONE, |
---|
[d007cc2] | 68 | .exit_code = NULL, |
---|
| 69 | .login_check = NULL, |
---|
| 70 | .uid = 0, |
---|
| 71 | .gid = 0 |
---|
[06f8e558] | 72 | }; |
---|
| 73 | |
---|
[d007cc2] | 74 | typedef struct rtems_shell_env_key_handle |
---|
| 75 | { |
---|
| 76 | bool managed; |
---|
| 77 | rtems_shell_env_t* env; |
---|
| 78 | } rtems_shell_env_key_handle; |
---|
| 79 | |
---|
[373ccbb9] | 80 | static pthread_once_t rtems_shell_once = PTHREAD_ONCE_INIT; |
---|
| 81 | |
---|
[6cd4a5c] | 82 | static pthread_key_t rtems_shell_current_env_key; |
---|
[4e5299f] | 83 | |
---|
| 84 | /* |
---|
[814d9588] | 85 | * Initialize the shell user/process environment information |
---|
[4e5299f] | 86 | */ |
---|
[94547d1] | 87 | static rtems_shell_env_t *rtems_shell_init_env( |
---|
[d007cc2] | 88 | rtems_shell_env_t *shell_env_parent |
---|
[4e5299f] | 89 | ) |
---|
| 90 | { |
---|
[13c37ad] | 91 | rtems_shell_env_t *shell_env; |
---|
| 92 | |
---|
| 93 | shell_env = malloc(sizeof(rtems_shell_env_t)); |
---|
| 94 | if ( !shell_env ) |
---|
| 95 | return NULL; |
---|
[d007cc2] | 96 | |
---|
| 97 | if ( shell_env_parent == NULL ) { |
---|
| 98 | shell_env_parent = rtems_shell_get_current_env(); |
---|
| 99 | } |
---|
| 100 | if ( shell_env_parent == NULL ) { |
---|
[1ff9922] | 101 | *shell_env = rtems_global_shell_env; |
---|
[13c37ad] | 102 | } else { |
---|
[d007cc2] | 103 | *shell_env = *shell_env_parent; |
---|
[4e5299f] | 104 | } |
---|
[d007cc2] | 105 | shell_env->managed = true; |
---|
| 106 | shell_env->taskname = NULL; |
---|
[4e5299f] | 107 | |
---|
[814d9588] | 108 | return shell_env; |
---|
[dd74e612] | 109 | } |
---|
[4e5299f] | 110 | |
---|
[798ff5a] | 111 | /* |
---|
| 112 | * Completely free a shell_env_t and all associated memory |
---|
| 113 | */ |
---|
[94547d1] | 114 | static void rtems_shell_env_free( |
---|
[798ff5a] | 115 | void *ptr |
---|
| 116 | ) |
---|
| 117 | { |
---|
[d007cc2] | 118 | if ( ptr != NULL ) { |
---|
| 119 | rtems_shell_env_key_handle *handle = (rtems_shell_env_key_handle *) ptr; |
---|
| 120 | rtems_shell_env_t *shell_env = handle->env; |
---|
| 121 | |
---|
| 122 | if ( handle->managed ) { |
---|
| 123 | if ( shell_env->input ) |
---|
| 124 | free((void *)shell_env->input); |
---|
| 125 | if ( shell_env->output ) |
---|
| 126 | free((void *)shell_env->output); |
---|
| 127 | free( shell_env ); |
---|
| 128 | } |
---|
[798ff5a] | 129 | |
---|
[d007cc2] | 130 | free( handle ); |
---|
| 131 | } |
---|
[798ff5a] | 132 | } |
---|
| 133 | |
---|
[373ccbb9] | 134 | static void rtems_shell_create_file(const char *name, const char *content) |
---|
[6cd4a5c] | 135 | { |
---|
[373ccbb9] | 136 | FILE *fp = fopen(name, "wx"); |
---|
| 137 | |
---|
| 138 | if (fp != NULL) { |
---|
| 139 | fputs(content, fp); |
---|
| 140 | fclose(fp); |
---|
| 141 | } |
---|
| 142 | } |
---|
| 143 | |
---|
[7840b66] | 144 | static void rtems_shell_init_commands(void) |
---|
| 145 | { |
---|
| 146 | rtems_shell_cmd_t * const *c; |
---|
| 147 | rtems_shell_alias_t * const *a; |
---|
| 148 | |
---|
| 149 | for ( c = rtems_shell_Initial_commands ; *c ; c++ ) { |
---|
| 150 | rtems_shell_add_cmd_struct( *c ); |
---|
| 151 | } |
---|
| 152 | |
---|
| 153 | for ( a = rtems_shell_Initial_aliases ; *a ; a++ ) { |
---|
| 154 | rtems_shell_alias_cmd( (*a)->name, (*a)->alias ); |
---|
| 155 | } |
---|
| 156 | } |
---|
| 157 | |
---|
[373ccbb9] | 158 | static void rtems_shell_init_once(void) |
---|
| 159 | { |
---|
| 160 | struct passwd pwd; |
---|
| 161 | struct passwd *pwd_res; |
---|
| 162 | |
---|
| 163 | pthread_key_create(&rtems_shell_current_env_key, rtems_shell_env_free); |
---|
| 164 | |
---|
| 165 | /* dummy call to init /etc dir */ |
---|
| 166 | getpwuid_r(0, &pwd, NULL, 0, &pwd_res); |
---|
| 167 | |
---|
| 168 | rtems_shell_create_file("etc/issue", |
---|
| 169 | "\n" |
---|
| 170 | "Welcome to @V\\n" |
---|
| 171 | "Login into @S\\n"); |
---|
| 172 | |
---|
| 173 | rtems_shell_create_file("/etc/issue.net", |
---|
| 174 | "\n" |
---|
| 175 | "Welcome to %v\n" |
---|
| 176 | "running on %m\n"); |
---|
[7840b66] | 177 | |
---|
| 178 | rtems_shell_init_commands(); |
---|
[2465c01] | 179 | rtems_shell_register_monitor_commands(); |
---|
| 180 | } |
---|
| 181 | |
---|
| 182 | void rtems_shell_init_environment(void) |
---|
| 183 | { |
---|
| 184 | assert(pthread_once(&rtems_shell_once, rtems_shell_init_once) == 0); |
---|
[6cd4a5c] | 185 | } |
---|
| 186 | |
---|
[d007cc2] | 187 | /* |
---|
| 188 | * Set the shell env into the current thread's shell key. |
---|
| 189 | */ |
---|
| 190 | static bool rtems_shell_set_shell_env( |
---|
| 191 | rtems_shell_env_t* shell_env |
---|
| 192 | ) |
---|
| 193 | { |
---|
| 194 | /* |
---|
| 195 | * The shell environment can be managed or it can be provided by a |
---|
| 196 | * user. We need to create a handle to hold the env pointer. |
---|
| 197 | */ |
---|
| 198 | rtems_shell_env_key_handle *handle; |
---|
| 199 | int eno; |
---|
| 200 | |
---|
| 201 | handle = malloc(sizeof(rtems_shell_env_key_handle)); |
---|
| 202 | if (handle == NULL) { |
---|
| 203 | rtems_error(0, "no memory for shell env key handle)"); |
---|
| 204 | return false; |
---|
| 205 | } |
---|
| 206 | |
---|
| 207 | handle->managed = shell_env->managed; |
---|
| 208 | handle->env = shell_env; |
---|
| 209 | |
---|
| 210 | eno = pthread_setspecific(rtems_shell_current_env_key, handle); |
---|
| 211 | if (eno != 0) { |
---|
| 212 | rtems_error(0, "pthread_setspecific(shell_current_env_key): set"); |
---|
| 213 | return false; |
---|
| 214 | } |
---|
| 215 | |
---|
| 216 | return true; |
---|
| 217 | } |
---|
| 218 | |
---|
| 219 | /* |
---|
| 220 | * Clear the current thread's shell key. |
---|
| 221 | */ |
---|
| 222 | static void rtems_shell_clear_shell_env(void) |
---|
| 223 | { |
---|
| 224 | int eno; |
---|
| 225 | |
---|
| 226 | /* |
---|
| 227 | * Run the destructor manually. |
---|
| 228 | */ |
---|
| 229 | rtems_shell_env_free(pthread_getspecific(rtems_shell_current_env_key)); |
---|
| 230 | |
---|
| 231 | /* |
---|
| 232 | * Clear the key |
---|
| 233 | */ |
---|
| 234 | eno = pthread_setspecific(rtems_shell_current_env_key, NULL); |
---|
| 235 | if (eno != 0) |
---|
| 236 | rtems_error(0, "pthread_setspecific(shell_current_env_key): clear"); |
---|
| 237 | |
---|
| 238 | /* |
---|
| 239 | * Clear stdin and stdout file pointers of they will be closed |
---|
| 240 | */ |
---|
| 241 | stdin = NULL; |
---|
| 242 | stdout = NULL; |
---|
| 243 | } |
---|
| 244 | |
---|
[6cd4a5c] | 245 | /* |
---|
| 246 | * Return the current shell environment |
---|
| 247 | */ |
---|
| 248 | rtems_shell_env_t *rtems_shell_get_current_env(void) |
---|
| 249 | { |
---|
[d007cc2] | 250 | rtems_shell_env_key_handle *handle; |
---|
| 251 | handle = (rtems_shell_env_key_handle*) |
---|
| 252 | pthread_getspecific(rtems_shell_current_env_key); |
---|
| 253 | return handle == NULL ? NULL : handle->env; |
---|
[bb58190] | 254 | } |
---|
| 255 | |
---|
| 256 | /* |
---|
| 257 | * Duplication the current shell environment and if none is set |
---|
| 258 | * clear it. |
---|
| 259 | */ |
---|
| 260 | void rtems_shell_dup_current_env(rtems_shell_env_t *copy) |
---|
| 261 | { |
---|
| 262 | rtems_shell_env_t *env = rtems_shell_get_current_env(); |
---|
[d007cc2] | 263 | if (env != NULL) { |
---|
| 264 | shell_std_debug("dup: existing parent\n"); |
---|
[bb58190] | 265 | *copy = *env; |
---|
| 266 | } |
---|
| 267 | else { |
---|
[d007cc2] | 268 | *copy = rtems_global_shell_env; |
---|
| 269 | copy->magic = rtems_build_name('S', 'E', 'N', 'V'); |
---|
| 270 | copy->devname = CONSOLE_DEVICE_NAME; |
---|
| 271 | copy->taskname = "RTSH"; |
---|
| 272 | copy->parent_stdout = stdout; |
---|
| 273 | copy->parent_stdin = stdin; |
---|
| 274 | copy->parent_stderr = stderr; |
---|
| 275 | shell_std_debug("dup: global: copy: %p out: %d (%p) in: %d (%p)\n", |
---|
| 276 | copy, |
---|
| 277 | fileno(copy->parent_stdout), copy->parent_stdout, |
---|
| 278 | fileno(copy->parent_stdin), copy->parent_stdin); |
---|
[bb58190] | 279 | } |
---|
[d007cc2] | 280 | /* |
---|
| 281 | * Duplicated environments are not managed. |
---|
| 282 | */ |
---|
| 283 | copy->managed = false; |
---|
[6cd4a5c] | 284 | } |
---|
| 285 | |
---|
[814d9588] | 286 | /* |
---|
| 287 | * Get a line of user input with modest features |
---|
| 288 | */ |
---|
[94547d1] | 289 | static int rtems_shell_line_editor( |
---|
[ea90df23] | 290 | char *cmds[], |
---|
| 291 | int count, |
---|
| 292 | int size, |
---|
| 293 | const char *prompt, |
---|
| 294 | FILE *in, |
---|
| 295 | FILE *out |
---|
| 296 | ) |
---|
| 297 | { |
---|
| 298 | unsigned int extended_key; |
---|
[7c4cdeb9] | 299 | int c; |
---|
[ea90df23] | 300 | int col; |
---|
| 301 | int last_col; |
---|
| 302 | int output; |
---|
| 303 | char line[size]; |
---|
| 304 | char new_line[size]; |
---|
| 305 | int up; |
---|
| 306 | int cmd = -1; |
---|
| 307 | int inserting = 1; |
---|
[d007cc2] | 308 | int in_fileno = fileno(in); |
---|
| 309 | int out_fileno = fileno(out); |
---|
[8a775c27] | 310 | |
---|
[d007cc2] | 311 | /* |
---|
| 312 | * Only this task can use this file descriptor because calling |
---|
| 313 | * fileno will block if another thread call made a call on this |
---|
| 314 | * descriptor. |
---|
| 315 | */ |
---|
| 316 | output = (out && isatty(in_fileno)); |
---|
[ea90df23] | 317 | |
---|
| 318 | col = last_col = 0; |
---|
[8a775c27] | 319 | |
---|
[d007cc2] | 320 | tcdrain(in_fileno); |
---|
[ea90df23] | 321 | if (out) |
---|
[d007cc2] | 322 | tcdrain(out_fileno); |
---|
[ea90df23] | 323 | |
---|
| 324 | if (output && prompt) |
---|
| 325 | fprintf(out, "\r%s", prompt); |
---|
[8a775c27] | 326 | |
---|
[ea90df23] | 327 | line[0] = 0; |
---|
| 328 | new_line[0] = 0; |
---|
[8a775c27] | 329 | |
---|
[ea90df23] | 330 | for (;;) { |
---|
[8a775c27] | 331 | |
---|
[ea90df23] | 332 | if (output) |
---|
| 333 | fflush(out); |
---|
| 334 | |
---|
| 335 | extended_key = rtems_shell_getchar(in); |
---|
| 336 | |
---|
| 337 | if (extended_key == EOF) |
---|
| 338 | return -2; |
---|
[8a775c27] | 339 | |
---|
[ea90df23] | 340 | c = extended_key & RTEMS_SHELL_KEYS_NORMAL_MASK; |
---|
[8a775c27] | 341 | |
---|
[ea90df23] | 342 | /* |
---|
| 343 | * Make the extended_key usable as a boolean. |
---|
| 344 | */ |
---|
| 345 | extended_key &= ~RTEMS_SHELL_KEYS_NORMAL_MASK; |
---|
[8a775c27] | 346 | |
---|
[ea90df23] | 347 | up = 0; |
---|
[8a775c27] | 348 | |
---|
[ea90df23] | 349 | if (extended_key) |
---|
| 350 | { |
---|
| 351 | switch (c) |
---|
| 352 | { |
---|
| 353 | case RTEMS_SHELL_KEYS_END: |
---|
| 354 | if (output) |
---|
[8bca4fc] | 355 | fprintf(out, "%s", line + col); |
---|
[ea90df23] | 356 | col = (int) strlen (line); |
---|
| 357 | break; |
---|
| 358 | |
---|
| 359 | case RTEMS_SHELL_KEYS_HOME: |
---|
| 360 | if (output) { |
---|
| 361 | if (prompt) |
---|
| 362 | fprintf(out,"\r%s", prompt); |
---|
| 363 | } |
---|
| 364 | col = 0; |
---|
| 365 | break; |
---|
| 366 | |
---|
| 367 | case RTEMS_SHELL_KEYS_LARROW: |
---|
[22e98377] | 368 | c = 2; |
---|
| 369 | extended_key = 0; |
---|
[ea90df23] | 370 | break; |
---|
| 371 | |
---|
[22e98377] | 372 | case RTEMS_SHELL_KEYS_RARROW: |
---|
| 373 | c = 6; |
---|
| 374 | extended_key = 0; |
---|
| 375 | break; |
---|
[ea90df23] | 376 | |
---|
| 377 | case RTEMS_SHELL_KEYS_UARROW: |
---|
[22e98377] | 378 | c = 16; |
---|
| 379 | extended_key = 0; |
---|
| 380 | break; |
---|
[ea90df23] | 381 | |
---|
| 382 | case RTEMS_SHELL_KEYS_DARROW: |
---|
[22e98377] | 383 | c = 14; |
---|
| 384 | extended_key = 0; |
---|
| 385 | break; |
---|
[ea90df23] | 386 | |
---|
| 387 | case RTEMS_SHELL_KEYS_DEL: |
---|
| 388 | if (line[col] != '\0') |
---|
| 389 | { |
---|
| 390 | int end; |
---|
| 391 | int bs; |
---|
| 392 | strcpy (&line[col], &line[col + 1]); |
---|
| 393 | if (output) { |
---|
| 394 | fprintf(out,"\r%s%s ", prompt, line); |
---|
| 395 | end = (int) strlen (line); |
---|
| 396 | for (bs = 0; bs < ((end - col) + 1); bs++) |
---|
| 397 | fputc('\b', out); |
---|
| 398 | } |
---|
| 399 | } |
---|
| 400 | break; |
---|
| 401 | |
---|
| 402 | case RTEMS_SHELL_KEYS_INS: |
---|
| 403 | inserting = inserting ? 0 : 1; |
---|
| 404 | break; |
---|
| 405 | } |
---|
| 406 | } |
---|
[22e98377] | 407 | if (!extended_key) |
---|
[ea90df23] | 408 | { |
---|
| 409 | switch (c) |
---|
| 410 | { |
---|
[22e98377] | 411 | case 1: /*Control-a*/ |
---|
[ea90df23] | 412 | if (output) { |
---|
| 413 | if (prompt) |
---|
| 414 | fprintf(out,"\r%s", prompt); |
---|
| 415 | } |
---|
| 416 | col = 0; |
---|
| 417 | break; |
---|
[8a775c27] | 418 | |
---|
[22e98377] | 419 | case 2: /* Control-B */ |
---|
| 420 | if (col > 0) |
---|
| 421 | { |
---|
| 422 | col--; |
---|
| 423 | if (output) |
---|
| 424 | fputc('\b', out); |
---|
| 425 | } |
---|
| 426 | break; |
---|
| 427 | |
---|
| 428 | case 4: /* Control-D */ |
---|
| 429 | if (strlen(line)) { |
---|
| 430 | if (col < strlen(line)) { |
---|
| 431 | strcpy (line + col, line + col + 1); |
---|
| 432 | if (output) { |
---|
| 433 | int bs; |
---|
| 434 | fprintf(out,"%s \b", line + col); |
---|
| 435 | for (bs = 0; bs < ((int) strlen (line) - col); bs++) |
---|
| 436 | fputc('\b', out); |
---|
| 437 | } |
---|
| 438 | } |
---|
| 439 | break; |
---|
| 440 | } |
---|
| 441 | /* Fall through */ |
---|
| 442 | |
---|
| 443 | case EOF: |
---|
| 444 | if (output) |
---|
| 445 | fputc('\n', out); |
---|
| 446 | return -2; |
---|
| 447 | |
---|
| 448 | case 5: /*Control-e*/ |
---|
[ea90df23] | 449 | if (output) |
---|
[8bca4fc] | 450 | fprintf(out, "%s", line + col); |
---|
[ea90df23] | 451 | col = (int) strlen (line); |
---|
| 452 | break; |
---|
| 453 | |
---|
[22e98377] | 454 | case 6: /* Control-F */ |
---|
| 455 | if ((col < size) && (line[col] != '\0')) { |
---|
| 456 | if (output) |
---|
| 457 | fputc(line[col], out); |
---|
| 458 | col++; |
---|
| 459 | } |
---|
| 460 | break; |
---|
| 461 | |
---|
| 462 | case 7: /* Control-G */ |
---|
| 463 | if (output) { |
---|
[06ac8b71] | 464 | /* |
---|
| 465 | * The (int) cast is needed because the width specifier (%*) |
---|
| 466 | * must be an int, but strlen() returns a size_t. Without |
---|
| 467 | * the case, the result is a printf() format warning. |
---|
| 468 | */ |
---|
| 469 | fprintf(out,"\r%s%*c", prompt, (int) strlen (line), ' '); |
---|
[22e98377] | 470 | fprintf(out,"\r%s\x7", prompt); |
---|
| 471 | } |
---|
| 472 | memset (line, '\0', strlen(line)); |
---|
| 473 | col = 0; |
---|
| 474 | break; |
---|
| 475 | |
---|
| 476 | case 11: /*Control-k*/ |
---|
[ea90df23] | 477 | if (line[col]) { |
---|
| 478 | if (output) { |
---|
| 479 | int end = strlen(line); |
---|
| 480 | int bs; |
---|
| 481 | fprintf(out,"%*c", end - col, ' '); |
---|
| 482 | for (bs = 0; bs < (end - col); bs++) |
---|
| 483 | fputc('\b', out); |
---|
| 484 | } |
---|
| 485 | line[col] = '\0'; |
---|
| 486 | } |
---|
| 487 | break; |
---|
[8a775c27] | 488 | |
---|
[ea90df23] | 489 | case '\f': |
---|
| 490 | if (output) { |
---|
| 491 | int end; |
---|
| 492 | int bs; |
---|
| 493 | fputc('\f',out); |
---|
| 494 | fprintf(out,"\r%s%s", prompt, line); |
---|
| 495 | end = (int) strlen (line); |
---|
| 496 | for (bs = 0; bs < (end - col); bs++) |
---|
| 497 | fputc('\b', out); |
---|
| 498 | } |
---|
| 499 | break; |
---|
| 500 | |
---|
| 501 | case '\b': |
---|
| 502 | case '\x7f': |
---|
| 503 | if (col > 0) |
---|
| 504 | { |
---|
| 505 | int bs; |
---|
| 506 | col--; |
---|
| 507 | strcpy (line + col, line + col + 1); |
---|
| 508 | if (output) { |
---|
| 509 | fprintf(out,"\b%s \b", line + col); |
---|
| 510 | for (bs = 0; bs < ((int) strlen (line) - col); bs++) |
---|
| 511 | fputc('\b', out); |
---|
| 512 | } |
---|
| 513 | } |
---|
| 514 | break; |
---|
| 515 | |
---|
| 516 | case '\n': |
---|
| 517 | case '\r': |
---|
| 518 | { |
---|
| 519 | /* |
---|
| 520 | * Process the command. |
---|
| 521 | */ |
---|
| 522 | if (output) |
---|
| 523 | fprintf(out,"\n"); |
---|
[8a775c27] | 524 | |
---|
[ea90df23] | 525 | /* |
---|
| 526 | * Only process the command if we have a command and it is not |
---|
| 527 | * repeated in the history. |
---|
| 528 | */ |
---|
| 529 | if (strlen(line) == 0) { |
---|
| 530 | cmd = -1; |
---|
| 531 | } else { |
---|
| 532 | if ((cmd < 0) || (strcmp(line, cmds[cmd]) != 0)) { |
---|
| 533 | if (count > 1) |
---|
| 534 | memmove(cmds[1], cmds[0], (count - 1) * size); |
---|
| 535 | memmove (cmds[0], line, size); |
---|
| 536 | cmd = 0; |
---|
[22e98377] | 537 | } else { |
---|
| 538 | if ((cmd > 1) && (strcmp(line, cmds[cmd]) == 0)) { |
---|
| 539 | memmove(cmds[1], cmds[0], cmd * size); |
---|
| 540 | memmove (cmds[0], line, size); |
---|
| 541 | cmd = 0; |
---|
| 542 | } |
---|
[ea90df23] | 543 | } |
---|
| 544 | } |
---|
| 545 | } |
---|
| 546 | return cmd; |
---|
| 547 | |
---|
[22e98377] | 548 | case 16: /* Control-P */ |
---|
| 549 | if ((cmd >= (count - 1)) || (strlen(cmds[cmd + 1]) == 0)) { |
---|
| 550 | if (output) |
---|
| 551 | fputc('\x7', out); |
---|
| 552 | break; |
---|
| 553 | } |
---|
| 554 | |
---|
| 555 | up = 1; |
---|
| 556 | /* drop through */ |
---|
| 557 | |
---|
| 558 | case 14: /* Control-N */ |
---|
| 559 | { |
---|
| 560 | int last_cmd = cmd; |
---|
| 561 | int clen = strlen (line); |
---|
| 562 | |
---|
| 563 | if (prompt) |
---|
| 564 | clen += strlen(prompt); |
---|
| 565 | |
---|
| 566 | if (up) { |
---|
| 567 | cmd++; |
---|
| 568 | } else { |
---|
| 569 | if (cmd < 0) { |
---|
| 570 | if (output) |
---|
| 571 | fprintf(out, "\x7"); |
---|
| 572 | break; |
---|
| 573 | } |
---|
| 574 | else |
---|
| 575 | cmd--; |
---|
| 576 | } |
---|
| 577 | |
---|
| 578 | if ((last_cmd < 0) || (strcmp(cmds[last_cmd], line) != 0)) |
---|
| 579 | memcpy (new_line, line, size); |
---|
| 580 | |
---|
| 581 | if (cmd < 0) |
---|
| 582 | memcpy (line, new_line, size); |
---|
| 583 | else |
---|
| 584 | memcpy (line, cmds[cmd], size); |
---|
| 585 | |
---|
| 586 | col = strlen (line); |
---|
| 587 | |
---|
| 588 | if (output) { |
---|
| 589 | fprintf(out,"\r%s%*c", prompt, clen, ' '); |
---|
| 590 | fprintf(out,"\r%s%s", prompt, line); |
---|
| 591 | } |
---|
| 592 | } |
---|
| 593 | break; |
---|
| 594 | |
---|
| 595 | case 20: /* Control-T */ |
---|
| 596 | if (col > 0) |
---|
| 597 | { |
---|
| 598 | char tmp; |
---|
| 599 | if (col == strlen(line)) { |
---|
| 600 | col--; |
---|
| 601 | if (output) |
---|
| 602 | fprintf(out,"\b"); |
---|
| 603 | } |
---|
| 604 | tmp = line[col]; |
---|
| 605 | line[col] = line[col - 1]; |
---|
| 606 | line[col - 1] = tmp; |
---|
| 607 | if (output) |
---|
| 608 | fprintf(out,"\b%c%c", line[col - 1], line[col]); |
---|
| 609 | col++; |
---|
| 610 | } else { |
---|
| 611 | if (output) |
---|
| 612 | fputc('\x7', out); |
---|
| 613 | } |
---|
| 614 | break; |
---|
| 615 | |
---|
| 616 | case 21: /* Control-U */ |
---|
| 617 | if (col > 0) |
---|
| 618 | { |
---|
| 619 | int clen = strlen (line); |
---|
| 620 | |
---|
| 621 | strcpy (line, line + col); |
---|
| 622 | if (output) { |
---|
| 623 | fprintf(out,"\r%s%*c", prompt, clen, ' '); |
---|
| 624 | fprintf(out,"\r%s%s", prompt, line); |
---|
| 625 | } |
---|
| 626 | col = 0; |
---|
| 627 | } |
---|
| 628 | break; |
---|
| 629 | |
---|
[ea90df23] | 630 | default: |
---|
[7311863] | 631 | if ((col < (size - 1)) && (c >= ' ') && (c <= '~')) { |
---|
[ea90df23] | 632 | int end = strlen (line); |
---|
| 633 | if (inserting && (col < end) && (end < size)) { |
---|
| 634 | int ch, bs; |
---|
| 635 | for (ch = end + 1; ch > col; ch--) |
---|
| 636 | line[ch] = line[ch - 1]; |
---|
| 637 | if (output) { |
---|
[8bca4fc] | 638 | fprintf(out, "%s", line + col); |
---|
[ea90df23] | 639 | for (bs = 0; bs < (end - col + 1); bs++) |
---|
| 640 | fputc('\b', out); |
---|
| 641 | } |
---|
| 642 | } |
---|
| 643 | line[col++] = c; |
---|
| 644 | if (col > end) |
---|
| 645 | line[col] = '\0'; |
---|
| 646 | if (output) |
---|
| 647 | fputc(c, out); |
---|
| 648 | } |
---|
| 649 | break; |
---|
| 650 | } |
---|
| 651 | } |
---|
| 652 | } |
---|
| 653 | return -2; |
---|
| 654 | } |
---|
| 655 | |
---|
[fa028bb] | 656 | static bool rtems_shell_login(rtems_shell_env_t *env, FILE * in,FILE * out) |
---|
| 657 | { |
---|
[d007cc2] | 658 | FILE *fd; |
---|
| 659 | int c; |
---|
| 660 | time_t t; |
---|
[bb58190] | 661 | |
---|
[6dd411aa] | 662 | if (out) { |
---|
[bb58190] | 663 | if ((env->devname[5]!='p')|| |
---|
| 664 | (env->devname[6]!='t')|| |
---|
| 665 | (env->devname[7]!='y')) { |
---|
[6dd411aa] | 666 | fd = fopen("/etc/issue","r"); |
---|
| 667 | if (fd) { |
---|
[d007cc2] | 668 | while ((c = fgetc(fd)) != EOF) { |
---|
[6dd411aa] | 669 | if (c=='@') { |
---|
[d007cc2] | 670 | switch (c = fgetc(fd)) { |
---|
[6dd411aa] | 671 | case 'L': |
---|
[bb58190] | 672 | fprintf(out,"%s", env->devname); |
---|
[6dd411aa] | 673 | break; |
---|
| 674 | case 'B': |
---|
| 675 | fprintf(out,"0"); |
---|
| 676 | break; |
---|
[70d689a] | 677 | case 'T': |
---|
[6dd411aa] | 678 | case 'D': |
---|
| 679 | time(&t); |
---|
| 680 | fprintf(out,"%s",ctime(&t)); |
---|
| 681 | break; |
---|
| 682 | case 'S': |
---|
| 683 | fprintf(out,"RTEMS"); |
---|
| 684 | break; |
---|
| 685 | case 'V': |
---|
[1af8e45b] | 686 | fprintf( |
---|
| 687 | out, |
---|
| 688 | "%s\n%s", |
---|
| 689 | rtems_get_version_string(), |
---|
| 690 | rtems_get_copyright_notice() |
---|
| 691 | ); |
---|
[6dd411aa] | 692 | break; |
---|
| 693 | case '@': |
---|
| 694 | fprintf(out,"@"); |
---|
| 695 | break; |
---|
| 696 | default : |
---|
| 697 | fprintf(out,"@%c",c); |
---|
| 698 | break; |
---|
| 699 | } |
---|
| 700 | } else if (c=='\\') { |
---|
| 701 | switch(c=fgetc(fd)) { |
---|
| 702 | case '\\': fprintf(out,"\\"); break; |
---|
| 703 | case 'b': fprintf(out,"\b"); break; |
---|
| 704 | case 'f': fprintf(out,"\f"); break; |
---|
| 705 | case 'n': fprintf(out,"\n"); break; |
---|
| 706 | case 'r': fprintf(out,"\r"); break; |
---|
| 707 | case 's': fprintf(out," "); break; |
---|
| 708 | case 't': fprintf(out,"\t"); break; |
---|
| 709 | case '@': fprintf(out,"@"); break; |
---|
| 710 | } |
---|
| 711 | } else { |
---|
| 712 | fputc(c,out); |
---|
| 713 | } |
---|
| 714 | } |
---|
| 715 | fclose(fd); |
---|
| 716 | } |
---|
| 717 | } else { |
---|
| 718 | fd = fopen("/etc/issue.net","r"); |
---|
| 719 | if (fd) { |
---|
| 720 | while ((c=fgetc(fd))!=EOF) { |
---|
| 721 | if (c=='%') { |
---|
| 722 | switch(c=fgetc(fd)) { |
---|
| 723 | case 't': |
---|
[bb58190] | 724 | fprintf(out,"%s", env->devname); |
---|
[6dd411aa] | 725 | break; |
---|
| 726 | case 'h': |
---|
| 727 | fprintf(out,"0"); |
---|
| 728 | break; |
---|
| 729 | case 'D': |
---|
| 730 | fprintf(out," "); |
---|
| 731 | break; |
---|
| 732 | case 'd': |
---|
| 733 | time(&t); |
---|
| 734 | fprintf(out,"%s",ctime(&t)); |
---|
| 735 | break; |
---|
| 736 | case 's': |
---|
| 737 | fprintf(out,"RTEMS"); |
---|
| 738 | break; |
---|
| 739 | case 'm': |
---|
| 740 | fprintf(out,"(" CPU_NAME "/" CPU_MODEL_NAME ")"); |
---|
| 741 | break; |
---|
| 742 | case 'r': |
---|
[4b9b6dd] | 743 | fprintf(out,rtems_get_version_string()); |
---|
[6dd411aa] | 744 | break; |
---|
| 745 | case 'v': |
---|
[1af8e45b] | 746 | fprintf( |
---|
| 747 | out, |
---|
| 748 | "%s\n%s", |
---|
| 749 | rtems_get_version_string(), |
---|
| 750 | rtems_get_copyright_notice() |
---|
| 751 | ); |
---|
[6dd411aa] | 752 | break; |
---|
| 753 | case '%':fprintf(out,"%%"); |
---|
| 754 | break; |
---|
| 755 | default: |
---|
| 756 | fprintf(out,"%%%c",c); |
---|
| 757 | break; |
---|
| 758 | } |
---|
| 759 | } else { |
---|
| 760 | fputc(c,out); |
---|
| 761 | } |
---|
| 762 | } |
---|
| 763 | fclose(fd); |
---|
| 764 | } |
---|
| 765 | } |
---|
| 766 | } |
---|
| 767 | |
---|
[bb58190] | 768 | return rtems_shell_login_prompt(in, out, env->devname, env->login_check); |
---|
[b2712e3] | 769 | } |
---|
| 770 | |
---|
[814d9588] | 771 | #if defined(SHELL_DEBUG) |
---|
[2eeb648c] | 772 | void rtems_shell_print_env( |
---|
| 773 | rtems_shell_env_t * shell_env |
---|
[6dd411aa] | 774 | ) |
---|
| 775 | { |
---|
| 776 | if ( !shell_env ) { |
---|
| 777 | printk( "shell_env is NULL\n" ); |
---|
| 778 | return; |
---|
| 779 | } |
---|
| 780 | printk( "shell_env=%p\n" |
---|
| 781 | "shell_env->magic=0x%08x\t" |
---|
| 782 | "shell_env->devname=%s\n" |
---|
| 783 | "shell_env->taskname=%s\t" |
---|
| 784 | "shell_env->exit_shell=%d\t" |
---|
| 785 | "shell_env->forever=%d\n", |
---|
| 786 | shell_env->magic, |
---|
| 787 | shell_env->devname, |
---|
| 788 | ((shell_env->taskname) ? shell_env->taskname : "NOT SET"), |
---|
| 789 | shell_env->exit_shell, |
---|
| 790 | shell_env->forever |
---|
| 791 | ); |
---|
| 792 | } |
---|
| 793 | #endif |
---|
[dd74e612] | 794 | |
---|
[94547d1] | 795 | static rtems_task rtems_shell_task(rtems_task_argument task_argument) |
---|
[6dd411aa] | 796 | { |
---|
[1ff9922] | 797 | rtems_shell_env_t *shell_env = (rtems_shell_env_t*) task_argument; |
---|
| 798 | rtems_id wake_on_end = shell_env->wake_on_end; |
---|
| 799 | rtems_shell_main_loop( shell_env ); |
---|
| 800 | if (wake_on_end != RTEMS_INVALID_ID) |
---|
| 801 | rtems_event_send (wake_on_end, RTEMS_EVENT_1); |
---|
[f004b2b8] | 802 | rtems_task_exit(); |
---|
[6dd411aa] | 803 | } |
---|
[dd74e612] | 804 | |
---|
[fa028bb] | 805 | static bool rtems_shell_init_user_env(void) |
---|
| 806 | { |
---|
| 807 | rtems_status_code sc; |
---|
| 808 | |
---|
| 809 | /* Make sure we have a private user environment */ |
---|
| 810 | sc = rtems_libio_set_private_env(); |
---|
| 811 | if (sc != RTEMS_SUCCESSFUL) { |
---|
[d007cc2] | 812 | rtems_error(sc, "rtems_libio_set_private_env():"); |
---|
[fa028bb] | 813 | return false; |
---|
| 814 | } |
---|
| 815 | |
---|
| 816 | /* Make an effective root user */ |
---|
| 817 | seteuid(0); |
---|
| 818 | setegid(0); |
---|
| 819 | |
---|
| 820 | return chroot("/") == 0; |
---|
| 821 | } |
---|
| 822 | |
---|
[ea90df23] | 823 | #define RTEMS_SHELL_MAXIMUM_ARGUMENTS (128) |
---|
| 824 | #define RTEMS_SHELL_CMD_SIZE (128) |
---|
| 825 | #define RTEMS_SHELL_CMD_COUNT (32) |
---|
| 826 | #define RTEMS_SHELL_PROMPT_SIZE (128) |
---|
[aed742c] | 827 | |
---|
[1167235] | 828 | bool rtems_shell_main_loop( |
---|
[d007cc2] | 829 | rtems_shell_env_t *shell_env |
---|
[798ff5a] | 830 | ) |
---|
[6dd411aa] | 831 | { |
---|
[d007cc2] | 832 | struct termios term; |
---|
| 833 | struct termios previous_term; |
---|
| 834 | char *prompt = NULL; |
---|
| 835 | int cmd; |
---|
| 836 | int cmd_count = 1; /* assume a script and so only 1 command line */ |
---|
| 837 | char *cmds[RTEMS_SHELL_CMD_COUNT]; |
---|
| 838 | char *cmd_argv; |
---|
| 839 | int argc; |
---|
| 840 | char *argv[RTEMS_SHELL_MAXIMUM_ARGUMENTS]; |
---|
| 841 | bool result = true; |
---|
| 842 | bool input_file = false; |
---|
| 843 | int line = 0; |
---|
| 844 | FILE *stdinToClose = NULL; |
---|
| 845 | FILE *stdoutToClose = NULL; |
---|
[2eeb648c] | 846 | |
---|
[2465c01] | 847 | rtems_shell_init_environment(); |
---|
[7840b66] | 848 | |
---|
[d007cc2] | 849 | if (shell_env->magic != rtems_build_name('S', 'E', 'N', 'V')) { |
---|
| 850 | rtems_error(0, "invalid shell environment passed to the main loop)"); |
---|
[6cd4a5c] | 851 | return false; |
---|
| 852 | } |
---|
| 853 | |
---|
[d007cc2] | 854 | if (!rtems_shell_set_shell_env(shell_env)) |
---|
[1167235] | 855 | return false; |
---|
[dd74e612] | 856 | |
---|
[fa028bb] | 857 | if (!rtems_shell_init_user_env()) { |
---|
[d007cc2] | 858 | rtems_error(0, "rtems_shell_init_user_env"); |
---|
| 859 | rtems_shell_clear_shell_env(); |
---|
[fa028bb] | 860 | return false; |
---|
| 861 | } |
---|
[6dd411aa] | 862 | |
---|
[d007cc2] | 863 | shell_std_debug("env: %p\n", shell_env); |
---|
[be8ab6a] | 864 | |
---|
[d007cc2] | 865 | if (shell_env->output == NULL || strcmp(shell_env->output, "stdout") == 0) { |
---|
| 866 | if (shell_env->parent_stdout != NULL) |
---|
| 867 | stdout = shell_env->parent_stdout; |
---|
| 868 | } |
---|
| 869 | else if (strcmp(shell_env->output, "stderr") == 0) { |
---|
| 870 | if (shell_env->parent_stderr != NULL) |
---|
| 871 | stdout = shell_env->parent_stderr; |
---|
| 872 | else |
---|
[1ff9922] | 873 | stdout = stderr; |
---|
[d007cc2] | 874 | } else if (strcmp(shell_env->output, "/dev/null") == 0) { |
---|
| 875 | fclose (stdout); |
---|
| 876 | } else { |
---|
| 877 | FILE *output = fopen(shell_env->output, |
---|
| 878 | shell_env->output_append ? "a" : "w"); |
---|
| 879 | if (output == NULL) { |
---|
| 880 | fprintf(stderr, "shell: open output %s failed: %s\n", |
---|
| 881 | shell_env->output, strerror(errno)); |
---|
| 882 | rtems_shell_clear_shell_env(); |
---|
| 883 | return false; |
---|
[1ff9922] | 884 | } |
---|
[d007cc2] | 885 | stdout = output; |
---|
| 886 | stdoutToClose = output; |
---|
[1ff9922] | 887 | } |
---|
[8a775c27] | 888 | |
---|
[d007cc2] | 889 | if (shell_env->input == NULL || strcmp(shell_env->input, "stdin") == 0) { |
---|
| 890 | if (shell_env->parent_stdin != NULL) |
---|
| 891 | stdin = shell_env->parent_stdin; |
---|
| 892 | } else { |
---|
| 893 | FILE *input = fopen(shell_env->input, "r"); |
---|
| 894 | if (input == NULL) { |
---|
[1ff9922] | 895 | fprintf(stderr, "shell: open input %s failed: %s\n", |
---|
[d007cc2] | 896 | shell_env->input, strerror(errno)); |
---|
| 897 | if (stdoutToClose != NULL) |
---|
| 898 | fclose(stdoutToClose); |
---|
| 899 | rtems_shell_clear_shell_env(); |
---|
[1167235] | 900 | return false; |
---|
[1ff9922] | 901 | } |
---|
| 902 | stdin = input; |
---|
[a3ddb08b] | 903 | stdinToClose = input; |
---|
[1167235] | 904 | shell_env->forever = false; |
---|
[d007cc2] | 905 | input_file = true; |
---|
[1ff9922] | 906 | } |
---|
[d007cc2] | 907 | |
---|
| 908 | if (!input_file) { |
---|
| 909 | /* Make a raw terminal, Linux Manuals */ |
---|
[8084ce80] | 910 | if (tcgetattr(fileno(stdin), &previous_term) >= 0) { |
---|
| 911 | term = previous_term; |
---|
[1ff9922] | 912 | term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); |
---|
| 913 | term.c_oflag &= ~OPOST; |
---|
| 914 | term.c_oflag |= (OPOST|ONLCR); /* But with cr+nl on output */ |
---|
| 915 | term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); |
---|
[d007cc2] | 916 | term.c_cflag |= CLOCAL | CREAD; |
---|
[1ff9922] | 917 | term.c_cc[VMIN] = 1; |
---|
| 918 | term.c_cc[VTIME] = 0; |
---|
| 919 | if (tcsetattr (fileno(stdin), TCSADRAIN, &term) < 0) { |
---|
| 920 | fprintf(stderr, |
---|
[d007cc2] | 921 | "shell: cannot set terminal attributes(%s)\n",shell_env->devname); |
---|
[1ff9922] | 922 | } |
---|
[814d9588] | 923 | } |
---|
[ea90df23] | 924 | cmd_count = RTEMS_SHELL_CMD_COUNT; |
---|
| 925 | prompt = malloc(RTEMS_SHELL_PROMPT_SIZE); |
---|
| 926 | if (!prompt) |
---|
| 927 | fprintf(stderr, |
---|
[d007cc2] | 928 | "shell: cannot allocate prompt memory\n"); |
---|
[6dd411aa] | 929 | } |
---|
| 930 | |
---|
[d007cc2] | 931 | shell_std_debug("child out: %d (%p)\n", fileno(stdout), stdout); |
---|
| 932 | shell_std_debug("child in: %d (%p)\n", fileno(stdin), stdin); |
---|
| 933 | |
---|
| 934 | /* Do not buffer if interactive else leave buffered */ |
---|
| 935 | if (!input_file) |
---|
| 936 | setvbuf(stdin, NULL, _IONBF, 0); |
---|
| 937 | setvbuf(stdout, NULL, _IONBF, 0); |
---|
[1ff9922] | 938 | |
---|
[ea90df23] | 939 | /* |
---|
| 940 | * Allocate the command line buffers. |
---|
| 941 | */ |
---|
[8c422e2] | 942 | cmd_argv = malloc (RTEMS_SHELL_CMD_SIZE); |
---|
| 943 | if (!cmd_argv) { |
---|
| 944 | fprintf(stderr, "no memory for command line buffers\n" ); |
---|
| 945 | } |
---|
[8a775c27] | 946 | |
---|
[ea90df23] | 947 | cmds[0] = calloc (cmd_count, RTEMS_SHELL_CMD_SIZE); |
---|
| 948 | if (!cmds[0]) { |
---|
| 949 | fprintf(stderr, "no memory for command line buffers\n" ); |
---|
| 950 | } |
---|
[8c422e2] | 951 | |
---|
| 952 | if (cmd_argv && cmds[0]) { |
---|
[ea90df23] | 953 | |
---|
| 954 | memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE); |
---|
| 955 | |
---|
| 956 | for (cmd = 1; cmd < cmd_count; cmd++) { |
---|
| 957 | cmds[cmd] = cmds[cmd - 1] + RTEMS_SHELL_CMD_SIZE; |
---|
[6dd411aa] | 958 | } |
---|
[8a775c27] | 959 | |
---|
[ea90df23] | 960 | do { |
---|
[fa028bb] | 961 | result = rtems_shell_init_user_env(); |
---|
| 962 | |
---|
| 963 | if (result) { |
---|
| 964 | /* |
---|
| 965 | * By using result here, we can fall to the bottom of the |
---|
| 966 | * loop when the connection is dropped during login and |
---|
| 967 | * keep on trucking. |
---|
| 968 | */ |
---|
| 969 | if (shell_env->login_check != NULL) { |
---|
| 970 | result = rtems_shell_login(shell_env, stdin,stdout); |
---|
| 971 | } else { |
---|
[ffd5285] | 972 | setuid(shell_env->uid); |
---|
| 973 | setgid(shell_env->gid); |
---|
| 974 | seteuid(shell_env->uid); |
---|
| 975 | setegid(shell_env->gid); |
---|
| 976 | rtems_current_user_env_getgroups(); |
---|
| 977 | |
---|
[fa028bb] | 978 | result = true; |
---|
| 979 | } |
---|
[7c4cdeb9] | 980 | } |
---|
| 981 | |
---|
| 982 | if (result) { |
---|
[ea90df23] | 983 | const char *c; |
---|
| 984 | memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE); |
---|
[1ff9922] | 985 | if (!input_file) { |
---|
[ea90df23] | 986 | rtems_shell_cat_file(stdout,"/etc/motd"); |
---|
| 987 | fprintf(stdout, "\n" |
---|
[a2097c5] | 988 | "RTEMS Shell on %s. Use 'help' to list commands.\n", |
---|
[ea90df23] | 989 | shell_env->devname); |
---|
[1ff9922] | 990 | } |
---|
[55c64fc9] | 991 | |
---|
| 992 | if (input_file) |
---|
| 993 | chdir(shell_env->cwd); |
---|
| 994 | else |
---|
| 995 | chdir("/"); /* XXX: chdir to getpwent homedir */ |
---|
[8a775c27] | 996 | |
---|
[1167235] | 997 | shell_env->exit_shell = false; |
---|
[ea90df23] | 998 | |
---|
| 999 | for (;;) { |
---|
| 1000 | /* Prompt section */ |
---|
| 1001 | if (prompt) { |
---|
| 1002 | rtems_shell_get_prompt(shell_env, prompt, |
---|
| 1003 | RTEMS_SHELL_PROMPT_SIZE); |
---|
| 1004 | } |
---|
[8a775c27] | 1005 | |
---|
[ea90df23] | 1006 | /* getcmd section */ |
---|
| 1007 | cmd = rtems_shell_line_editor(cmds, cmd_count, |
---|
| 1008 | RTEMS_SHELL_CMD_SIZE, prompt, |
---|
| 1009 | stdin, stdout); |
---|
| 1010 | |
---|
| 1011 | if (cmd == -1) |
---|
| 1012 | continue; /* empty line */ |
---|
[8a775c27] | 1013 | |
---|
[d007cc2] | 1014 | if (cmd == -2) { |
---|
| 1015 | result = false; |
---|
[ea90df23] | 1016 | break; /*EOF*/ |
---|
[d007cc2] | 1017 | } |
---|
[ea90df23] | 1018 | |
---|
| 1019 | line++; |
---|
| 1020 | |
---|
[55c64fc9] | 1021 | if (shell_env->echo) |
---|
| 1022 | fprintf(stdout, "%d: %s\n", line, cmds[cmd]); |
---|
[8a775c27] | 1023 | |
---|
[ea90df23] | 1024 | /* evaluate cmd section */ |
---|
| 1025 | c = cmds[cmd]; |
---|
| 1026 | while (*c) { |
---|
[bab5c5fa] | 1027 | if (!isblank((unsigned char)*c)) |
---|
[ea90df23] | 1028 | break; |
---|
| 1029 | c++; |
---|
| 1030 | } |
---|
[1ff9922] | 1031 | |
---|
[ea90df23] | 1032 | if (*c == '\0') /* empty line */ |
---|
| 1033 | continue; |
---|
[a5de1ef] | 1034 | |
---|
[ea90df23] | 1035 | if (*c == '#') { /* comment character */ |
---|
| 1036 | cmds[cmd][0] = 0; |
---|
| 1037 | continue; |
---|
| 1038 | } |
---|
[1ff9922] | 1039 | |
---|
[ea90df23] | 1040 | if (!strcmp(cmds[cmd],"bye") || !strcmp(cmds[cmd],"exit")) { |
---|
| 1041 | fprintf(stdout, "Shell exiting\n" ); |
---|
| 1042 | break; |
---|
| 1043 | } |
---|
[6dd411aa] | 1044 | |
---|
[ea90df23] | 1045 | /* exec cmd section */ |
---|
| 1046 | /* TODO: |
---|
| 1047 | * To avoid user crash catch the signals. |
---|
| 1048 | * Open a new stdio files with posibility of redirection * |
---|
| 1049 | * Run in a new shell task background. (unix &) |
---|
| 1050 | * Resuming. A little bash. |
---|
| 1051 | */ |
---|
[8c422e2] | 1052 | memcpy (cmd_argv, cmds[cmd], RTEMS_SHELL_CMD_SIZE); |
---|
| 1053 | if (!rtems_shell_make_args(cmd_argv, &argc, argv, |
---|
[ea90df23] | 1054 | RTEMS_SHELL_MAXIMUM_ARGUMENTS)) { |
---|
[d007cc2] | 1055 | int exit_code = rtems_shell_execute_cmd(argv[0], argc, argv); |
---|
| 1056 | if (shell_env->exit_code != NULL) |
---|
| 1057 | *shell_env->exit_code = exit_code; |
---|
| 1058 | if (exit_code != 0 && shell_env->exit_on_error) |
---|
| 1059 | shell_env->exit_shell = true; |
---|
[6dd411aa] | 1060 | } |
---|
[ea90df23] | 1061 | |
---|
| 1062 | /* end exec cmd section */ |
---|
| 1063 | if (shell_env->exit_shell) |
---|
| 1064 | break; |
---|
[6dd411aa] | 1065 | } |
---|
| 1066 | |
---|
[ea90df23] | 1067 | fflush( stdout ); |
---|
| 1068 | fflush( stderr ); |
---|
[6dd411aa] | 1069 | } |
---|
[d007cc2] | 1070 | shell_std_debug("end: %d %d\n", result, shell_env->forever); |
---|
[ea90df23] | 1071 | } while (result && shell_env->forever); |
---|
| 1072 | |
---|
| 1073 | } |
---|
| 1074 | |
---|
[8c422e2] | 1075 | if (cmds[0]) |
---|
| 1076 | free (cmds[0]); |
---|
| 1077 | if (cmd_argv) |
---|
| 1078 | free (cmd_argv); |
---|
[798ff5a] | 1079 | if (prompt) |
---|
| 1080 | free (prompt); |
---|
| 1081 | |
---|
[d007cc2] | 1082 | shell_std_debug("child in-to-close: %p\n", stdinToClose); |
---|
| 1083 | shell_std_debug("child out-to-close: %p\n", stdoutToClose); |
---|
| 1084 | |
---|
[8084ce80] | 1085 | if (stdinToClose) { |
---|
[a3ddb08b] | 1086 | fclose( stdinToClose ); |
---|
[8084ce80] | 1087 | } else { |
---|
[798ff5a] | 1088 | if (tcsetattr(fileno(stdin), TCSADRAIN, &previous_term) < 0) { |
---|
[8084ce80] | 1089 | fprintf( |
---|
| 1090 | stderr, |
---|
| 1091 | "shell: cannot reset terminal attributes (%s)\n", |
---|
| 1092 | shell_env->devname |
---|
| 1093 | ); |
---|
| 1094 | } |
---|
| 1095 | } |
---|
[a3ddb08b] | 1096 | if ( stdoutToClose ) |
---|
| 1097 | fclose( stdoutToClose ); |
---|
[d007cc2] | 1098 | rtems_shell_clear_shell_env(); |
---|
[1ff9922] | 1099 | return result; |
---|
[dd74e612] | 1100 | } |
---|
[6dd411aa] | 1101 | |
---|
[dd74e612] | 1102 | /* ----------------------------------------------- */ |
---|
[cbd1e87] | 1103 | static rtems_status_code rtems_shell_run ( |
---|
| 1104 | const char *task_name, |
---|
| 1105 | size_t task_stacksize, |
---|
| 1106 | rtems_task_priority task_priority, |
---|
| 1107 | const char *devname, |
---|
| 1108 | bool forever, |
---|
| 1109 | bool wait, |
---|
| 1110 | const char *input, |
---|
| 1111 | const char *output, |
---|
| 1112 | bool output_append, |
---|
| 1113 | rtems_id wake_on_end, |
---|
[d007cc2] | 1114 | int *exit_code, |
---|
[cbd1e87] | 1115 | bool echo, |
---|
| 1116 | rtems_shell_login_check_t login_check |
---|
[6dd411aa] | 1117 | ) |
---|
| 1118 | { |
---|
| 1119 | rtems_id task_id; |
---|
| 1120 | rtems_status_code sc; |
---|
[2eeb648c] | 1121 | rtems_shell_env_t *shell_env; |
---|
[4e5299f] | 1122 | rtems_name name; |
---|
| 1123 | |
---|
[d007cc2] | 1124 | rtems_shell_init_environment(); |
---|
| 1125 | |
---|
[e41eaa88] | 1126 | if ( task_name && strlen(task_name) >= 4) |
---|
[814d9588] | 1127 | name = rtems_build_name( |
---|
| 1128 | task_name[0], task_name[1], task_name[2], task_name[3]); |
---|
[4e5299f] | 1129 | else |
---|
| 1130 | name = rtems_build_name( 'S', 'E', 'N', 'V' ); |
---|
[6dd411aa] | 1131 | |
---|
| 1132 | sc = rtems_task_create( |
---|
[4e5299f] | 1133 | name, |
---|
[6dd411aa] | 1134 | task_priority, |
---|
[4e5299f] | 1135 | task_stacksize, |
---|
[3899a537] | 1136 | RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR, |
---|
[6dd411aa] | 1137 | RTEMS_LOCAL | RTEMS_FLOATING_POINT, |
---|
| 1138 | &task_id |
---|
| 1139 | ); |
---|
| 1140 | if (sc != RTEMS_SUCCESSFUL) { |
---|
[d007cc2] | 1141 | rtems_error(sc,"creating task %s in shell_init()",task_name); |
---|
[6dd411aa] | 1142 | return sc; |
---|
| 1143 | } |
---|
| 1144 | |
---|
[2eeb648c] | 1145 | shell_env = rtems_shell_init_env( NULL ); |
---|
[6dd411aa] | 1146 | if ( !shell_env ) { |
---|
[d007cc2] | 1147 | rtems_error(RTEMS_NO_MEMORY, |
---|
| 1148 | "allocating shell_env %s in shell_init()",task_name); |
---|
[6dd411aa] | 1149 | return RTEMS_NO_MEMORY; |
---|
| 1150 | } |
---|
[d007cc2] | 1151 | |
---|
| 1152 | shell_std_debug("run: env: %p\n", shell_env); |
---|
| 1153 | |
---|
[1ff9922] | 1154 | shell_env->devname = devname; |
---|
| 1155 | shell_env->taskname = task_name; |
---|
[d007cc2] | 1156 | |
---|
[1167235] | 1157 | shell_env->exit_shell = false; |
---|
[1ff9922] | 1158 | shell_env->forever = forever; |
---|
[55c64fc9] | 1159 | shell_env->echo = echo; |
---|
[d007cc2] | 1160 | shell_env->input = input == NULL ? NULL : strdup (input); |
---|
| 1161 | shell_env->output = output == NULL ? NULL : strdup (output); |
---|
[1ff9922] | 1162 | shell_env->output_append = output_append; |
---|
[d007cc2] | 1163 | shell_env->parent_stdin = stdin; |
---|
| 1164 | shell_env->parent_stdout = stdout; |
---|
| 1165 | shell_env->parent_stderr = stderr; |
---|
[1ff9922] | 1166 | shell_env->wake_on_end = wake_on_end; |
---|
[d007cc2] | 1167 | shell_env->exit_code = exit_code; |
---|
[8a775c27] | 1168 | shell_env->login_check = login_check; |
---|
[ffd5285] | 1169 | shell_env->uid = getuid(); |
---|
| 1170 | shell_env->gid = getgid(); |
---|
[6dd411aa] | 1171 | |
---|
[55c64fc9] | 1172 | getcwd(shell_env->cwd, sizeof(shell_env->cwd)); |
---|
| 1173 | |
---|
[d007cc2] | 1174 | shell_std_debug("run out: %d (%p)\n", |
---|
| 1175 | fileno(shell_env->parent_stdout), shell_env->parent_stdout); |
---|
| 1176 | shell_std_debug("run in: %d (%p)\n", |
---|
| 1177 | fileno(shell_env->parent_stdin), shell_env->parent_stdin); |
---|
| 1178 | |
---|
[798ff5a] | 1179 | sc = rtems_task_start(task_id, rtems_shell_task, |
---|
[d007cc2] | 1180 | (rtems_task_argument) shell_env); |
---|
[798ff5a] | 1181 | if (sc != RTEMS_SUCCESSFUL) { |
---|
[d007cc2] | 1182 | rtems_error(sc,"starting task %s in shell_init()",task_name); |
---|
| 1183 | free( (void*) shell_env->input ); |
---|
| 1184 | free( (void*) shell_env->output ); |
---|
| 1185 | free( shell_env ); |
---|
[798ff5a] | 1186 | return sc; |
---|
| 1187 | } |
---|
| 1188 | |
---|
| 1189 | if (wait) { |
---|
| 1190 | rtems_event_set out; |
---|
| 1191 | sc = rtems_event_receive (RTEMS_EVENT_1, RTEMS_WAIT, 0, &out); |
---|
| 1192 | } |
---|
| 1193 | |
---|
[d007cc2] | 1194 | shell_std_debug("run: end: sc:%d ec:%d\n", sc, *exit_code); |
---|
| 1195 | |
---|
| 1196 | return sc; |
---|
[6dd411aa] | 1197 | } |
---|
[1ff9922] | 1198 | |
---|
[798ff5a] | 1199 | rtems_status_code rtems_shell_init( |
---|
[cbd1e87] | 1200 | const char *task_name, |
---|
| 1201 | size_t task_stacksize, |
---|
| 1202 | rtems_task_priority task_priority, |
---|
| 1203 | const char *devname, |
---|
| 1204 | bool forever, |
---|
| 1205 | bool wait, |
---|
| 1206 | rtems_shell_login_check_t login_check |
---|
[1ff9922] | 1207 | ) |
---|
| 1208 | { |
---|
[06f8e558] | 1209 | rtems_id to_wake = RTEMS_ID_NONE; |
---|
[d007cc2] | 1210 | int exit_code = 0; |
---|
[798ff5a] | 1211 | |
---|
| 1212 | if ( wait ) |
---|
| 1213 | to_wake = rtems_task_self(); |
---|
| 1214 | |
---|
| 1215 | return rtems_shell_run( |
---|
| 1216 | task_name, /* task_name */ |
---|
| 1217 | task_stacksize, /* task_stacksize */ |
---|
| 1218 | task_priority, /* task_priority */ |
---|
| 1219 | devname, /* devname */ |
---|
| 1220 | forever, /* forever */ |
---|
| 1221 | wait, /* wait */ |
---|
| 1222 | "stdin", /* input */ |
---|
| 1223 | "stdout", /* output */ |
---|
[06f8e558] | 1224 | false, /* output_append */ |
---|
[798ff5a] | 1225 | to_wake, /* wake_on_end */ |
---|
[d007cc2] | 1226 | &exit_code, /* exit code of command */ |
---|
[06f8e558] | 1227 | false, /* echo */ |
---|
[8a775c27] | 1228 | login_check /* login check */ |
---|
[798ff5a] | 1229 | ); |
---|
[1ff9922] | 1230 | } |
---|
| 1231 | |
---|
[d007cc2] | 1232 | rtems_status_code rtems_shell_script ( |
---|
[e41eaa88] | 1233 | const char *task_name, |
---|
[06f8e558] | 1234 | size_t task_stacksize, |
---|
[1ff9922] | 1235 | rtems_task_priority task_priority, |
---|
| 1236 | const char* input, |
---|
| 1237 | const char* output, |
---|
[06f8e558] | 1238 | bool output_append, |
---|
| 1239 | bool wait, |
---|
| 1240 | bool echo |
---|
[1ff9922] | 1241 | ) |
---|
| 1242 | { |
---|
[d007cc2] | 1243 | rtems_id to_wake = RTEMS_ID_NONE; |
---|
| 1244 | int exit_code = 0; |
---|
[1ff9922] | 1245 | rtems_status_code sc; |
---|
| 1246 | |
---|
[d007cc2] | 1247 | shell_std_debug("script: in: %s out: %s\n", input, output); |
---|
| 1248 | |
---|
| 1249 | if ( wait ) |
---|
| 1250 | to_wake = rtems_task_self(); |
---|
[8a775c27] | 1251 | |
---|
[798ff5a] | 1252 | sc = rtems_shell_run( |
---|
| 1253 | task_name, /* task_name */ |
---|
| 1254 | task_stacksize, /* task_stacksize */ |
---|
| 1255 | task_priority, /* task_priority */ |
---|
| 1256 | NULL, /* devname */ |
---|
| 1257 | 0, /* forever */ |
---|
| 1258 | wait, /* wait */ |
---|
| 1259 | input, /* input */ |
---|
| 1260 | output, /* output */ |
---|
| 1261 | output_append, /* output_append */ |
---|
[d007cc2] | 1262 | to_wake, /* wake_on_end */ |
---|
| 1263 | &exit_code, /* exit_code */ |
---|
[06f8e558] | 1264 | echo, /* echo */ |
---|
[8a775c27] | 1265 | NULL /* login check */ |
---|
[798ff5a] | 1266 | ); |
---|
[d007cc2] | 1267 | |
---|
| 1268 | if (sc == RTEMS_SUCCESSFUL) |
---|
| 1269 | { |
---|
| 1270 | /* Place holder until RTEMS 5 is released then the interface for |
---|
| 1271 | * this call will change. */ |
---|
| 1272 | } |
---|
| 1273 | |
---|
| 1274 | shell_std_debug("script: end: %d\n", sc); |
---|
[1ff9922] | 1275 | |
---|
| 1276 | return sc; |
---|
| 1277 | } |
---|