diff options
| -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 | |||
