File indexing completed on 2025-05-11 08:24:19
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifdef HAVE_CONFIG_H
0016 #include "config.h"
0017 #endif
0018
0019 #include <stdio.h>
0020 #include <time.h>
0021
0022 #include <rtems.h>
0023 #include <rtems/error.h>
0024 #include <rtems/libio.h>
0025 #include <rtems/libio_.h>
0026 #include <rtems/shell.h>
0027 #include <rtems/shellconfig.h>
0028 #include <rtems/console.h>
0029 #include "internal.h"
0030
0031 #include <termios.h>
0032 #include <string.h>
0033 #include <stdlib.h>
0034 #include <ctype.h>
0035 #include <sys/stat.h>
0036 #include <unistd.h>
0037 #include <errno.h>
0038 #include <pwd.h>
0039 #include <pthread.h>
0040 #include <assert.h>
0041
0042 #define SHELL_STD_DEBUG 0
0043
0044 #if SHELL_STD_DEBUG
0045 #include <rtems/bspIo.h>
0046 #define shell_std_debug(...) \
0047 do { printk("shell[%08x]: ", rtems_task_self()); printk(__VA_ARGS__); } while (0)
0048 #else
0049 #define shell_std_debug(...)
0050 #endif
0051
0052 #define SHELL_MAGIC rtems_build_name('S', 'E', 'N', 'V')
0053
0054 const rtems_shell_env_t rtems_global_shell_env = {
0055 .magic = SHELL_MAGIC,
0056 .managed = false,
0057 .devname = CONSOLE_DEVICE_NAME,
0058 .taskname = "RTSH",
0059 .exit_shell = false,
0060 .forever = true,
0061 .echo = false,
0062 .cwd = "/",
0063 .input = NULL,
0064 .output = NULL,
0065 .output_append = false,
0066 .parent_stdin = NULL,
0067 .parent_stdout = NULL,
0068 .parent_stderr = NULL,
0069 .wake_on_end = RTEMS_ID_NONE,
0070 .exit_code = NULL,
0071 .login_check = NULL,
0072 .uid = 0,
0073 .gid = 0
0074 };
0075
0076 typedef struct rtems_shell_env_key_handle
0077 {
0078 bool managed;
0079 rtems_shell_env_t* env;
0080 } rtems_shell_env_key_handle;
0081
0082 static pthread_once_t rtems_shell_once = PTHREAD_ONCE_INIT;
0083
0084 static pthread_key_t rtems_shell_current_env_key;
0085
0086
0087
0088
0089 static rtems_shell_env_t *rtems_shell_init_env(
0090 rtems_shell_env_t *shell_env_parent
0091 )
0092 {
0093 rtems_shell_env_t *shell_env;
0094
0095 shell_env = malloc(sizeof(rtems_shell_env_t));
0096 if ( !shell_env )
0097 return NULL;
0098
0099 if ( shell_env_parent == NULL ) {
0100 shell_env_parent = rtems_shell_get_current_env();
0101 }
0102 if ( shell_env_parent == NULL ) {
0103 *shell_env = rtems_global_shell_env;
0104 } else {
0105 *shell_env = *shell_env_parent;
0106 }
0107 shell_env->managed = true;
0108 shell_env->taskname = NULL;
0109
0110 return shell_env;
0111 }
0112
0113
0114
0115
0116 static void rtems_shell_env_free(
0117 void *ptr
0118 )
0119 {
0120 if ( ptr != NULL ) {
0121 rtems_shell_env_key_handle *handle = (rtems_shell_env_key_handle *) ptr;
0122 rtems_shell_env_t *shell_env = handle->env;
0123
0124 if ( handle->managed ) {
0125 if ( shell_env->input )
0126 free((void *)shell_env->input);
0127 if ( shell_env->output )
0128 free((void *)shell_env->output);
0129 free( shell_env );
0130 }
0131
0132 free( handle );
0133 }
0134 }
0135
0136 static void rtems_shell_create_file(const char *name, const char *content)
0137 {
0138 FILE *fp = fopen(name, "wx");
0139
0140 if (fp != NULL) {
0141 fputs(content, fp);
0142 fclose(fp);
0143 }
0144 }
0145
0146 static void rtems_shell_init_commands(void)
0147 {
0148 rtems_shell_cmd_t * const *c;
0149 rtems_shell_alias_t * const *a;
0150
0151 for ( c = rtems_shell_Initial_commands ; *c ; c++ ) {
0152 rtems_shell_add_cmd_struct( *c );
0153 }
0154
0155 for ( a = rtems_shell_Initial_aliases ; *a ; a++ ) {
0156 rtems_shell_alias_cmd( (*a)->name, (*a)->alias );
0157 }
0158 }
0159
0160 static void rtems_shell_init_once(void)
0161 {
0162 struct passwd pwd;
0163 struct passwd *pwd_res;
0164
0165 pthread_key_create(&rtems_shell_current_env_key, rtems_shell_env_free);
0166
0167
0168 getpwuid_r(0, &pwd, NULL, 0, &pwd_res);
0169
0170 rtems_shell_create_file("etc/issue",
0171 "\n"
0172 "Welcome to @V\\n"
0173 "Login into @S\\n");
0174
0175 rtems_shell_create_file("/etc/issue.net",
0176 "\n"
0177 "Welcome to %v\n"
0178 "running on %m\n");
0179
0180 rtems_shell_init_commands();
0181 rtems_shell_register_monitor_commands();
0182 }
0183
0184 void rtems_shell_init_environment(void)
0185 {
0186 assert(pthread_once(&rtems_shell_once, rtems_shell_init_once) == 0);
0187 }
0188
0189
0190
0191
0192 static bool rtems_shell_set_shell_env(
0193 rtems_shell_env_t* shell_env
0194 )
0195 {
0196
0197
0198
0199
0200 rtems_shell_env_key_handle *handle;
0201 int eno;
0202
0203 rtems_shell_init_environment();
0204
0205 handle = malloc(sizeof(rtems_shell_env_key_handle));
0206 if (handle == NULL) {
0207 rtems_error(0, "no memory for shell env key handle)");
0208 return false;
0209 }
0210
0211 handle->managed = shell_env->managed;
0212 handle->env = shell_env;
0213
0214 eno = pthread_setspecific(rtems_shell_current_env_key, handle);
0215 if (eno != 0) {
0216 rtems_error(0, "pthread_setspecific(shell_current_env_key): set");
0217 return false;
0218 }
0219
0220 return true;
0221 }
0222
0223
0224
0225
0226 static void rtems_shell_clear_shell_env(void)
0227 {
0228 int eno;
0229
0230
0231
0232
0233 rtems_shell_env_free(pthread_getspecific(rtems_shell_current_env_key));
0234
0235
0236
0237
0238 eno = pthread_setspecific(rtems_shell_current_env_key, NULL);
0239 if (eno != 0)
0240 rtems_error(0, "pthread_setspecific(shell_current_env_key): clear");
0241 }
0242
0243
0244
0245
0246 static void rtems_shell_clear_shell_std_handles(void)
0247 {
0248 stdin = NULL;
0249 stdout = NULL;
0250 stderr = NULL;
0251 }
0252
0253
0254
0255
0256 rtems_shell_env_t *rtems_shell_get_current_env(void)
0257 {
0258 rtems_shell_env_key_handle *handle;
0259 handle = (rtems_shell_env_key_handle*)
0260 pthread_getspecific(rtems_shell_current_env_key);
0261 return handle == NULL ? NULL : handle->env;
0262 }
0263
0264
0265
0266
0267
0268 void rtems_shell_dup_current_env(rtems_shell_env_t *copy)
0269 {
0270 rtems_shell_env_t *env = rtems_shell_get_current_env();
0271 if (env != NULL) {
0272 shell_std_debug("dup: existing parent\n");
0273 *copy = *env;
0274
0275
0276
0277
0278 copy->managed = false;
0279 } else {
0280 *copy = rtems_global_shell_env;
0281 copy->parent_stdout = stdout;
0282 copy->parent_stdin = stdin;
0283 copy->parent_stderr = stderr;
0284 shell_std_debug("dup: global: copy: %p out: %d (%p) in: %d (%p)\n",
0285 copy,
0286 fileno(copy->parent_stdout), copy->parent_stdout,
0287 fileno(copy->parent_stdin), copy->parent_stdin);
0288 }
0289 }
0290
0291
0292
0293
0294
0295
0296 static void rtems_shell_move_left(char *start, size_t offset)
0297 {
0298 memmove(start, start + offset, strlen(start + offset) + 1);
0299 }
0300
0301
0302
0303
0304 static int rtems_shell_line_editor(
0305 char *cmds[],
0306 int count,
0307 int size,
0308 const char *prompt,
0309 FILE *in,
0310 FILE *out
0311 )
0312 {
0313 unsigned int extended_key;
0314 int c;
0315 int col;
0316 int last_col;
0317 char line[size];
0318 char new_line[size];
0319 int up;
0320 int cmd = -1;
0321 int inserting = 1;
0322 int in_fileno = fileno(in);
0323
0324 col = last_col = 0;
0325
0326 tcdrain(in_fileno);
0327 if (out != NULL) {
0328 tcdrain(fileno(out));
0329 }
0330
0331 if (out != NULL && prompt != NULL)
0332 fprintf(out, "%s", prompt);
0333
0334 line[0] = 0;
0335 new_line[0] = 0;
0336
0337 for (;;) {
0338
0339 if (out != NULL)
0340 fflush(out);
0341
0342 extended_key = rtems_shell_getchar(in);
0343
0344 if (extended_key == EOF)
0345 return -2;
0346
0347 c = extended_key & RTEMS_SHELL_KEYS_NORMAL_MASK;
0348
0349
0350
0351
0352 extended_key &= ~RTEMS_SHELL_KEYS_NORMAL_MASK;
0353
0354 up = 0;
0355
0356 if (extended_key)
0357 {
0358 switch (c)
0359 {
0360 case RTEMS_SHELL_KEYS_END:
0361 if (out != NULL)
0362 fprintf(out, "%s", line + col);
0363 col = (int) strlen (line);
0364 break;
0365
0366 case RTEMS_SHELL_KEYS_HOME:
0367 if (out != NULL && prompt != NULL) {
0368 fprintf(out,"\r%s", prompt);
0369 }
0370 col = 0;
0371 break;
0372
0373 case RTEMS_SHELL_KEYS_LARROW:
0374 c = 2;
0375 extended_key = 0;
0376 break;
0377
0378 case RTEMS_SHELL_KEYS_RARROW:
0379 c = 6;
0380 extended_key = 0;
0381 break;
0382
0383 case RTEMS_SHELL_KEYS_UARROW:
0384 c = 16;
0385 extended_key = 0;
0386 break;
0387
0388 case RTEMS_SHELL_KEYS_DARROW:
0389 c = 14;
0390 extended_key = 0;
0391 break;
0392
0393 case RTEMS_SHELL_KEYS_DEL:
0394 if (line[col] != '\0')
0395 {
0396 int end;
0397 int bs;
0398 rtems_shell_move_left(line + col, 1);
0399 if (out != NULL) {
0400 fprintf(out,"\r%s%s ", prompt, line);
0401 end = (int) strlen (line);
0402 for (bs = 0; bs < ((end - col) + 1); bs++)
0403 fputc('\b', out);
0404 }
0405 }
0406 break;
0407
0408 case RTEMS_SHELL_KEYS_INS:
0409 inserting = inserting ? 0 : 1;
0410 break;
0411 }
0412 }
0413 if (!extended_key)
0414 {
0415 switch (c)
0416 {
0417 case 1:
0418 if (out != NULL && prompt != NULL) {
0419 fprintf(out,"\r%s", prompt);
0420 }
0421 col = 0;
0422 break;
0423
0424 case 2:
0425 if (col > 0)
0426 {
0427 col--;
0428 if (out != NULL)
0429 fputc('\b', out);
0430 }
0431 break;
0432
0433 case 4:
0434 if (strlen(line)) {
0435 if (col < strlen(line)) {
0436 rtems_shell_move_left(line + col, 1);
0437 if (out != NULL) {
0438 int bs;
0439 fprintf(out,"%s \b", line + col);
0440 for (bs = 0; bs < ((int) strlen (line) - col); bs++)
0441 fputc('\b', out);
0442 }
0443 }
0444 break;
0445 }
0446
0447
0448 case EOF:
0449 if (out != NULL)
0450 fputc('\n', out);
0451 return -2;
0452
0453 case 5:
0454 if (out != NULL)
0455 fprintf(out, "%s", line + col);
0456 col = (int) strlen (line);
0457 break;
0458
0459 case 6:
0460 if ((col < size) && (line[col] != '\0')) {
0461 if (out != NULL)
0462 fputc(line[col], out);
0463 col++;
0464 }
0465 break;
0466
0467 case 7:
0468 if (out != NULL) {
0469
0470
0471
0472
0473
0474 fprintf(out,"\r%s%*c", prompt, (int) strlen (line), ' ');
0475 fprintf(out,"\r%s\x7", prompt);
0476 }
0477 memset (line, '\0', strlen(line));
0478 col = 0;
0479 break;
0480
0481 case 11:
0482 if (line[col]) {
0483 if (out != NULL) {
0484 int end = strlen(line);
0485 int bs;
0486 fprintf(out,"%*c", end - col, ' ');
0487 for (bs = 0; bs < (end - col); bs++)
0488 fputc('\b', out);
0489 }
0490 line[col] = '\0';
0491 }
0492 break;
0493
0494 case '\f':
0495 if (out != NULL) {
0496 int end;
0497 int bs;
0498 fputc('\f',out);
0499 fprintf(out,"\r%s%s", prompt, line);
0500 end = (int) strlen (line);
0501 for (bs = 0; bs < (end - col); bs++)
0502 fputc('\b', out);
0503 }
0504 break;
0505
0506 case '\b':
0507 case '\x7f':
0508 if (col > 0)
0509 {
0510 int bs;
0511 col--;
0512 rtems_shell_move_left(line + col, 1);
0513 if (out != NULL) {
0514 fprintf(out,"\b%s \b", line + col);
0515 for (bs = 0; bs < ((int) strlen (line) - col); bs++)
0516 fputc('\b', out);
0517 }
0518 }
0519 break;
0520
0521 case '\n':
0522 case '\r':
0523 {
0524
0525
0526
0527 if (out != NULL)
0528 fprintf(out,"\n");
0529
0530
0531
0532
0533
0534 if (strlen(line) == 0) {
0535 cmd = -1;
0536 } else {
0537 if ((cmd < 0) || (strcmp(line, cmds[cmd]) != 0)) {
0538 if (count > 1)
0539 memmove(cmds[1], cmds[0], (count - 1) * size);
0540 memmove (cmds[0], line, size);
0541 cmd = 0;
0542 } else {
0543 if ((cmd > 1) && (strcmp(line, cmds[cmd]) == 0)) {
0544 memmove(cmds[1], cmds[0], cmd * size);
0545 memmove (cmds[0], line, size);
0546 cmd = 0;
0547 }
0548 }
0549 }
0550 }
0551 return cmd;
0552
0553 case 16:
0554 if ((cmd >= (count - 1)) || (strlen(cmds[cmd + 1]) == 0)) {
0555 if (out != NULL)
0556 fputc('\x7', out);
0557 break;
0558 }
0559
0560 up = 1;
0561
0562
0563 case 14:
0564 {
0565 int last_cmd = cmd;
0566 int clen = strlen (line);
0567
0568 if (prompt)
0569 clen += strlen(prompt);
0570
0571 if (up) {
0572 cmd++;
0573 } else {
0574 if (cmd < 0) {
0575 if (out != NULL)
0576 fprintf(out, "\x7");
0577 break;
0578 }
0579 else
0580 cmd--;
0581 }
0582
0583 if ((last_cmd < 0) || (strcmp(cmds[last_cmd], line) != 0))
0584 memcpy (new_line, line, size);
0585
0586 if (cmd < 0)
0587 memcpy (line, new_line, size);
0588 else
0589 memcpy (line, cmds[cmd], size);
0590
0591 col = strlen (line);
0592
0593 if (out != NULL) {
0594 fprintf(out,"\r%s%*c", prompt, clen, ' ');
0595 fprintf(out,"\r%s%s", prompt, line);
0596 }
0597 }
0598 break;
0599
0600 case 20:
0601 if (col > 0)
0602 {
0603 char tmp;
0604 if (col == strlen(line)) {
0605 col--;
0606 if (out != NULL)
0607 fprintf(out,"\b");
0608 }
0609 tmp = line[col];
0610 line[col] = line[col - 1];
0611 line[col - 1] = tmp;
0612 if (out != NULL)
0613 fprintf(out,"\b%c%c", line[col - 1], line[col]);
0614 col++;
0615 } else {
0616 if (out != NULL)
0617 fputc('\x7', out);
0618 }
0619 break;
0620
0621 case 21:
0622 if (col > 0)
0623 {
0624
0625
0626 int clen = (int) strlen (line);
0627 int bs;
0628
0629 rtems_shell_move_left(line, col);
0630 if (out != NULL) {
0631 fprintf(out,"\r%s%*c", prompt, clen, ' ');
0632 fprintf(out,"\r%s%s", prompt, line);
0633
0634 for (bs = 0; bs < strlen(line); bs++) {
0635 fputc('\b', out);
0636 }
0637 }
0638 col = 0;
0639 }
0640 break;
0641
0642 default:
0643 if ((col < (size - 1)) && (c >= ' ') && (c <= '~')) {
0644 int end = strlen (line);
0645 if (inserting && (col < end) && (end < size)) {
0646 int ch, bs;
0647 for (ch = end + 1; ch > col; ch--)
0648 line[ch] = line[ch - 1];
0649 if (out != NULL) {
0650 fprintf(out, "%s", line + col);
0651 for (bs = 0; bs < (end - col + 1); bs++)
0652 fputc('\b', out);
0653 }
0654 }
0655 line[col++] = c;
0656 if (col > end)
0657 line[col] = '\0';
0658 if (out != NULL)
0659 fputc(c, out);
0660 }
0661 break;
0662 }
0663 }
0664 }
0665 return -2;
0666 }
0667
0668 static bool rtems_shell_login(rtems_shell_env_t *env, FILE * in,FILE * out)
0669 {
0670 FILE *fd;
0671 int c;
0672 time_t t;
0673
0674 if (out) {
0675 if ((env->devname[5]!='p')||
0676 (env->devname[6]!='t')||
0677 (env->devname[7]!='y')) {
0678 fd = fopen("/etc/issue","r");
0679 if (fd) {
0680 while ((c = fgetc(fd)) != EOF) {
0681 if (c=='@') {
0682 switch (c = fgetc(fd)) {
0683 case 'L':
0684 fprintf(out,"%s", env->devname);
0685 break;
0686 case 'B':
0687 fprintf(out,"0");
0688 break;
0689 case 'T':
0690 case 'D':
0691 time(&t);
0692 fprintf(out,"%s",ctime(&t));
0693 break;
0694 case 'S':
0695 fprintf(out,"RTEMS");
0696 break;
0697 case 'V':
0698 fprintf(
0699 out,
0700 "%s\n%s",
0701 rtems_get_version_string(),
0702 rtems_get_copyright_notice()
0703 );
0704 break;
0705 case '@':
0706 fprintf(out,"@");
0707 break;
0708 default :
0709 fprintf(out,"@%c",c);
0710 break;
0711 }
0712 } else if (c=='\\') {
0713 switch(c=fgetc(fd)) {
0714 case '\\': fprintf(out,"\\"); break;
0715 case 'b': fprintf(out,"\b"); break;
0716 case 'f': fprintf(out,"\f"); break;
0717 case 'n': fprintf(out,"\n"); break;
0718 case 'r': fprintf(out,"\r"); break;
0719 case 's': fprintf(out," "); break;
0720 case 't': fprintf(out,"\t"); break;
0721 case '@': fprintf(out,"@"); break;
0722 }
0723 } else {
0724 fputc(c,out);
0725 }
0726 }
0727 fclose(fd);
0728 }
0729 } else {
0730 fd = fopen("/etc/issue.net","r");
0731 if (fd) {
0732 while ((c=fgetc(fd))!=EOF) {
0733 if (c=='%') {
0734 switch(c=fgetc(fd)) {
0735 case 't':
0736 fprintf(out,"%s", env->devname);
0737 break;
0738 case 'h':
0739 fprintf(out,"0");
0740 break;
0741 case 'D':
0742 fprintf(out," ");
0743 break;
0744 case 'd':
0745 time(&t);
0746 fprintf(out,"%s",ctime(&t));
0747 break;
0748 case 's':
0749 fprintf(out,"RTEMS");
0750 break;
0751 case 'm':
0752 fprintf(out,"(" CPU_NAME "/" CPU_MODEL_NAME ")");
0753 break;
0754 case 'r':
0755 fprintf(out,rtems_get_version_string());
0756 break;
0757 case 'v':
0758 fprintf(
0759 out,
0760 "%s\n%s",
0761 rtems_get_version_string(),
0762 rtems_get_copyright_notice()
0763 );
0764 break;
0765 case '%':fprintf(out,"%%");
0766 break;
0767 default:
0768 fprintf(out,"%%%c",c);
0769 break;
0770 }
0771 } else {
0772 fputc(c,out);
0773 }
0774 }
0775 fclose(fd);
0776 }
0777 }
0778 }
0779
0780 return rtems_shell_login_prompt(in, out, env->devname, env->login_check);
0781 }
0782
0783 #if defined(SHELL_DEBUG)
0784 void rtems_shell_print_env(
0785 rtems_shell_env_t * shell_env
0786 )
0787 {
0788 if ( !shell_env ) {
0789 printk( "shell_env is NULL\n" );
0790
0791 return;
0792 }
0793 printk( "shell_env=%p\n"
0794 "shell_env->magic=0x%08x\t"
0795 "shell_env->devname=%s\n"
0796 "shell_env->taskname=%s\t"
0797 "shell_env->exit_shell=%d\t"
0798 "shell_env->forever=%d\n",
0799 shell_env->magic,
0800 shell_env->devname,
0801 ((shell_env->taskname) ? shell_env->taskname : "NOT SET"),
0802 shell_env->exit_shell,
0803 shell_env->forever
0804 );
0805 }
0806 #endif
0807
0808 static int get_ticks_from_ms(const int timeout_ms)
0809 {
0810 int ticks = timeout_ms * 1000;
0811
0812 ticks /= rtems_configuration_get_microseconds_per_tick();
0813
0814 return MAX(1, ticks);
0815 }
0816
0817
0818
0819
0820 static bool rtems_shell_term_wait_for(const int fd,
0821 const char* str,
0822 const int timeout_ms)
0823 {
0824 const int timeout_ticks = get_ticks_from_ms(timeout_ms);
0825 int tick_count = timeout_ticks;
0826 int i = 0;
0827 while (tick_count-- > 0 && str[i] != '\0') {
0828 char ch[2];
0829 if (read(fd, &ch[0], 1) == 1) {
0830 fflush(stdout);
0831 if (ch[0] != str[i++]) {
0832 return false;
0833 }
0834 tick_count = timeout_ticks;
0835 } else {
0836 rtems_task_wake_after(1);
0837 }
0838 }
0839 if (tick_count == 0) {
0840 return false;
0841 }
0842 return true;
0843 }
0844
0845
0846
0847
0848 static int rtems_shell_term_buffer_until(const int fd,
0849 char* buf,
0850 const int size,
0851 const char* end,
0852 const int timeout_ms)
0853 {
0854 const int timeout_ticks = get_ticks_from_ms(timeout_ms);
0855 int tick_count = timeout_ticks;
0856 int i = 0;
0857 int e = 0;
0858 memset(&buf[0], 0, size);
0859 while (tick_count-- > 0 && i < size && end[e] != '\0') {
0860 char ch[2];
0861 if (read(fd, &ch[0], 1) == 1) {
0862 fflush(stdout);
0863 buf[i++] = ch[0];
0864 if (ch[0] == end[e]) {
0865 e++;
0866 } else {
0867 e = 0;
0868 }
0869 tick_count = timeout_ticks;
0870 } else {
0871 rtems_task_wake_after(1);
0872 }
0873 }
0874 if (tick_count == 0 || end[e] != '\0') {
0875 return -1;
0876 }
0877 i -= e;
0878 if (i < size) {
0879 buf[i] = '\0';
0880 }
0881 return i;
0882 }
0883
0884
0885
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896 static bool rtems_shell_term_row_column_swapped(const int fd, const int timeout) {
0897 char buf[64];
0898 memset(&buf[0], 0, sizeof(buf));
0899
0900
0901
0902
0903 fputs("\033[>0q", stdout);
0904 fflush(stdout);
0905 if (rtems_shell_term_wait_for(fd, "\033P>|", timeout)) {
0906 int len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), "\033\\", timeout);
0907 if (len > 0) {
0908 if (memcmp(buf, "tmux ", 5) == 0) {
0909 static const char* bad_versions[] = {
0910 "3.2", "3.2a", "3.3", "3.3a"
0911 };
0912 size_t i;
0913 for (i = 0; i < RTEMS_ARRAY_SIZE(bad_versions); ++i) {
0914 if (strcmp(bad_versions[i], buf + 5) == 0) {
0915 return true;
0916 }
0917 }
0918 }
0919 }
0920 }
0921 return false;
0922 }
0923
0924
0925
0926
0927
0928
0929 static void rtems_shell_winsize( void )
0930 {
0931 const int fd = fileno(stdin);
0932 struct winsize ws;
0933 const int timeout = 150;
0934 char buf[64];
0935 bool ok = false;
0936 int lines = 0;
0937 int cols = 0;
0938 int r;
0939 const char *detect = getenv("TERM_SIZE_DETECT");
0940
0941 if (detect) {
0942
0943 if (strcmp(detect, "false") == 0) {
0944 return;
0945 }
0946 if (strcmp(detect, "False") == 0) {
0947 return;
0948 }
0949 if (strcmp(detect, "0") == 0) {
0950 return;
0951 }
0952 }
0953
0954 r = ioctl(fd, TIOCGWINSZ, &ws);
0955 if (r == 0) {
0956 ok = true;
0957 lines = ws.ws_row;
0958 cols = ws.ws_col;
0959 } else if (isatty(fd)) {
0960 struct termios cterm;
0961 if (tcgetattr(fd, &cterm) == 0) {
0962 struct termios term = cterm;
0963 term.c_cc[VMIN] = 0;
0964 term.c_cc[VTIME] = 0;
0965 if (tcsetattr (fd, TCSADRAIN, &term) == 0) {
0966 memset(&buf[0], 0, sizeof(buf));
0967
0968
0969
0970
0971
0972 fputs("\033[18t", stdout);
0973 fflush(stdout);
0974 if (rtems_shell_term_wait_for(fd, "\033[8;", timeout)) {
0975 int len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), ";", timeout);
0976 if (len > 0) {
0977 int i;
0978 lines = 0;
0979 i = 0;
0980 while (i < len) {
0981 lines *= 10;
0982 lines += buf[i++] - '0';
0983 }
0984 len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), "t", timeout);
0985 if (len > 0) {
0986 cols = 0;
0987 i = 0;
0988 while (i < len) {
0989 cols *= 10;
0990 cols += buf[i++] - '0';
0991 }
0992 ok = true;
0993 }
0994 }
0995 }
0996 }
0997 if (rtems_shell_term_row_column_swapped(fd, timeout)) {
0998 int tmp = lines;
0999 lines = cols;
1000 cols = tmp;
1001 }
1002 tcsetattr (fd, TCSADRAIN, &cterm);
1003 }
1004 }
1005 if (ok) {
1006 snprintf(buf, sizeof(buf) - 1, "%d", lines);
1007 setenv("LINES", buf, 1);
1008 snprintf(buf, sizeof(buf) - 1, "%d", cols);
1009 setenv("COLUMNS", buf, 1);
1010 } else {
1011 setenv("TERM_SIZE_DETECT", "0", 1);
1012 }
1013 }
1014
1015 static rtems_task rtems_shell_task(rtems_task_argument task_argument)
1016 {
1017 rtems_shell_env_t *shell_env = (rtems_shell_env_t*) task_argument;
1018 rtems_id wake_on_end = shell_env->wake_on_end;
1019 rtems_shell_main_loop( shell_env );
1020 rtems_shell_clear_shell_std_handles();
1021 if (wake_on_end != RTEMS_INVALID_ID)
1022 rtems_event_send (wake_on_end, RTEMS_EVENT_1);
1023 rtems_task_exit();
1024 }
1025
1026 static bool rtems_shell_init_user_env(void)
1027 {
1028 rtems_status_code sc;
1029
1030
1031 sc = rtems_libio_set_private_env();
1032 if (sc != RTEMS_SUCCESSFUL) {
1033 rtems_error(sc, "rtems_libio_set_private_env():");
1034 return false;
1035 }
1036
1037
1038 seteuid(0);
1039 setegid(0);
1040
1041 return chroot("/") == 0;
1042 }
1043
1044 #define RTEMS_SHELL_MAXIMUM_ARGUMENTS (128)
1045 #define RTEMS_SHELL_CMD_SIZE (128)
1046 #define RTEMS_SHELL_CMD_COUNT (32)
1047 #define RTEMS_SHELL_PROMPT_SIZE (128)
1048
1049 static bool shell_main_loop(
1050 rtems_shell_env_t *shell_env,
1051 bool interactive,
1052 FILE *line_editor_output
1053 )
1054 {
1055 bool result = false;
1056 int line = 0;
1057 int cmd_count;
1058 char *cmds[RTEMS_SHELL_CMD_COUNT];
1059 char *cmd_argv;
1060 char *prompt;
1061
1062 if (interactive) {
1063 prompt = malloc(RTEMS_SHELL_PROMPT_SIZE);
1064 if (prompt == NULL) {
1065 fprintf(stderr, "shell: cannot allocate prompt memory\n");
1066 return false;
1067 }
1068
1069 cmd_count = RTEMS_SHELL_CMD_COUNT;
1070 } else {
1071 prompt = NULL;
1072 cmd_count = 1;
1073 }
1074
1075
1076
1077
1078 cmd_argv = malloc (RTEMS_SHELL_CMD_SIZE);
1079 if (!cmd_argv) {
1080 fprintf(stderr, "no memory for command line buffers\n" );
1081 }
1082
1083 cmds[0] = calloc (cmd_count, RTEMS_SHELL_CMD_SIZE);
1084 if (!cmds[0]) {
1085 fprintf(stderr, "no memory for command line buffers\n" );
1086 }
1087
1088 if (cmd_argv && cmds[0]) {
1089 size_t cmd;
1090
1091 memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE);
1092
1093 for (cmd = 1; cmd < cmd_count; cmd++) {
1094 cmds[cmd] = cmds[cmd - 1] + RTEMS_SHELL_CMD_SIZE;
1095 }
1096
1097 do {
1098 result = rtems_shell_init_user_env();
1099
1100 if (result) {
1101
1102
1103
1104
1105
1106 if (shell_env->login_check != NULL) {
1107 result = rtems_shell_login(shell_env, stdin, stdout);
1108 } else {
1109 setuid(shell_env->uid);
1110 setgid(shell_env->gid);
1111 seteuid(shell_env->uid);
1112 setegid(shell_env->gid);
1113 rtems_current_user_env_getgroups();
1114
1115 result = true;
1116 }
1117 }
1118
1119 if (result) {
1120 memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE);
1121
1122 if (interactive) {
1123 rtems_shell_cat_file(stdout,"/etc/motd");
1124 fprintf(stdout, "\n"
1125 "RTEMS Shell on %s. Use 'help' to list commands.\n",
1126 shell_env->devname);
1127 chdir("/");
1128 } else {
1129 chdir(shell_env->cwd);
1130 }
1131
1132 shell_env->exit_shell = false;
1133
1134 for (;;) {
1135 const char *c;
1136 int argc;
1137 char *argv[RTEMS_SHELL_MAXIMUM_ARGUMENTS];
1138
1139
1140 if (prompt) {
1141 rtems_shell_get_prompt(shell_env, prompt,
1142 RTEMS_SHELL_PROMPT_SIZE);
1143 }
1144
1145
1146 cmd = rtems_shell_line_editor(cmds, cmd_count,
1147 RTEMS_SHELL_CMD_SIZE, prompt,
1148 stdin, line_editor_output);
1149
1150 if (cmd == -1)
1151 continue;
1152
1153 if (cmd == -2) {
1154 result = false;
1155 break;
1156 }
1157
1158 line++;
1159
1160 if (shell_env->echo)
1161 fprintf(stdout, "%d: %s\n", line, cmds[cmd]);
1162
1163
1164 c = cmds[cmd];
1165 while (*c) {
1166 if (!isblank((unsigned char)*c))
1167 break;
1168 c++;
1169 }
1170
1171 if (*c == '\0')
1172 continue;
1173
1174 if (*c == '#') {
1175 cmds[cmd][0] = 0;
1176 continue;
1177 }
1178
1179 if (!strcmp(cmds[cmd],"bye") || !strcmp(cmds[cmd],"exit")) {
1180 fprintf(stdout, "Shell exiting\n" );
1181 break;
1182 }
1183
1184
1185
1186
1187
1188
1189
1190
1191 memcpy (cmd_argv, cmds[cmd], RTEMS_SHELL_CMD_SIZE);
1192 if (!rtems_shell_make_args(cmd_argv, &argc, argv,
1193 RTEMS_SHELL_MAXIMUM_ARGUMENTS)) {
1194 int exit_code;
1195 rtems_shell_winsize();
1196 exit_code = rtems_shell_execute_cmd(argv[0], argc, argv);
1197 if (shell_env->exit_code != NULL)
1198 *shell_env->exit_code = exit_code;
1199 if (exit_code != 0 && shell_env->exit_on_error)
1200 shell_env->exit_shell = true;
1201 }
1202
1203
1204 if (shell_env->exit_shell)
1205 break;
1206 }
1207
1208 fflush( stdout );
1209 fflush( stderr );
1210 }
1211 shell_std_debug("end: %d %d\n", result, shell_env->forever);
1212 } while (result && shell_env->forever);
1213 }
1214
1215 free(cmds[0]);
1216 free(cmd_argv);
1217 free(prompt);
1218
1219 return result;
1220 }
1221
1222 bool rtems_shell_run_main_loop(
1223 rtems_shell_env_t *shell_env,
1224 bool interactive,
1225 FILE *line_editor_output
1226 )
1227 {
1228 bool result;
1229
1230 if (shell_env->magic != SHELL_MAGIC) {
1231 return false;
1232 }
1233
1234 if (!rtems_shell_init_user_env()) {
1235 return false;
1236 }
1237
1238 if (!rtems_shell_set_shell_env(shell_env)) {
1239 return false;
1240 }
1241
1242 result = shell_main_loop(shell_env, interactive, line_editor_output);
1243 rtems_shell_clear_shell_env();
1244 return result;
1245 }
1246
1247 bool rtems_shell_main_loop(
1248 rtems_shell_env_t *shell_env
1249 )
1250 {
1251 struct termios term;
1252 struct termios previous_term;
1253 bool result;
1254 bool interactive = true;
1255 bool have_previous_term = false;
1256 FILE *stdinToClose = NULL;
1257 FILE *stdoutToClose = NULL;
1258 FILE *line_editor_output;
1259
1260 if (shell_env->magic != SHELL_MAGIC) {
1261 rtems_error(0, "invalid shell environment passed to the main loop)");
1262 return false;
1263 }
1264
1265 if (!rtems_shell_set_shell_env(shell_env))
1266 return false;
1267
1268 if (!rtems_shell_init_user_env()) {
1269 rtems_error(0, "rtems_shell_init_user_env");
1270 rtems_shell_clear_shell_env();
1271 return false;
1272 }
1273
1274 shell_std_debug("env: %p\n", shell_env);
1275
1276 if (shell_env->output == NULL || strcmp(shell_env->output, "stdout") == 0) {
1277 if (shell_env->parent_stdout != NULL)
1278 stdout = shell_env->parent_stdout;
1279 }
1280 else if (strcmp(shell_env->output, "stderr") == 0) {
1281 if (shell_env->parent_stderr != NULL)
1282 stdout = shell_env->parent_stderr;
1283 else
1284 stdout = stderr;
1285 } else if (strcmp(shell_env->output, "/dev/null") == 0) {
1286 if (stdout == NULL) {
1287 fprintf(stderr, "shell: stdout is NULLs\n");
1288 rtems_shell_clear_shell_env();
1289 return false;
1290 }
1291 fclose (stdout);
1292 } else {
1293 FILE *output = fopen(shell_env->output,
1294 shell_env->output_append ? "a" : "w");
1295 if (output == NULL) {
1296 fprintf(stderr, "shell: open output %s failed: %s\n",
1297 shell_env->output, strerror(errno));
1298 rtems_shell_clear_shell_env();
1299 return false;
1300 }
1301 stdout = output;
1302 stdoutToClose = output;
1303 }
1304
1305 if (shell_env->input == NULL || strcmp(shell_env->input, "stdin") == 0) {
1306 if (shell_env->parent_stdin != NULL)
1307 stdin = shell_env->parent_stdin;
1308 } else {
1309 FILE *input = fopen(shell_env->input, "r");
1310 if (input == NULL) {
1311 fprintf(stderr, "shell: open input %s failed: %s\n",
1312 shell_env->input, strerror(errno));
1313 if (stdoutToClose != NULL)
1314 fclose(stdoutToClose);
1315 rtems_shell_clear_shell_env();
1316 return false;
1317 }
1318 stdin = input;
1319 stdinToClose = input;
1320 shell_env->forever = false;
1321 interactive = false;
1322 }
1323
1324 if (interactive) {
1325 if (stdin == NULL) {
1326 fprintf(stderr, "shell: stdin is NULLs\n");
1327 if (stdoutToClose != NULL)
1328 fclose(stdoutToClose);
1329 rtems_shell_clear_shell_env();
1330 return false;
1331 }
1332
1333 have_previous_term = (tcgetattr(fileno(stdin), &previous_term) == 0);
1334 if (have_previous_term) {
1335 term = previous_term;
1336 term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
1337 term.c_oflag &= ~OPOST;
1338 term.c_oflag |= (OPOST|ONLCR);
1339 term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
1340 term.c_cflag |= CLOCAL | CREAD;
1341 term.c_cc[VMIN] = 1;
1342 term.c_cc[VTIME] = 0;
1343 if (tcsetattr (fileno(stdin), TCSADRAIN, &term) < 0) {
1344 fprintf(stderr,
1345 "shell: cannot set terminal attributes(%s)\n",shell_env->devname);
1346 }
1347 }
1348 }
1349
1350 shell_std_debug("child out: %d (%p)\n", fileno(stdout), stdout);
1351 shell_std_debug("child in: %d (%p)\n", fileno(stdin), stdin);
1352
1353
1354 if (interactive)
1355 setvbuf(stdin, NULL, _IONBF, 0);
1356 setvbuf(stdout, NULL, _IONBF, 0);
1357
1358 if (isatty(fileno(stdin))) {
1359 line_editor_output = stdout;
1360 } else {
1361 line_editor_output = NULL;
1362 }
1363
1364 result = shell_main_loop(shell_env, interactive, line_editor_output);
1365 shell_std_debug("child in-to-close: %p\n", stdinToClose);
1366 shell_std_debug("child out-to-close: %p\n", stdoutToClose);
1367
1368 if (stdinToClose) {
1369 fclose( stdinToClose );
1370 } else if (have_previous_term) {
1371 if (tcsetattr(fileno(stdin), TCSADRAIN, &previous_term) < 0) {
1372 fprintf(
1373 stderr,
1374 "shell: cannot reset terminal attributes (%s)\n",
1375 shell_env->devname
1376 );
1377 }
1378 }
1379 if ( stdoutToClose )
1380 fclose( stdoutToClose );
1381 rtems_shell_clear_shell_env();
1382 return result;
1383 }
1384
1385
1386 static rtems_status_code rtems_shell_run (
1387 const char *task_name,
1388 size_t task_stacksize,
1389 rtems_task_priority task_priority,
1390 const char *devname,
1391 bool forever,
1392 bool wait,
1393 const char *input,
1394 const char *output,
1395 bool output_append,
1396 rtems_id wake_on_end,
1397 bool echo,
1398 rtems_shell_login_check_t login_check
1399 )
1400 {
1401 rtems_id task_id;
1402 rtems_status_code sc;
1403 rtems_shell_env_t *shell_env;
1404 rtems_name name;
1405
1406 rtems_shell_init_environment();
1407
1408 if ( task_name && strlen(task_name) >= 4)
1409 name = rtems_build_name(
1410 task_name[0], task_name[1], task_name[2], task_name[3]);
1411 else
1412 name = SHELL_MAGIC;
1413
1414 sc = rtems_task_create(
1415 name,
1416 task_priority,
1417 task_stacksize,
1418 RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR,
1419 RTEMS_LOCAL | RTEMS_FLOATING_POINT,
1420 &task_id
1421 );
1422 if (sc != RTEMS_SUCCESSFUL) {
1423 rtems_error(sc,"creating task %s in shell_init()",task_name);
1424 return sc;
1425 }
1426
1427 shell_env = rtems_shell_init_env( NULL );
1428 if ( !shell_env ) {
1429 rtems_error(RTEMS_NO_MEMORY,
1430 "allocating shell_env %s in shell_init()",task_name);
1431 return RTEMS_NO_MEMORY;
1432 }
1433
1434 shell_std_debug("run: env: %p\n", shell_env);
1435
1436 shell_env->devname = devname;
1437 shell_env->taskname = task_name;
1438
1439 shell_env->exit_shell = false;
1440 shell_env->forever = forever;
1441 shell_env->echo = echo;
1442 shell_env->input = input == NULL ? NULL : strdup (input);
1443 shell_env->output = output == NULL ? NULL : strdup (output);
1444 shell_env->output_append = output_append;
1445 shell_env->parent_stdin = stdin;
1446 shell_env->parent_stdout = stdout;
1447 shell_env->parent_stderr = stderr;
1448 shell_env->wake_on_end = wake_on_end;
1449 shell_env->login_check = login_check;
1450 shell_env->uid = getuid();
1451 shell_env->gid = getgid();
1452
1453 getcwd(shell_env->cwd, sizeof(shell_env->cwd));
1454
1455 shell_std_debug("run out: %d (%p)\n",
1456 fileno(shell_env->parent_stdout), shell_env->parent_stdout);
1457 shell_std_debug("run in: %d (%p)\n",
1458 fileno(shell_env->parent_stdin), shell_env->parent_stdin);
1459
1460 sc = rtems_task_start(task_id, rtems_shell_task,
1461 (rtems_task_argument) shell_env);
1462 if (sc != RTEMS_SUCCESSFUL) {
1463 rtems_error(sc,"starting task %s in shell_init()",task_name);
1464 free( (void*) shell_env->input );
1465 free( (void*) shell_env->output );
1466 free( shell_env );
1467 return sc;
1468 }
1469
1470 if (wait) {
1471 rtems_event_set out;
1472 sc = rtems_event_receive (RTEMS_EVENT_1, RTEMS_WAIT, 0, &out);
1473 }
1474
1475 shell_std_debug("run: end: sc:%d\n", sc);
1476
1477 return sc;
1478 }
1479
1480 rtems_status_code rtems_shell_init(
1481 const char *task_name,
1482 size_t task_stacksize,
1483 rtems_task_priority task_priority,
1484 const char *devname,
1485 bool forever,
1486 bool wait,
1487 rtems_shell_login_check_t login_check
1488 )
1489 {
1490 rtems_id to_wake = RTEMS_ID_NONE;
1491
1492 if ( wait )
1493 to_wake = rtems_task_self();
1494
1495 return rtems_shell_run(
1496 task_name,
1497 task_stacksize,
1498 task_priority,
1499 devname,
1500 forever,
1501 wait,
1502 "stdin",
1503 "stdout",
1504 false,
1505 to_wake,
1506 false,
1507 login_check
1508 );
1509 }
1510
1511 rtems_status_code rtems_shell_script (
1512 const char *task_name,
1513 size_t task_stacksize,
1514 rtems_task_priority task_priority,
1515 const char* input,
1516 const char* output,
1517 bool output_append,
1518 bool wait,
1519 bool echo
1520 )
1521 {
1522 rtems_id to_wake = RTEMS_ID_NONE;
1523 rtems_status_code sc;
1524
1525 shell_std_debug("script: in: %s out: %s\n", input, output);
1526
1527 if ( wait )
1528 to_wake = rtems_task_self();
1529
1530 sc = rtems_shell_run(
1531 task_name,
1532 task_stacksize,
1533 task_priority,
1534 NULL,
1535 0,
1536 wait,
1537 input,
1538 output,
1539 output_append,
1540 to_wake,
1541 echo,
1542 NULL
1543 );
1544
1545 if (sc == RTEMS_SUCCESSFUL)
1546 {
1547
1548
1549 }
1550
1551 shell_std_debug("script: end: %d\n", sc);
1552
1553 return sc;
1554 }