Implement exec_one_command & exec_simple_command
The new two functions replace the exec_process function.
@@ -158,10 +158,9 @@ | ||
158 | 158 | __attribute__((nonnull)); |
159 | 159 | static void exec_one_command(command_T *c, bool finally_exit) |
160 | 160 | __attribute__((nonnull)); |
161 | +static void exec_simple_command(const command_T *c, bool finally_exit) | |
162 | + __attribute__((nonnull)); | |
161 | 163 | // TODO Reconsider order of functions around here |
162 | -static pid_t exec_process( | |
163 | - command_T *restrict c, exec_T type, pipeinfo_T *restrict pi, pid_t pgid) | |
164 | - __attribute__((nonnull)); | |
165 | 164 | static inline void connect_pipes(pipeinfo_T *pi) |
166 | 165 | __attribute__((nonnull)); |
167 | 166 | static void become_child(sigtype_T sigtype); |
@@ -613,6 +612,8 @@ | ||
613 | 612 | exec_one_command: /* child process */ |
614 | 613 | free(job); |
615 | 614 | connect_pipes(&pipe); |
615 | + if (type == E_ASYNC && pipe.pi_fromprevfd < 0) | |
616 | + maybe_redirect_stdin_to_devnull(); | |
616 | 617 | exec_one_command(c, true); |
617 | 618 | assert(false); |
618 | 619 | } else if (pid >= 0) { |
@@ -803,6 +804,7 @@ | ||
803 | 804 | xerror(errno, Ngt("cannot open a pipe")); |
804 | 805 | } |
805 | 806 | |
807 | +/* Executes the command. */ | |
806 | 808 | void exec_one_command(command_T *c, bool finally_exit) |
807 | 809 | { |
808 | 810 | /* prevent the command data from being freed in case the command is part of |
@@ -809,76 +811,51 @@ | ||
809 | 811 | * a function that is unset during execution. */ |
810 | 812 | c = comsdup(c); |
811 | 813 | |
814 | + update_lineno(c->c_lineno); | |
815 | + | |
812 | 816 | if (c->c_type == CT_SIMPLE) { |
817 | + exec_simple_command(c, finally_exit); | |
813 | 818 | } else { |
819 | + savefd_T *savefd; | |
820 | + if (open_redirections(c->c_redirs, &savefd)) { | |
821 | + exec_nonsimple_command(c, finally_exit && savefd == NULL); | |
822 | + undo_redirections(savefd); | |
823 | + } else { | |
824 | + laststatus = Exit_REDIRERR; | |
825 | + apply_errexit_errreturn(NULL); | |
826 | + } | |
814 | 827 | } |
815 | - // TODO implement exec_one_command | |
816 | 828 | |
817 | 829 | comsfree(c); |
830 | + | |
831 | + if (finally_exit) | |
832 | + exit_shell(); | |
818 | 833 | } |
819 | 834 | |
820 | -/* Executes the command. | |
821 | - * If job control is active, the child process's process group ID is set to | |
822 | - * `pgid'. If `pgid' is 0, the child process's process ID is used as the process | |
823 | - * group ID. | |
824 | - * If the child process forked successfully, its process ID is returned. | |
825 | - * If the command was executed without forking, `laststatus' is set to the exit | |
826 | - * status of the command and 0 is returned. | |
827 | - * if `type' is E_SELF, this function never returns. */ | |
828 | -pid_t exec_process( | |
829 | - command_T *restrict c, exec_T type, pipeinfo_T *restrict pi, pid_t pgid) | |
835 | +/* Executes the simple command. */ | |
836 | +void exec_simple_command(const command_T *c, bool finally_exit) | |
830 | 837 | { |
831 | - bool finally_exit; /* never return? */ | |
838 | + lastcmdsubstatus = Exit_SUCCESS; | |
839 | + | |
840 | + /* expand the command words */ | |
832 | 841 | int argc; |
833 | - void **argv = NULL; | |
834 | - char *argv0 = NULL; | |
835 | - pid_t cpid = 0; | |
842 | + void **argv; | |
843 | + if (!expand_line(c->c_words, &argc, &argv)) { | |
844 | + laststatus = Exit_EXPERROR; | |
845 | + goto done; | |
846 | + } | |
847 | + if (is_interrupted()) | |
848 | + goto done1; | |
836 | 849 | |
837 | - update_lineno(c->c_lineno); | |
838 | - | |
839 | - finally_exit = (type == E_SELF); | |
840 | - if (finally_exit) { | |
841 | - if (c->c_type == CT_SUBSHELL) | |
842 | - /* No command follows this subshell command, so we can execute the | |
843 | - * subshell directly in this process. */ | |
844 | - become_child(0); | |
850 | + char *argv0; // a multi-byte version of argv[0] | |
851 | + if (argc == 0) { | |
852 | + argv0 = NULL; | |
845 | 853 | } else { |
846 | - /* fork first if `type' is E_ASYNC, the command type is subshell, | |
847 | - * or there is a pipe. */ | |
848 | - if (type == E_ASYNC || c->c_type == CT_SUBSHELL | |
849 | - || pi->pi_fromprevfd >= 0 || pi->pi_tonextfds[PIPE_OUT] >= 0) { | |
850 | - sigtype_T sigtype = (type == E_ASYNC) ? t_quitint : 0; | |
851 | - cpid = fork_and_reset(pgid, type == E_NORMAL, sigtype); | |
852 | - if (cpid != 0) | |
853 | - goto done; | |
854 | - finally_exit = true; | |
855 | - } | |
854 | + argv0 = malloc_wcstombs(argv[0]); | |
855 | + if (argv0 == NULL) | |
856 | + argv0 = xstrdup(""); | |
856 | 857 | } |
857 | 858 | |
858 | - lastcmdsubstatus = Exit_SUCCESS; | |
859 | - | |
860 | - /* connect pipes and close leftovers */ | |
861 | - connect_pipes(pi); | |
862 | - | |
863 | - if (c->c_type == CT_SIMPLE) { | |
864 | - if (!expand_line(c->c_words, &argc, &argv)) { | |
865 | - laststatus = Exit_EXPERROR; | |
866 | - goto done; | |
867 | - } | |
868 | - if (is_interrupted()) { | |
869 | - plfree(argv, free); | |
870 | - goto done; | |
871 | - } | |
872 | - if (argc == 0) { | |
873 | - argv0 = NULL; | |
874 | - } else { | |
875 | - argv0 = malloc_wcstombs(argv[0]); | |
876 | - if (argv0 == NULL) | |
877 | - argv0 = xstrdup(""); | |
878 | - } | |
879 | - } | |
880 | - /* `argc' and `argv' are used only for `CT_SIMPLE'. */ | |
881 | - | |
882 | 859 | /* open redirections */ |
883 | 860 | savefd_T *savefd; |
884 | 861 | if (!open_redirections(c->c_redirs, &savefd)) { |
@@ -885,24 +862,12 @@ | ||
885 | 862 | /* On redirection error, the command is not executed. */ |
886 | 863 | laststatus = Exit_REDIRERR; |
887 | 864 | apply_errexit_errreturn(NULL); |
888 | - if (posixly_correct && !is_interactive_now && c->c_type == CT_SIMPLE && | |
865 | + if (posixly_correct && !is_interactive_now && | |
889 | 866 | argc > 0 && is_special_builtin(argv0)) |
890 | 867 | finally_exit = true; |
891 | 868 | goto done2; |
892 | 869 | } |
893 | - | |
894 | - if (type == E_ASYNC && pi->pi_fromprevfd < 0) | |
895 | - maybe_redirect_stdin_to_devnull(); | |
896 | 870 | |
897 | - if (c->c_type != CT_SIMPLE) { | |
898 | - if (c->c_type == CT_SUBSHELL) { | |
899 | - clear_savefd(savefd); | |
900 | - savefd = NULL; | |
901 | - } | |
902 | - exec_nonsimple_command(c, finally_exit && savefd == NULL); | |
903 | - goto done1; | |
904 | - } | |
905 | - | |
906 | 871 | last_assign = c->c_assigns; |
907 | 872 | if (argc == 0) { |
908 | 873 | /* if there is no command word, just perform assignments */ |
@@ -917,14 +882,13 @@ | ||
917 | 882 | goto done2; |
918 | 883 | } |
919 | 884 | |
885 | + /* check if the command is a special built-in or function */ | |
920 | 886 | commandinfo_T cmdinfo; |
921 | - bool temp; | |
922 | - | |
923 | - /* check if the command is a special built-in or a function and determine | |
924 | - * whether we have to open a temporary environment. */ | |
925 | 887 | search_command(argv0, argv[0], &cmdinfo, SCT_BUILTIN | SCT_FUNCTION); |
926 | 888 | special_builtin_executed = (cmdinfo.type == CT_SPECIALBUILTIN); |
927 | - temp = c->c_assigns != NULL && !special_builtin_executed; | |
889 | + | |
890 | + /* open a temporary variable environment */ | |
891 | + bool temp = c->c_assigns != NULL && !special_builtin_executed; | |
928 | 892 | if (temp) |
929 | 893 | open_new_environment(true); |
930 | 894 |
@@ -953,29 +917,10 @@ | ||
953 | 917 | } |
954 | 918 | } |
955 | 919 | |
956 | - /* create a child process to execute the external command */ | |
957 | - if (cmdinfo.type == CT_EXTERNALPROGRAM && !finally_exit) { | |
958 | - assert(type == E_NORMAL); | |
959 | - cpid = fork_and_reset(pgid, true, t_leave); | |
960 | - if (cpid != 0) | |
961 | - goto done3; | |
962 | - finally_exit = true; | |
963 | - } | |
964 | - | |
965 | 920 | /* execute! */ |
966 | - bool finally_exit2; | |
967 | - switch (cmdinfo.type) { | |
968 | - case CT_EXTERNALPROGRAM: | |
969 | - finally_exit2 = true; | |
970 | - break; | |
971 | - case CT_FUNCTION: | |
972 | - finally_exit2 = (finally_exit && /* !temp && */ savefd == NULL); | |
973 | - break; | |
974 | - default: | |
975 | - finally_exit2 = false; | |
976 | - break; | |
977 | - } | |
978 | - invoke_simple_command(&cmdinfo, argc, argv0, argv, finally_exit2); | |
921 | + invoke_simple_command(&cmdinfo, argc, argv0, argv, | |
922 | + finally_exit && /* !temp && */ savefd == NULL); | |
923 | + // TODO refactor invoke_simple_command | |
979 | 924 | |
980 | 925 | /* Redirections are not undone after a successful "exec" command: |
981 | 926 | * remove the saved data of file descriptors. */ |
@@ -985,22 +930,18 @@ | ||
985 | 930 | } |
986 | 931 | exec_builtin_executed = false; |
987 | 932 | |
933 | + /* cleanup */ | |
988 | 934 | done3: |
989 | 935 | if (temp) |
990 | 936 | close_current_environment(); |
991 | 937 | done2: |
992 | - if (c->c_type == CT_SIMPLE) | |
993 | - plfree(argv, free), free(argv0); | |
938 | + undo_redirections(savefd); | |
939 | + free(argv0); | |
994 | 940 | done1: |
995 | - undo_redirections(savefd); | |
941 | + plfree(argv, free); | |
996 | 942 | done: |
997 | - if (cpid < 0) { | |
998 | - laststatus = Exit_NOEXEC; | |
999 | - cpid = 0; | |
1000 | - } | |
1001 | 943 | if (finally_exit) |
1002 | 944 | exit_shell(); |
1003 | - return cpid; | |
1004 | 945 | } |
1005 | 946 | |
1006 | 947 | /* Connects the pipe(s) and closes the pipes left. */ |
@@ -1234,6 +1175,7 @@ | ||
1234 | 1175 | */ |
1235 | 1176 | void exec_nonsimple_command(command_T *c, bool finally_exit) |
1236 | 1177 | { |
1178 | + // TODO fork or become_child(0) if CT_GROUP | |
1237 | 1179 | switch (c->c_type) { |
1238 | 1180 | case CT_SIMPLE: |
1239 | 1181 | assert(false); |