diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-06-27 04:30:11 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-06-27 04:30:11 +0000 |
commit | 4b6b5e4314e6b760bdc0cf51dfb1f01896f3b6d0 (patch) | |
tree | d058a44b529547cdb550f198428549d9669efa1b | |
parent | 5c66d06104db468908598d276062fc50f542a17a (diff) | |
download | busybox-w32-4b6b5e4314e6b760bdc0cf51dfb1f01896f3b6d0.tar.gz busybox-w32-4b6b5e4314e6b760bdc0cf51dfb1f01896f3b6d0.tar.bz2 busybox-w32-4b6b5e4314e6b760bdc0cf51dfb1f01896f3b6d0.zip |
Re-enable globbing (I'd accidentaly removed it) and finish off the last
of the job control polishing. Works fine now.
-Erik
-rw-r--r-- | lash.c | 234 | ||||
-rw-r--r-- | shell/lash.c | 234 |
2 files changed, 448 insertions, 20 deletions
@@ -135,6 +135,7 @@ static void mark_open(int fd); | |||
135 | static void mark_closed(int fd); | 135 | static void mark_closed(int fd); |
136 | static void close_all(void); | 136 | static void close_all(void); |
137 | static void checkjobs(struct jobset *job_list); | 137 | static void checkjobs(struct jobset *job_list); |
138 | static void remove_job(struct jobset *j_list, struct job *job); | ||
138 | static int get_command(FILE * source, char *command); | 139 | static int get_command(FILE * source, char *command); |
139 | static int parse_command(char **command_ptr, struct job *job, int *inbg); | 140 | static int parse_command(char **command_ptr, struct job *job, int *inbg); |
140 | static int run_command(struct job *newjob, int inbg, int outpipe[2]); | 141 | static int run_command(struct job *newjob, int inbg, int outpipe[2]); |
@@ -181,6 +182,8 @@ static struct jobset job_list = { NULL, NULL }; | |||
181 | static int argc; | 182 | static int argc; |
182 | static char **argv; | 183 | static char **argv; |
183 | static struct close_me *close_me_head; | 184 | static struct close_me *close_me_head; |
185 | static int last_return_code; | ||
186 | static int last_bg_pid; | ||
184 | static unsigned int last_jobid; | 187 | static unsigned int last_jobid; |
185 | static int shell_terminal; | 188 | static int shell_terminal; |
186 | static pid_t shell_pgrp; | 189 | static pid_t shell_pgrp; |
@@ -313,8 +316,12 @@ static int builtin_fg_bg(struct child_prog *child) | |||
313 | 316 | ||
314 | job->stopped_progs = 0; | 317 | job->stopped_progs = 0; |
315 | 318 | ||
316 | if (kill(- job->pgrp, SIGCONT) < 0) | 319 | if ( (i=kill(- job->pgrp, SIGCONT)) < 0) { |
320 | if (i == ESRCH) { | ||
321 | remove_job(&job_list, job); | ||
322 | } | ||
317 | perror_msg("kill (SIGCONT)"); | 323 | perror_msg("kill (SIGCONT)"); |
324 | } | ||
318 | 325 | ||
319 | return EXIT_SUCCESS; | 326 | return EXIT_SUCCESS; |
320 | } | 327 | } |
@@ -536,6 +543,11 @@ static void remove_job(struct jobset *j_list, struct job *job) | |||
536 | prevjob->next = job->next; | 543 | prevjob->next = job->next; |
537 | } | 544 | } |
538 | 545 | ||
546 | if (j_list->head) | ||
547 | last_jobid = j_list->head->jobid; | ||
548 | else | ||
549 | last_jobid = 0; | ||
550 | |||
539 | free(job); | 551 | free(job); |
540 | } | 552 | } |
541 | 553 | ||
@@ -576,10 +588,15 @@ static void checkjobs(struct jobset *j_list) | |||
576 | job->stopped_progs++; | 588 | job->stopped_progs++; |
577 | job->progs[prognum].is_stopped = 1; | 589 | job->progs[prognum].is_stopped = 1; |
578 | 590 | ||
591 | #if 0 | ||
592 | /* Printing this stuff is a pain, since it tends to | ||
593 | * overwrite the prompt an inconveinient moments. So | ||
594 | * don't do that. */ | ||
579 | if (job->stopped_progs == job->num_progs) { | 595 | if (job->stopped_progs == job->num_progs) { |
580 | printf(JOB_STATUS_FORMAT, job->jobid, "Stopped", | 596 | printf(JOB_STATUS_FORMAT, job->jobid, "Stopped", |
581 | job->text); | 597 | job->text); |
582 | } | 598 | } |
599 | #endif | ||
583 | } | 600 | } |
584 | } | 601 | } |
585 | 602 | ||
@@ -714,14 +731,78 @@ static int get_command(FILE * source, char *command) | |||
714 | return 0; | 731 | return 0; |
715 | } | 732 | } |
716 | 733 | ||
734 | static char* itoa(register int i) | ||
735 | { | ||
736 | static char a[7]; /* Max 7 ints */ | ||
737 | register char *b = a + sizeof(a) - 1; | ||
738 | int sign = (i < 0); | ||
739 | |||
740 | if (sign) | ||
741 | i = -i; | ||
742 | *b = 0; | ||
743 | do | ||
744 | { | ||
745 | *--b = '0' + (i % 10); | ||
746 | i /= 10; | ||
747 | } | ||
748 | while (i); | ||
749 | if (sign) | ||
750 | *--b = '-'; | ||
751 | return b; | ||
752 | } | ||
753 | |||
754 | char * strsep_space( char *string, int * ix) | ||
755 | { | ||
756 | char *token, *begin; | ||
757 | |||
758 | begin = string; | ||
759 | |||
760 | /* Short circuit the trivial case */ | ||
761 | if ( !string || ! string[*ix]) | ||
762 | return NULL; | ||
763 | |||
764 | /* Find the end of the token. */ | ||
765 | while( string && string[*ix] && !isspace(string[*ix]) ) { | ||
766 | (*ix)++; | ||
767 | } | ||
768 | |||
769 | /* Find the end of any whitespace trailing behind | ||
770 | * the token and let that be part of the token */ | ||
771 | while( string && string[*ix] && isspace(string[*ix]) ) { | ||
772 | (*ix)++; | ||
773 | } | ||
774 | |||
775 | if (! string && *ix==0) { | ||
776 | /* Nothing useful was found */ | ||
777 | return NULL; | ||
778 | } | ||
779 | |||
780 | token = xmalloc(*ix+1); | ||
781 | token[*ix] = '\0'; | ||
782 | strncpy(token, string, *ix); | ||
783 | |||
784 | return token; | ||
785 | } | ||
717 | 786 | ||
718 | static int expand_arguments(char *command) | 787 | static int expand_arguments(char *command) |
719 | { | 788 | { |
720 | int ix = 0; | 789 | int total_length=0, length, i, retval, ix = 0; |
790 | expand_t expand_result; | ||
791 | char *tmpcmd, *cmd, *cmd_copy; | ||
792 | char *src, *dst, *var; | ||
793 | const char *out_of_space = "out of space during expansion"; | ||
794 | int flags = GLOB_NOCHECK | ||
795 | #ifdef GLOB_BRACE | ||
796 | | GLOB_BRACE | ||
797 | #endif | ||
798 | #ifdef GLOB_TILDE | ||
799 | | GLOB_TILDE | ||
800 | #endif | ||
801 | ; | ||
721 | 802 | ||
722 | /* get rid of the terminating \n */ | 803 | /* get rid of the terminating \n */ |
723 | chomp(command); | 804 | chomp(command); |
724 | 805 | ||
725 | /* Fix up escape sequences to be the Real Thing(tm) */ | 806 | /* Fix up escape sequences to be the Real Thing(tm) */ |
726 | while( command && command[ix]) { | 807 | while( command && command[ix]) { |
727 | if (command[ix] == '\\') { | 808 | if (command[ix] == '\\') { |
@@ -731,6 +812,139 @@ static int expand_arguments(char *command) | |||
731 | } | 812 | } |
732 | ix++; | 813 | ix++; |
733 | } | 814 | } |
815 | /* Use glob and then fixup environment variables and such */ | ||
816 | |||
817 | /* It turns out that glob is very stupid. We have to feed it one word at a | ||
818 | * time since it can't cope with a full string. Here we convert command | ||
819 | * (char*) into cmd (char**, one word per string) */ | ||
820 | |||
821 | /* We need a clean copy, so strsep can mess up the copy while | ||
822 | * we write stuff into the original (in a minute) */ | ||
823 | cmd = cmd_copy = strdup(command); | ||
824 | *command = '\0'; | ||
825 | for (ix = 0, tmpcmd = cmd; | ||
826 | (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) { | ||
827 | if (*tmpcmd == '\0') | ||
828 | break; | ||
829 | /* we need to trim() the result for glob! */ | ||
830 | trim(tmpcmd); | ||
831 | retval = glob(tmpcmd, flags, NULL, &expand_result); | ||
832 | free(tmpcmd); /* Free mem allocated by strsep_space */ | ||
833 | if (retval == GLOB_NOSPACE) { | ||
834 | /* Mem may have been allocated... */ | ||
835 | globfree (&expand_result); | ||
836 | error_msg(out_of_space); | ||
837 | return FALSE; | ||
838 | } else if (retval != 0) { | ||
839 | /* Some other error. GLOB_NOMATCH shouldn't | ||
840 | * happen because of the GLOB_NOCHECK flag in | ||
841 | * the glob call. */ | ||
842 | error_msg("syntax error"); | ||
843 | return FALSE; | ||
844 | } else { | ||
845 | /* Convert from char** (one word per string) to a simple char*, | ||
846 | * but don't overflow command which is BUFSIZ in length */ | ||
847 | for (i=0; i < expand_result.gl_pathc; i++) { | ||
848 | length=strlen(expand_result.gl_pathv[i]); | ||
849 | if (total_length+length+1 >= BUFSIZ) { | ||
850 | error_msg(out_of_space); | ||
851 | return FALSE; | ||
852 | } | ||
853 | strcat(command+total_length, " "); | ||
854 | total_length+=1; | ||
855 | strcat(command+total_length, expand_result.gl_pathv[i]); | ||
856 | total_length+=length; | ||
857 | } | ||
858 | globfree (&expand_result); | ||
859 | } | ||
860 | } | ||
861 | free(cmd_copy); | ||
862 | trim(command); | ||
863 | |||
864 | /* Now do the shell variable substitutions which | ||
865 | * wordexp can't do for us, namely $? and $! */ | ||
866 | src = command; | ||
867 | while((dst = strchr(src,'$')) != NULL){ | ||
868 | var = NULL; | ||
869 | switch(*(dst+1)) { | ||
870 | case '?': | ||
871 | var = itoa(last_return_code); | ||
872 | break; | ||
873 | case '!': | ||
874 | if (last_bg_pid==-1) | ||
875 | *(var)='\0'; | ||
876 | else | ||
877 | var = itoa(last_bg_pid); | ||
878 | break; | ||
879 | /* Everything else like $$, $#, $[0-9], etc. should all be | ||
880 | * expanded by wordexp(), so we can in theory skip that stuff | ||
881 | * here, but just to be on the safe side (i.e., since uClibc | ||
882 | * wordexp doesn't do this stuff yet), lets leave it in for | ||
883 | * now. */ | ||
884 | case '$': | ||
885 | var = itoa(getpid()); | ||
886 | break; | ||
887 | case '#': | ||
888 | var = itoa(argc-1); | ||
889 | break; | ||
890 | case '0':case '1':case '2':case '3':case '4': | ||
891 | case '5':case '6':case '7':case '8':case '9': | ||
892 | { | ||
893 | int ixx=*(dst + 1)-48; | ||
894 | if (ixx >= argc) { | ||
895 | var='\0'; | ||
896 | } else { | ||
897 | var = argv[ixx]; | ||
898 | } | ||
899 | } | ||
900 | break; | ||
901 | |||
902 | } | ||
903 | if (var) { | ||
904 | /* a single character construction was found, and | ||
905 | * already handled in the case statement */ | ||
906 | src=dst+2; | ||
907 | } else { | ||
908 | /* Looks like an environment variable */ | ||
909 | char delim_hold; | ||
910 | int num_skip_chars=0; | ||
911 | int dstlen = strlen(dst); | ||
912 | /* Is this a ${foo} type variable? */ | ||
913 | if (dstlen >=2 && *(dst+1) == '{') { | ||
914 | src=strchr(dst+1, '}'); | ||
915 | num_skip_chars=1; | ||
916 | } else { | ||
917 | src=dst+1; | ||
918 | while(isalnum(*src) || *src=='_') src++; | ||
919 | } | ||
920 | if (src == NULL) { | ||
921 | src = dst+dstlen; | ||
922 | } | ||
923 | delim_hold=*src; | ||
924 | *src='\0'; /* temporary */ | ||
925 | var = getenv(dst + 1 + num_skip_chars); | ||
926 | *src=delim_hold; | ||
927 | src += num_skip_chars; | ||
928 | } | ||
929 | if (var == NULL) { | ||
930 | /* Seems we got an un-expandable variable. So delete it. */ | ||
931 | var = ""; | ||
932 | } | ||
933 | { | ||
934 | int subst_len = strlen(var); | ||
935 | int trail_len = strlen(src); | ||
936 | if (dst+subst_len+trail_len >= command+BUFSIZ) { | ||
937 | error_msg(out_of_space); | ||
938 | return FALSE; | ||
939 | } | ||
940 | /* Move stuff to the end of the string to accommodate | ||
941 | * filling the created gap with the new stuff */ | ||
942 | memmove(dst+subst_len, src, trail_len+1); | ||
943 | /* Now copy in the new stuff */ | ||
944 | memcpy(dst, var, subst_len); | ||
945 | src = dst+subst_len; | ||
946 | } | ||
947 | } | ||
734 | 948 | ||
735 | return TRUE; | 949 | return TRUE; |
736 | } | 950 | } |
@@ -1078,6 +1292,7 @@ static void insert_job(struct job *newjob, int inbg) | |||
1078 | printf("[%d] %d\n", thejob->jobid, | 1292 | printf("[%d] %d\n", thejob->jobid, |
1079 | newjob->progs[newjob->num_progs - 1].pid); | 1293 | newjob->progs[newjob->num_progs - 1].pid); |
1080 | last_jobid = newjob->jobid; | 1294 | last_jobid = newjob->jobid; |
1295 | last_bg_pid=newjob->progs[newjob->num_progs - 1].pid; | ||
1081 | } else { | 1296 | } else { |
1082 | newjob->job_list->fg = thejob; | 1297 | newjob->job_list->fg = thejob; |
1083 | 1298 | ||
@@ -1250,6 +1465,8 @@ static int busy_loop(FILE * input) | |||
1250 | job_list.fg->running_progs--; | 1465 | job_list.fg->running_progs--; |
1251 | job_list.fg->progs[i].pid = 0; | 1466 | job_list.fg->progs[i].pid = 0; |
1252 | 1467 | ||
1468 | last_return_code=WEXITSTATUS(status); | ||
1469 | |||
1253 | if (!job_list.fg->running_progs) { | 1470 | if (!job_list.fg->running_progs) { |
1254 | /* child exited */ | 1471 | /* child exited */ |
1255 | remove_job(&job_list, job_list.fg); | 1472 | remove_job(&job_list, job_list.fg); |
@@ -1322,10 +1539,9 @@ static void setup_job_control() | |||
1322 | signal(SIGCHLD, SIG_IGN); | 1539 | signal(SIGCHLD, SIG_IGN); |
1323 | 1540 | ||
1324 | /* Put ourselves in our own process group. */ | 1541 | /* Put ourselves in our own process group. */ |
1542 | setsid(); | ||
1325 | shell_pgrp = getpid (); | 1543 | shell_pgrp = getpid (); |
1326 | if (setpgid (shell_pgrp, shell_pgrp) < 0) { | 1544 | setpgid (shell_pgrp, shell_pgrp); |
1327 | perror_msg_and_die("Couldn't put the shell in its own process group"); | ||
1328 | } | ||
1329 | 1545 | ||
1330 | /* Grab control of the terminal. */ | 1546 | /* Grab control of the terminal. */ |
1331 | tcsetpgrp(shell_terminal, shell_pgrp); | 1547 | tcsetpgrp(shell_terminal, shell_pgrp); |
@@ -1345,13 +1561,12 @@ int shell_main(int argc_l, char **argv_l) | |||
1345 | close_me_head = NULL; | 1561 | close_me_head = NULL; |
1346 | job_list.head = NULL; | 1562 | job_list.head = NULL; |
1347 | job_list.fg = NULL; | 1563 | job_list.fg = NULL; |
1564 | last_return_code=1; | ||
1348 | 1565 | ||
1349 | if (argv[0] && argv[0][0] == '-') { | 1566 | if (argv[0] && argv[0][0] == '-') { |
1350 | FILE *prof_input; | 1567 | FILE *prof_input; |
1351 | prof_input = fopen("/etc/profile", "r"); | 1568 | prof_input = fopen("/etc/profile", "r"); |
1352 | if (!prof_input) { | 1569 | if (prof_input) { |
1353 | printf( "Couldn't open file '/etc/profile'\n"); | ||
1354 | } else { | ||
1355 | int tmp_fd = fileno(prof_input); | 1570 | int tmp_fd = fileno(prof_input); |
1356 | mark_open(tmp_fd); | 1571 | mark_open(tmp_fd); |
1357 | /* Now run the file */ | 1572 | /* Now run the file */ |
@@ -1418,4 +1633,3 @@ int shell_main(int argc_l, char **argv_l) | |||
1418 | 1633 | ||
1419 | return (busy_loop(input)); | 1634 | return (busy_loop(input)); |
1420 | } | 1635 | } |
1421 | |||
diff --git a/shell/lash.c b/shell/lash.c index 68f673539..e4ca5f67b 100644 --- a/shell/lash.c +++ b/shell/lash.c | |||
@@ -135,6 +135,7 @@ static void mark_open(int fd); | |||
135 | static void mark_closed(int fd); | 135 | static void mark_closed(int fd); |
136 | static void close_all(void); | 136 | static void close_all(void); |
137 | static void checkjobs(struct jobset *job_list); | 137 | static void checkjobs(struct jobset *job_list); |
138 | static void remove_job(struct jobset *j_list, struct job *job); | ||
138 | static int get_command(FILE * source, char *command); | 139 | static int get_command(FILE * source, char *command); |
139 | static int parse_command(char **command_ptr, struct job *job, int *inbg); | 140 | static int parse_command(char **command_ptr, struct job *job, int *inbg); |
140 | static int run_command(struct job *newjob, int inbg, int outpipe[2]); | 141 | static int run_command(struct job *newjob, int inbg, int outpipe[2]); |
@@ -181,6 +182,8 @@ static struct jobset job_list = { NULL, NULL }; | |||
181 | static int argc; | 182 | static int argc; |
182 | static char **argv; | 183 | static char **argv; |
183 | static struct close_me *close_me_head; | 184 | static struct close_me *close_me_head; |
185 | static int last_return_code; | ||
186 | static int last_bg_pid; | ||
184 | static unsigned int last_jobid; | 187 | static unsigned int last_jobid; |
185 | static int shell_terminal; | 188 | static int shell_terminal; |
186 | static pid_t shell_pgrp; | 189 | static pid_t shell_pgrp; |
@@ -313,8 +316,12 @@ static int builtin_fg_bg(struct child_prog *child) | |||
313 | 316 | ||
314 | job->stopped_progs = 0; | 317 | job->stopped_progs = 0; |
315 | 318 | ||
316 | if (kill(- job->pgrp, SIGCONT) < 0) | 319 | if ( (i=kill(- job->pgrp, SIGCONT)) < 0) { |
320 | if (i == ESRCH) { | ||
321 | remove_job(&job_list, job); | ||
322 | } | ||
317 | perror_msg("kill (SIGCONT)"); | 323 | perror_msg("kill (SIGCONT)"); |
324 | } | ||
318 | 325 | ||
319 | return EXIT_SUCCESS; | 326 | return EXIT_SUCCESS; |
320 | } | 327 | } |
@@ -536,6 +543,11 @@ static void remove_job(struct jobset *j_list, struct job *job) | |||
536 | prevjob->next = job->next; | 543 | prevjob->next = job->next; |
537 | } | 544 | } |
538 | 545 | ||
546 | if (j_list->head) | ||
547 | last_jobid = j_list->head->jobid; | ||
548 | else | ||
549 | last_jobid = 0; | ||
550 | |||
539 | free(job); | 551 | free(job); |
540 | } | 552 | } |
541 | 553 | ||
@@ -576,10 +588,15 @@ static void checkjobs(struct jobset *j_list) | |||
576 | job->stopped_progs++; | 588 | job->stopped_progs++; |
577 | job->progs[prognum].is_stopped = 1; | 589 | job->progs[prognum].is_stopped = 1; |
578 | 590 | ||
591 | #if 0 | ||
592 | /* Printing this stuff is a pain, since it tends to | ||
593 | * overwrite the prompt an inconveinient moments. So | ||
594 | * don't do that. */ | ||
579 | if (job->stopped_progs == job->num_progs) { | 595 | if (job->stopped_progs == job->num_progs) { |
580 | printf(JOB_STATUS_FORMAT, job->jobid, "Stopped", | 596 | printf(JOB_STATUS_FORMAT, job->jobid, "Stopped", |
581 | job->text); | 597 | job->text); |
582 | } | 598 | } |
599 | #endif | ||
583 | } | 600 | } |
584 | } | 601 | } |
585 | 602 | ||
@@ -714,14 +731,78 @@ static int get_command(FILE * source, char *command) | |||
714 | return 0; | 731 | return 0; |
715 | } | 732 | } |
716 | 733 | ||
734 | static char* itoa(register int i) | ||
735 | { | ||
736 | static char a[7]; /* Max 7 ints */ | ||
737 | register char *b = a + sizeof(a) - 1; | ||
738 | int sign = (i < 0); | ||
739 | |||
740 | if (sign) | ||
741 | i = -i; | ||
742 | *b = 0; | ||
743 | do | ||
744 | { | ||
745 | *--b = '0' + (i % 10); | ||
746 | i /= 10; | ||
747 | } | ||
748 | while (i); | ||
749 | if (sign) | ||
750 | *--b = '-'; | ||
751 | return b; | ||
752 | } | ||
753 | |||
754 | char * strsep_space( char *string, int * ix) | ||
755 | { | ||
756 | char *token, *begin; | ||
757 | |||
758 | begin = string; | ||
759 | |||
760 | /* Short circuit the trivial case */ | ||
761 | if ( !string || ! string[*ix]) | ||
762 | return NULL; | ||
763 | |||
764 | /* Find the end of the token. */ | ||
765 | while( string && string[*ix] && !isspace(string[*ix]) ) { | ||
766 | (*ix)++; | ||
767 | } | ||
768 | |||
769 | /* Find the end of any whitespace trailing behind | ||
770 | * the token and let that be part of the token */ | ||
771 | while( string && string[*ix] && isspace(string[*ix]) ) { | ||
772 | (*ix)++; | ||
773 | } | ||
774 | |||
775 | if (! string && *ix==0) { | ||
776 | /* Nothing useful was found */ | ||
777 | return NULL; | ||
778 | } | ||
779 | |||
780 | token = xmalloc(*ix+1); | ||
781 | token[*ix] = '\0'; | ||
782 | strncpy(token, string, *ix); | ||
783 | |||
784 | return token; | ||
785 | } | ||
717 | 786 | ||
718 | static int expand_arguments(char *command) | 787 | static int expand_arguments(char *command) |
719 | { | 788 | { |
720 | int ix = 0; | 789 | int total_length=0, length, i, retval, ix = 0; |
790 | expand_t expand_result; | ||
791 | char *tmpcmd, *cmd, *cmd_copy; | ||
792 | char *src, *dst, *var; | ||
793 | const char *out_of_space = "out of space during expansion"; | ||
794 | int flags = GLOB_NOCHECK | ||
795 | #ifdef GLOB_BRACE | ||
796 | | GLOB_BRACE | ||
797 | #endif | ||
798 | #ifdef GLOB_TILDE | ||
799 | | GLOB_TILDE | ||
800 | #endif | ||
801 | ; | ||
721 | 802 | ||
722 | /* get rid of the terminating \n */ | 803 | /* get rid of the terminating \n */ |
723 | chomp(command); | 804 | chomp(command); |
724 | 805 | ||
725 | /* Fix up escape sequences to be the Real Thing(tm) */ | 806 | /* Fix up escape sequences to be the Real Thing(tm) */ |
726 | while( command && command[ix]) { | 807 | while( command && command[ix]) { |
727 | if (command[ix] == '\\') { | 808 | if (command[ix] == '\\') { |
@@ -731,6 +812,139 @@ static int expand_arguments(char *command) | |||
731 | } | 812 | } |
732 | ix++; | 813 | ix++; |
733 | } | 814 | } |
815 | /* Use glob and then fixup environment variables and such */ | ||
816 | |||
817 | /* It turns out that glob is very stupid. We have to feed it one word at a | ||
818 | * time since it can't cope with a full string. Here we convert command | ||
819 | * (char*) into cmd (char**, one word per string) */ | ||
820 | |||
821 | /* We need a clean copy, so strsep can mess up the copy while | ||
822 | * we write stuff into the original (in a minute) */ | ||
823 | cmd = cmd_copy = strdup(command); | ||
824 | *command = '\0'; | ||
825 | for (ix = 0, tmpcmd = cmd; | ||
826 | (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) { | ||
827 | if (*tmpcmd == '\0') | ||
828 | break; | ||
829 | /* we need to trim() the result for glob! */ | ||
830 | trim(tmpcmd); | ||
831 | retval = glob(tmpcmd, flags, NULL, &expand_result); | ||
832 | free(tmpcmd); /* Free mem allocated by strsep_space */ | ||
833 | if (retval == GLOB_NOSPACE) { | ||
834 | /* Mem may have been allocated... */ | ||
835 | globfree (&expand_result); | ||
836 | error_msg(out_of_space); | ||
837 | return FALSE; | ||
838 | } else if (retval != 0) { | ||
839 | /* Some other error. GLOB_NOMATCH shouldn't | ||
840 | * happen because of the GLOB_NOCHECK flag in | ||
841 | * the glob call. */ | ||
842 | error_msg("syntax error"); | ||
843 | return FALSE; | ||
844 | } else { | ||
845 | /* Convert from char** (one word per string) to a simple char*, | ||
846 | * but don't overflow command which is BUFSIZ in length */ | ||
847 | for (i=0; i < expand_result.gl_pathc; i++) { | ||
848 | length=strlen(expand_result.gl_pathv[i]); | ||
849 | if (total_length+length+1 >= BUFSIZ) { | ||
850 | error_msg(out_of_space); | ||
851 | return FALSE; | ||
852 | } | ||
853 | strcat(command+total_length, " "); | ||
854 | total_length+=1; | ||
855 | strcat(command+total_length, expand_result.gl_pathv[i]); | ||
856 | total_length+=length; | ||
857 | } | ||
858 | globfree (&expand_result); | ||
859 | } | ||
860 | } | ||
861 | free(cmd_copy); | ||
862 | trim(command); | ||
863 | |||
864 | /* Now do the shell variable substitutions which | ||
865 | * wordexp can't do for us, namely $? and $! */ | ||
866 | src = command; | ||
867 | while((dst = strchr(src,'$')) != NULL){ | ||
868 | var = NULL; | ||
869 | switch(*(dst+1)) { | ||
870 | case '?': | ||
871 | var = itoa(last_return_code); | ||
872 | break; | ||
873 | case '!': | ||
874 | if (last_bg_pid==-1) | ||
875 | *(var)='\0'; | ||
876 | else | ||
877 | var = itoa(last_bg_pid); | ||
878 | break; | ||
879 | /* Everything else like $$, $#, $[0-9], etc. should all be | ||
880 | * expanded by wordexp(), so we can in theory skip that stuff | ||
881 | * here, but just to be on the safe side (i.e., since uClibc | ||
882 | * wordexp doesn't do this stuff yet), lets leave it in for | ||
883 | * now. */ | ||
884 | case '$': | ||
885 | var = itoa(getpid()); | ||
886 | break; | ||
887 | case '#': | ||
888 | var = itoa(argc-1); | ||
889 | break; | ||
890 | case '0':case '1':case '2':case '3':case '4': | ||
891 | case '5':case '6':case '7':case '8':case '9': | ||
892 | { | ||
893 | int ixx=*(dst + 1)-48; | ||
894 | if (ixx >= argc) { | ||
895 | var='\0'; | ||
896 | } else { | ||
897 | var = argv[ixx]; | ||
898 | } | ||
899 | } | ||
900 | break; | ||
901 | |||
902 | } | ||
903 | if (var) { | ||
904 | /* a single character construction was found, and | ||
905 | * already handled in the case statement */ | ||
906 | src=dst+2; | ||
907 | } else { | ||
908 | /* Looks like an environment variable */ | ||
909 | char delim_hold; | ||
910 | int num_skip_chars=0; | ||
911 | int dstlen = strlen(dst); | ||
912 | /* Is this a ${foo} type variable? */ | ||
913 | if (dstlen >=2 && *(dst+1) == '{') { | ||
914 | src=strchr(dst+1, '}'); | ||
915 | num_skip_chars=1; | ||
916 | } else { | ||
917 | src=dst+1; | ||
918 | while(isalnum(*src) || *src=='_') src++; | ||
919 | } | ||
920 | if (src == NULL) { | ||
921 | src = dst+dstlen; | ||
922 | } | ||
923 | delim_hold=*src; | ||
924 | *src='\0'; /* temporary */ | ||
925 | var = getenv(dst + 1 + num_skip_chars); | ||
926 | *src=delim_hold; | ||
927 | src += num_skip_chars; | ||
928 | } | ||
929 | if (var == NULL) { | ||
930 | /* Seems we got an un-expandable variable. So delete it. */ | ||
931 | var = ""; | ||
932 | } | ||
933 | { | ||
934 | int subst_len = strlen(var); | ||
935 | int trail_len = strlen(src); | ||
936 | if (dst+subst_len+trail_len >= command+BUFSIZ) { | ||
937 | error_msg(out_of_space); | ||
938 | return FALSE; | ||
939 | } | ||
940 | /* Move stuff to the end of the string to accommodate | ||
941 | * filling the created gap with the new stuff */ | ||
942 | memmove(dst+subst_len, src, trail_len+1); | ||
943 | /* Now copy in the new stuff */ | ||
944 | memcpy(dst, var, subst_len); | ||
945 | src = dst+subst_len; | ||
946 | } | ||
947 | } | ||
734 | 948 | ||
735 | return TRUE; | 949 | return TRUE; |
736 | } | 950 | } |
@@ -1078,6 +1292,7 @@ static void insert_job(struct job *newjob, int inbg) | |||
1078 | printf("[%d] %d\n", thejob->jobid, | 1292 | printf("[%d] %d\n", thejob->jobid, |
1079 | newjob->progs[newjob->num_progs - 1].pid); | 1293 | newjob->progs[newjob->num_progs - 1].pid); |
1080 | last_jobid = newjob->jobid; | 1294 | last_jobid = newjob->jobid; |
1295 | last_bg_pid=newjob->progs[newjob->num_progs - 1].pid; | ||
1081 | } else { | 1296 | } else { |
1082 | newjob->job_list->fg = thejob; | 1297 | newjob->job_list->fg = thejob; |
1083 | 1298 | ||
@@ -1250,6 +1465,8 @@ static int busy_loop(FILE * input) | |||
1250 | job_list.fg->running_progs--; | 1465 | job_list.fg->running_progs--; |
1251 | job_list.fg->progs[i].pid = 0; | 1466 | job_list.fg->progs[i].pid = 0; |
1252 | 1467 | ||
1468 | last_return_code=WEXITSTATUS(status); | ||
1469 | |||
1253 | if (!job_list.fg->running_progs) { | 1470 | if (!job_list.fg->running_progs) { |
1254 | /* child exited */ | 1471 | /* child exited */ |
1255 | remove_job(&job_list, job_list.fg); | 1472 | remove_job(&job_list, job_list.fg); |
@@ -1322,10 +1539,9 @@ static void setup_job_control() | |||
1322 | signal(SIGCHLD, SIG_IGN); | 1539 | signal(SIGCHLD, SIG_IGN); |
1323 | 1540 | ||
1324 | /* Put ourselves in our own process group. */ | 1541 | /* Put ourselves in our own process group. */ |
1542 | setsid(); | ||
1325 | shell_pgrp = getpid (); | 1543 | shell_pgrp = getpid (); |
1326 | if (setpgid (shell_pgrp, shell_pgrp) < 0) { | 1544 | setpgid (shell_pgrp, shell_pgrp); |
1327 | perror_msg_and_die("Couldn't put the shell in its own process group"); | ||
1328 | } | ||
1329 | 1545 | ||
1330 | /* Grab control of the terminal. */ | 1546 | /* Grab control of the terminal. */ |
1331 | tcsetpgrp(shell_terminal, shell_pgrp); | 1547 | tcsetpgrp(shell_terminal, shell_pgrp); |
@@ -1345,13 +1561,12 @@ int shell_main(int argc_l, char **argv_l) | |||
1345 | close_me_head = NULL; | 1561 | close_me_head = NULL; |
1346 | job_list.head = NULL; | 1562 | job_list.head = NULL; |
1347 | job_list.fg = NULL; | 1563 | job_list.fg = NULL; |
1564 | last_return_code=1; | ||
1348 | 1565 | ||
1349 | if (argv[0] && argv[0][0] == '-') { | 1566 | if (argv[0] && argv[0][0] == '-') { |
1350 | FILE *prof_input; | 1567 | FILE *prof_input; |
1351 | prof_input = fopen("/etc/profile", "r"); | 1568 | prof_input = fopen("/etc/profile", "r"); |
1352 | if (!prof_input) { | 1569 | if (prof_input) { |
1353 | printf( "Couldn't open file '/etc/profile'\n"); | ||
1354 | } else { | ||
1355 | int tmp_fd = fileno(prof_input); | 1570 | int tmp_fd = fileno(prof_input); |
1356 | mark_open(tmp_fd); | 1571 | mark_open(tmp_fd); |
1357 | /* Now run the file */ | 1572 | /* Now run the file */ |
@@ -1418,4 +1633,3 @@ int shell_main(int argc_l, char **argv_l) | |||
1418 | 1633 | ||
1419 | return (busy_loop(input)); | 1634 | return (busy_loop(input)); |
1420 | } | 1635 | } |
1421 | |||