Changeset 4d906d6a in rtems
- Timestamp:
- 02/18/20 00:34:46 (4 years ago)
- Branches:
- 4.11
- Children:
- 55d9d8c
- Parents:
- fe09d8d
- git-author:
- Chris Johns <chrisj@…> (02/18/20 00:34:46)
- git-committer:
- Chris Johns <chrisj@…> (02/19/20 08:05:54)
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
cpukit/libmisc/shell/shell.c
rfe09d8d r4d906d6a 41 41 #include <assert.h> 42 42 43 #define SHELL_STD_DEBUG 0 44 45 #if SHELL_STD_DEBUG 46 static FILE* default_stdout; 47 #define shell_std_debug(...) fprintf(default_stdout, __VA_ARGS__) 48 #else 49 #define shell_std_debug(...) 50 #endif 51 43 52 const rtems_shell_env_t rtems_global_shell_env = { 44 53 .magic = rtems_build_name('S', 'E', 'N', 'V'), 54 .managed = false, 45 55 .devname = CONSOLE_DEVICE_NAME, 46 56 .taskname = "SHGL", 47 57 .exit_shell = false, 48 58 .forever = true, 49 .errorlevel = -1,50 59 .echo = false, 51 60 .cwd = "/", … … 53 62 .output = NULL, 54 63 .output_append = false, 64 .parent_stdin = NULL, 65 .parent_stdout = NULL, 66 .parent_stderr = NULL, 55 67 .wake_on_end = RTEMS_ID_NONE, 56 .login_check = NULL 68 .exit_code = NULL, 69 .login_check = NULL, 70 .uid = 0, 71 .gid = 0 57 72 }; 73 74 typedef struct rtems_shell_env_key_handle 75 { 76 bool managed; 77 rtems_shell_env_t* env; 78 } rtems_shell_env_key_handle; 58 79 59 80 static pthread_once_t rtems_shell_once = PTHREAD_ONCE_INIT; … … 65 86 */ 66 87 static rtems_shell_env_t *rtems_shell_init_env( 67 rtems_shell_env_t *shell_env_p 88 rtems_shell_env_t *shell_env_parent 68 89 ) 69 90 { … … 73 94 if ( !shell_env ) 74 95 return NULL; 75 if ( !shell_env_p ) { 96 97 if ( shell_env_parent == NULL ) { 98 shell_env_parent = rtems_shell_get_current_env(); 99 } 100 if ( shell_env_parent == NULL ) { 76 101 *shell_env = rtems_global_shell_env; 77 102 } else { 78 *shell_env = *shell_env_p; 79 } 103 *shell_env = *shell_env_parent; 104 } 105 shell_env->managed = true; 80 106 shell_env->taskname = NULL; 81 107 … … 90 116 ) 91 117 { 92 rtems_shell_env_t *shell_env; 93 shell_env = (rtems_shell_env_t *) ptr; 94 95 if ( !ptr ) 96 return; 97 98 if ( shell_env->input ) 99 free((void *)shell_env->input); 100 if ( shell_env->output ) 101 free((void *)shell_env->output); 102 free( ptr ); 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( ptr ); 128 } 129 130 free( handle ); 131 } 103 132 } 104 133 … … 131 160 struct passwd pwd; 132 161 struct passwd *pwd_res; 162 163 #if SHELL_STD_DEBUG 164 default_stdout = stdout; 165 #endif 133 166 134 167 pthread_key_create(&rtems_shell_current_env_key, rtems_shell_env_free); … … 157 190 158 191 /* 192 * Create a current shell key. 193 */ 194 static bool rtems_shell_set_shell_env( 195 rtems_shell_env_t* shell_env 196 ) 197 { 198 /* 199 * The shell environment can be managed or it can be provided by a 200 * user. We need to create a handle to hold the env pointer. 201 */ 202 rtems_shell_env_key_handle *handle; 203 int eno; 204 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)"); 217 return false; 218 } 219 220 return true; 221 } 222 223 /* 159 224 * Return the current shell environment 160 225 */ 161 226 rtems_shell_env_t *rtems_shell_get_current_env(void) 162 227 { 163 return (rtems_shell_env_t *) pthread_getspecific(rtems_shell_current_env_key); 228 rtems_shell_env_key_handle *handle; 229 handle = (rtems_shell_env_key_handle*) 230 pthread_getspecific(rtems_shell_current_env_key); 231 return handle->env; 164 232 } 165 233 … … 171 239 { 172 240 rtems_shell_env_t *env = rtems_shell_get_current_env(); 173 if (env ) {241 if (env != NULL) { 174 242 *copy = *env; 175 243 } 176 244 else { 177 memset(copy, 0, sizeof(rtems_shell_env_t)); 178 copy->magic = rtems_build_name('S', 'E', 'N', 'V'); 179 copy->devname = CONSOLE_DEVICE_NAME; 180 copy->taskname = "RTSH"; 181 } 245 *copy = rtems_global_shell_env; 246 copy->magic = rtems_build_name('S', 'E', 'N', 'V'); 247 copy->devname = CONSOLE_DEVICE_NAME; 248 copy->taskname = "RTSH"; 249 copy->parent_stdout = stdout; 250 copy->parent_stdin = stdin; 251 copy->parent_stderr = stderr; 252 } 253 /* 254 * Duplicated environments are not managed. 255 */ 256 copy->managed = false; 182 257 } 183 258 … … 547 622 static bool rtems_shell_login(rtems_shell_env_t *env, FILE * in,FILE * out) 548 623 { 549 FILE 550 int 551 time_t 624 FILE *fd; 625 int c; 626 time_t t; 552 627 553 628 if (out) { … … 708 783 709 784 bool rtems_shell_main_loop( 710 rtems_shell_env_t *shell_env _arg785 rtems_shell_env_t *shell_env 711 786 ) 712 787 { 713 rtems_shell_env_t *shell_env; 714 int eno; 715 struct termios term; 716 struct termios previous_term; 717 char *prompt = NULL; 718 int cmd; 719 int cmd_count = 1; /* assume a script and so only 1 command line */ 720 char *cmds[RTEMS_SHELL_CMD_COUNT]; 721 char *cmd_argv; 722 int argc; 723 char *argv[RTEMS_SHELL_MAXIMUM_ARGUMENTS]; 724 bool result = true; 725 bool input_file = false; 726 int line = 0; 727 FILE *stdinToClose = NULL; 728 FILE *stdoutToClose = NULL; 788 struct termios term; 789 struct termios previous_term; 790 char *prompt = NULL; 791 int cmd; 792 int cmd_count = 1; /* assume a script and so only 1 command line */ 793 char *cmds[RTEMS_SHELL_CMD_COUNT]; 794 char *cmd_argv; 795 int argc; 796 char *argv[RTEMS_SHELL_MAXIMUM_ARGUMENTS]; 797 bool result = true; 798 bool input_file = false; 799 int line = 0; 800 FILE *stdinToClose = NULL; 801 FILE *stdoutToClose = NULL; 729 802 730 803 rtems_shell_init_environment(); 731 804 732 shell_env = rtems_shell_init_env(shell_env_arg); 733 if (shell_env == NULL) { 734 rtems_error(0, "rtems_shell_init_env"); 805 if (shell_env->magic != rtems_build_name('S', 'E', 'N', 'V')) { 806 rtems_error(0, "invalid shell environment passed to the main loop)"); 735 807 return false; 736 808 } 737 809 738 eno = pthread_setspecific(rtems_shell_current_env_key, shell_env); 739 if (eno != 0) { 740 rtems_error(0, "pthread_setspecific(shell_current_env_key)"); 810 if (!rtems_shell_set_shell_env(shell_env)) 741 811 return false; 742 }743 812 744 813 if (!rtems_shell_init_user_env()) { … … 747 816 } 748 817 749 fileno(stdout); 750 751 /* fprintf( stderr, 752 "-%s-%s-\n", shell_env->input, shell_env->output ); 753 */ 754 755 if (shell_env->output && strcmp(shell_env->output, "stdout") != 0) { 756 if (strcmp(shell_env->output, "stderr") == 0) { 757 stdout = stderr; 818 shell_std_debug("shell: out: %d %d %s\n", 819 fileno(stdout), fileno(shell_env->parent_stdout), 820 shell_env->output); 821 shell_std_debug(" : in: %d %d %s\n", 822 fileno(stdin), fileno(shell_env->parent_stdin), 823 shell_env->input); 824 825 if (shell_env->output != NULL) { 826 if (strcmp(shell_env->output, "stdout") == 0) { 827 if (shell_env->parent_stdout != NULL) 828 stdout = shell_env->parent_stdout; 829 } 830 else if (strcmp(shell_env->output, "stderr") == 0) { 831 if (shell_env->parent_stderr != NULL) 832 stdout = shell_env->parent_stderr; 833 else 834 stdout = stderr; 758 835 } else if (strcmp(shell_env->output, "/dev/null") == 0) { 759 836 fclose (stdout); 760 837 } else { 761 FILE *output = fopen(shell_env _arg->output,762 shell_env _arg->output_append ? "a" : "w");763 if ( !output) {838 FILE *output = fopen(shell_env->output, 839 shell_env->output_append ? "a" : "w"); 840 if (output == NULL) { 764 841 fprintf(stderr, "shell: open output %s failed: %s\n", 765 shell_env _arg->output, strerror(errno));842 shell_env->output, strerror(errno)); 766 843 return false; 767 844 } … … 771 848 } 772 849 773 if (shell_env->input && strcmp(shell_env_arg->input, "stdin") != 0) { 774 FILE *input = fopen(shell_env_arg->input, "r"); 775 if (!input) { 776 fprintf(stderr, "shell: open input %s failed: %s\n", 777 shell_env_arg->input, strerror(errno)); 778 return false; 850 if (shell_env->input != NULL) { 851 if (strcmp(shell_env->input, "stdin") == 0) { 852 if (shell_env->parent_stdin != NULL) 853 stdin = shell_env->parent_stdin; 854 } else { 855 FILE *input = fopen(shell_env->input, "r"); 856 if (input == NULL) { 857 fprintf(stderr, "shell: open input %s failed: %s\n", 858 shell_env->input, strerror(errno)); 859 if (stdoutToClose != NULL) 860 fclose(stdoutToClose); 861 return false; 862 } 863 stdin = input; 864 stdinToClose = input; 865 shell_env->forever = false; 866 input_file = true; 779 867 } 780 stdin = input; 781 stdinToClose = input; 782 shell_env->forever = false; 783 input_file =true; 784 } 785 else { 786 /* make a raw terminal,Linux Manuals */ 868 } 869 870 if (!input_file) { 871 /* Make a raw terminal, Linux Manuals */ 787 872 if (tcgetattr(fileno(stdin), &previous_term) >= 0) { 788 873 term = previous_term; … … 791 876 term.c_oflag |= (OPOST|ONLCR); /* But with cr+nl on output */ 792 877 term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); 793 term.c_cflag 878 term.c_cflag |= CLOCAL | CREAD; 794 879 term.c_cc[VMIN] = 1; 795 880 term.c_cc[VTIME] = 0; … … 806 891 } 807 892 808 setvbuf(stdin,NULL,_IONBF,0); /* Not buffered*/ 809 setvbuf(stdout,NULL,_IONBF,0); /* Not buffered*/ 893 shell_std_debug("shell: child out: %d in %d\n", fileno(stdout), fileno(stdin)); 894 shell_std_debug("shell: child out: %p\n", stdout); 895 896 /* Do not buffer if interactive else leave buffered */ 897 if (!input_file) 898 setvbuf(stdin, NULL, _IONBF, 0); 899 setvbuf(stdout, NULL, _IONBF, 0); 810 900 811 901 /* … … 870 960 871 961 for (;;) { 872 int cmd;873 874 962 /* Prompt section */ 875 963 if (prompt) { … … 925 1013 if (!rtems_shell_make_args(cmd_argv, &argc, argv, 926 1014 RTEMS_SHELL_MAXIMUM_ARGUMENTS)) { 927 shell_env->errorlevel = rtems_shell_execute_cmd(argv[0], argc, argv); 1015 int exit_code = rtems_shell_execute_cmd(argv[0], argc, argv); 1016 if (shell_env->exit_code != NULL) 1017 *shell_env->exit_code = exit_code; 1018 if (exit_code != 0 && shell_env->exit_on_error) 1019 shell_env->exit_shell = true; 928 1020 } 929 1021 … … 975 1067 bool output_append, 976 1068 rtems_id wake_on_end, 1069 int *exit_code, 977 1070 bool echo, 978 1071 rtems_shell_login_check_t login_check … … 983 1076 rtems_shell_env_t *shell_env; 984 1077 rtems_name name; 1078 1079 rtems_shell_init_environment(); 985 1080 986 1081 if ( task_name && strlen(task_name) >= 4) … … 1009 1104 return RTEMS_NO_MEMORY; 1010 1105 } 1106 1011 1107 shell_env->devname = devname; 1012 1108 shell_env->taskname = task_name; 1109 1013 1110 shell_env->exit_shell = false; 1014 1111 shell_env->forever = forever; 1015 1112 shell_env->echo = echo; 1016 shell_env->input = strdup (input);1017 shell_env->output = strdup (output);1113 shell_env->input = input == NULL ? NULL : strdup (input); 1114 shell_env->output = output == NULL ? NULL : strdup (output); 1018 1115 shell_env->output_append = output_append; 1116 shell_env->parent_stdin = stdin; 1117 shell_env->parent_stdout = stdout; 1118 shell_env->parent_stderr = stderr; 1019 1119 shell_env->wake_on_end = wake_on_end; 1120 shell_env->exit_code = exit_code; 1020 1121 shell_env->login_check = login_check; 1021 1122 shell_env->uid = getuid(); … … 1025 1126 1026 1127 sc = rtems_task_start(task_id, rtems_shell_task, 1027 1128 (rtems_task_argument) shell_env); 1028 1129 if (sc != RTEMS_SUCCESSFUL) { 1029 1130 rtems_error(sc,"starting task %s in shell_init()",task_name); 1131 free( (void*) shell_env->input ); 1132 free( (void*) shell_env->output ); 1133 free( shell_env ); 1030 1134 return sc; 1031 1135 } … … 1036 1140 } 1037 1141 1038 return 0;1142 return sc; 1039 1143 } 1040 1144 … … 1050 1154 { 1051 1155 rtems_id to_wake = RTEMS_ID_NONE; 1156 int exit_code = 0; 1052 1157 1053 1158 if ( wait ) … … 1065 1170 false, /* output_append */ 1066 1171 to_wake, /* wake_on_end */ 1172 &exit_code, /* exit code of command */ 1067 1173 false, /* echo */ 1068 1174 login_check /* login check */ … … 1070 1176 } 1071 1177 1072 rtems_status_code 1178 rtems_status_code rtems_shell_script ( 1073 1179 const char *task_name, 1074 1180 size_t task_stacksize, … … 1081 1187 ) 1082 1188 { 1083 rtems_id current_task = RTEMS_INVALID_ID; 1189 rtems_id to_wake = RTEMS_ID_NONE; 1190 int exit_code = 0; 1084 1191 rtems_status_code sc; 1085 1192 1086 if (wait) { 1087 sc = rtems_task_ident (RTEMS_SELF, RTEMS_LOCAL, ¤t_task); 1088 if (sc != RTEMS_SUCCESSFUL) 1089 return sc; 1090 } 1091 1092 sc = rtems_shell_run( 1193 if ( wait ) 1194 to_wake = rtems_task_self(); 1195 1196 return rtems_shell_run( 1093 1197 task_name, /* task_name */ 1094 1198 task_stacksize, /* task_stacksize */ … … 1100 1204 output, /* output */ 1101 1205 output_append, /* output_append */ 1102 current_task, /* wake_on_end */ 1206 to_wake, /* wake_on_end */ 1207 &exit_code, /* exit_code */ 1103 1208 echo, /* echo */ 1104 1209 NULL /* login check */ 1105 1210 ); 1106 if (sc != RTEMS_SUCCESSFUL) 1107 return sc; 1211 1212 if (sc == RTEMS_SUCCESSFUL) 1213 { 1214 /* Place holder until RTEMS 5 is released then the interface for 1215 * this call will change. */ 1216 } 1108 1217 1109 1218 return sc; -
cpukit/libmisc/shell/shell.h
rfe09d8d r4d906d6a 218 218 * Private environment associated with each shell instance. 219 219 */ 220 typedef struct {220 typedef struct rtems_shell_env { 221 221 /** 'S','E','N','V': Shell Environment */ 222 222 rtems_name magic; 223 bool managed; 223 224 const char *devname; 224 225 const char *taskname; 225 226 bool exit_shell; /* logout */ 226 227 bool forever; /* repeat login */ 227 int errorlevel; 228 int *exit_code; 229 bool exit_on_error; 228 230 bool echo; 229 231 char cwd[256]; … … 231 233 const char *output; 232 234 bool output_append; 235 FILE *parent_stdin; 236 FILE *parent_stdout; 237 FILE *parent_stderr; 233 238 rtems_id wake_on_end; 234 239 rtems_shell_login_check_t login_check; -
testsuites/libtests/shell01/init.c
rfe09d8d r4d906d6a 47 47 } 48 48 49 static const char joel_in[] = 50 "#! joel\n" 51 "jtst hello world\n" 52 "jtst 1 2 3 4 5\n"; 53 54 static const char joel_out_1[] = 55 " 3 'jtst hello world'\n" 56 " 6 'jtst 1 2 3 4 5'\n"; 57 58 static const char joel_out_2[] = 59 "\n" 60 "RTEMS Shell on (null). Use 'help' to list commands.\n" 61 " 3 'jtst hello world'\n" 62 " 6 'jtst 1 2 3 4 5'\n"; 63 64 static int joel_test_command(int argc, char** argv) 65 { 66 int i; 67 fprintf(stdout, "%2d '", argc); 68 for (i = 0; i < argc; ++i) { 69 fprintf(stdout, argv[i]); 70 if (i < (argc - 1)) 71 fprintf(stdout, " "); 72 } 73 fprintf(stdout, "'\n"); 74 return 0; 75 } 76 77 static void test_joel(void) 78 { 79 /* 80 * Running a joel script tests the shell main loop. 81 */ 82 char buf[sizeof(joel_out_2) + 1]; 83 rtems_shell_cmd_t* cmd; 84 FILE *in; 85 FILE *out; 86 FILE *current_stdout = stdout; 87 FILE *current_stdin = stdin; 88 size_t len; 89 rtems_status_code sc; 90 91 /* 92 * Use a private command due to the way the testsuite maps printk onto printf. 93 */ 94 cmd = rtems_shell_add_cmd("jtst", "misc", "joel test", joel_test_command); 95 rtems_test_assert(cmd != NULL); 96 97 len = strlen(joel_in); 98 99 in = fopen("/jin", "w"); 100 rtems_test_assert(in != NULL); 101 rtems_test_assert(fwrite(joel_in, sizeof(char), len, in) == len); 102 rtems_test_assert(fclose(in) == 0); 103 104 /* 105 * The shell opens the input and output files. 106 */ 107 sc = rtems_shell_script( 108 "JTST", 109 8 * 1024, 110 1, 111 "/jin", 112 "/jout", 113 false, 114 true, 115 false); 116 rtems_test_assert(sc == RTEMS_SUCCESSFUL); 117 118 out = fopen("/jout", "r"); 119 rtems_test_assert(out != NULL); 120 rtems_test_assert(!feof(out)); 121 memset(buf, 0, sizeof(buf)); 122 len = fread(buf, sizeof(char), sizeof(buf), out); 123 rtems_test_assert(len > 0); 124 rtems_test_assert(strcmp(joel_out_1, buf) == 0); 125 rtems_test_assert(fclose(out) == 0); 126 127 /* 128 * The shell task inherits the parent stdin and stdout 129 */ 130 in = fopen("/jin", "r"); 131 rtems_test_assert(in != NULL); 132 out = fopen("/jout", "w"); 133 rtems_test_assert(out != NULL); 134 135 stdin = in; 136 stdout = out; 137 138 sc = rtems_shell_script( 139 "JTST", 140 8 * 1024, 141 1, 142 "stdin", 143 "stdout", 144 false, 145 true, 146 false); 147 rtems_test_assert(sc == RTEMS_SUCCESSFUL); 148 149 stdout = current_stdout; 150 stdin = current_stdin; 151 152 rtems_test_assert(fclose(in) == 0); 153 rtems_test_assert(fclose(out) == 0); 154 155 out = fopen("/jout", "r"); 156 rtems_test_assert(out != NULL); 157 rtems_test_assert(!feof(out)); 158 memset(buf, 0, sizeof(buf)); 159 len = fread(buf, sizeof(char), sizeof(buf), out); 160 rtems_test_assert(len > 0); 161 rtems_test_assert(strcmp(joel_out_2, buf) == 0); 162 rtems_test_assert(fclose(out) == 0); 163 } 164 49 165 static void test(void) 50 166 { … … 166 282 167 283 test(); 284 test_joel(); 168 285 169 286 TEST_END(); … … 174 291 #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER 175 292 176 #define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 4177 178 #define CONFIGURE_MAXIMUM_TASKS 1179 #define CONFIGURE_MAXIMUM_POSIX_KEYS 1293 #define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 5 294 295 #define CONFIGURE_MAXIMUM_TASKS 3 296 #define CONFIGURE_MAXIMUM_POSIX_KEYS 2 180 297 #define CONFIGURE_MAXIMUM_POSIX_KEY_VALUE_PAIRS 2 181 298
Note: See TracChangeset
for help on using the changeset viewer.