summaryrefslogtreecommitdiff
path: root/shell/lash.c
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-06-27 04:30:11 +0000
committerEric Andersen <andersen@codepoet.org>2001-06-27 04:30:11 +0000
commit4b6b5e4314e6b760bdc0cf51dfb1f01896f3b6d0 (patch)
treed058a44b529547cdb550f198428549d9669efa1b /shell/lash.c
parent5c66d06104db468908598d276062fc50f542a17a (diff)
downloadbusybox-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
Diffstat (limited to '')
-rw-r--r--shell/lash.c234
1 files changed, 224 insertions, 10 deletions
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);
135static void mark_closed(int fd); 135static void mark_closed(int fd);
136static void close_all(void); 136static void close_all(void);
137static void checkjobs(struct jobset *job_list); 137static void checkjobs(struct jobset *job_list);
138static void remove_job(struct jobset *j_list, struct job *job);
138static int get_command(FILE * source, char *command); 139static int get_command(FILE * source, char *command);
139static int parse_command(char **command_ptr, struct job *job, int *inbg); 140static int parse_command(char **command_ptr, struct job *job, int *inbg);
140static int run_command(struct job *newjob, int inbg, int outpipe[2]); 141static int run_command(struct job *newjob, int inbg, int outpipe[2]);
@@ -181,6 +182,8 @@ static struct jobset job_list = { NULL, NULL };
181static int argc; 182static int argc;
182static char **argv; 183static char **argv;
183static struct close_me *close_me_head; 184static struct close_me *close_me_head;
185static int last_return_code;
186static int last_bg_pid;
184static unsigned int last_jobid; 187static unsigned int last_jobid;
185static int shell_terminal; 188static int shell_terminal;
186static pid_t shell_pgrp; 189static 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
734static 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
754char * 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
718static int expand_arguments(char *command) 787static 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