source: MondoRescue/branches/stable/mindi-busybox/shell/lash.c@ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 18 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 39.9 KB
RevLine 
[821]1/* vi: set sw=4 ts=4: */
2/*
3 * lash -- the BusyBox Lame-Ass SHell
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is
8 * under the following liberal license: "We have placed this source code in the
9 * public domain. Use it in any project, free or commercial."
10 *
11 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
12 */
13
14/* This shell's parsing engine is officially at a dead-end. Future
15 * work shell work should be done using hush, msh, or ash. This is
16 * still a very useful, small shell -- it just don't need any more
17 * features beyond what it already has...
18 */
19
20//For debugging/development on the shell only...
21//#define DEBUG_SHELL
22
23
24#include "busybox.h"
25#include <stdio.h>
26#include <stdlib.h>
27#include <ctype.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <signal.h>
31#include <string.h>
32#include <sys/ioctl.h>
33#include <sys/wait.h>
34#include <unistd.h>
35#include <getopt.h>
36#include <termios.h>
37#include "cmdedit.h"
38
39#ifdef CONFIG_LOCALE_SUPPORT
40#include <locale.h>
41#endif
42
43#include <glob.h>
44#define expand_t glob_t
45
46/* Always enable for the moment... */
47#define CONFIG_LASH_PIPE_N_REDIRECTS
48#define CONFIG_LASH_JOB_CONTROL
49
50static const int MAX_READ = 128; /* size of input buffer for `read' builtin */
51#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
52
53
54#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
55enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
56 REDIRECT_APPEND
57};
58#endif
59
60enum {
61 DEFAULT_CONTEXT = 0x1,
62 IF_TRUE_CONTEXT = 0x2,
63 IF_FALSE_CONTEXT = 0x4,
64 THEN_EXP_CONTEXT = 0x8,
65 ELSE_EXP_CONTEXT = 0x10
66};
67
68#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
69struct redir_struct {
70 enum redir_type type; /* type of redirection */
71 int fd; /* file descriptor being redirected */
72 char *filename; /* file to redirect fd to */
73};
74#endif
75
76struct child_prog {
77 pid_t pid; /* 0 if exited */
78 char **argv; /* program name and arguments */
79 int num_redirects; /* elements in redirection array */
80 int is_stopped; /* is the program currently running? */
81 struct job *family; /* pointer back to the child's parent job */
82#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
83 struct redir_struct *redirects; /* I/O redirects */
84#endif
85};
86
87struct jobset {
88 struct job *head; /* head of list of running jobs */
89 struct job *fg; /* current foreground job */
90};
91
92struct job {
93 int jobid; /* job number */
94 int num_progs; /* total number of programs in job */
95 int running_progs; /* number of programs running */
96 char *text; /* name of job */
97 char *cmdbuf; /* buffer various argv's point into */
98 pid_t pgrp; /* process group ID for the job */
99 struct child_prog *progs; /* array of programs in job */
100 struct job *next; /* to track background commands */
101 int stopped_progs; /* number of programs alive, but stopped */
102 unsigned int job_context; /* bitmask defining current context */
103 struct jobset *job_list;
104};
105
106struct built_in_command {
107 char *cmd; /* name */
108 char *descr; /* description */
109 int (*function) (struct child_prog *); /* function ptr */
110};
111
112/* function prototypes for builtins */
113static int builtin_cd(struct child_prog *cmd);
114static int builtin_exec(struct child_prog *cmd);
115static int builtin_exit(struct child_prog *cmd);
116static int builtin_fg_bg(struct child_prog *cmd);
117static int builtin_help(struct child_prog *cmd);
118static int builtin_jobs(struct child_prog *dummy);
119static int builtin_pwd(struct child_prog *dummy);
120static int builtin_export(struct child_prog *cmd);
121static int builtin_source(struct child_prog *cmd);
122static int builtin_unset(struct child_prog *cmd);
123static int builtin_read(struct child_prog *cmd);
124
125
126/* function prototypes for shell stuff */
127static void checkjobs(struct jobset *job_list);
128static void remove_job(struct jobset *j_list, struct job *job);
129static int get_command(FILE * source, char *command);
130static int parse_command(char **command_ptr, struct job *job, int *inbg);
131static int run_command(struct job *newjob, int inbg, int outpipe[2]);
132static int pseudo_exec(struct child_prog *cmd) ATTRIBUTE_NORETURN;
133static int busy_loop(FILE * input);
134
135
136/* Table of built-in functions (these are non-forking builtins, meaning they
137 * can change global variables in the parent shell process but they will not
138 * work with pipes and redirects; 'unset foo | whatever' will not work) */
139static struct built_in_command bltins[] = {
140 {"bg", "Resume a job in the background", builtin_fg_bg},
141 {"cd", "Change working directory", builtin_cd},
142 {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
143 {"exit", "Exit from shell()", builtin_exit},
144 {"fg", "Bring job into the foreground", builtin_fg_bg},
145 {"jobs", "Lists the active jobs", builtin_jobs},
146 {"export", "Set environment variable", builtin_export},
147 {"unset", "Unset environment variable", builtin_unset},
148 {"read", "Input environment variable", builtin_read},
149 {".", "Source-in and run commands in a file", builtin_source},
150 /* to do: add ulimit */
151 {NULL, NULL, NULL}
152};
153
154/* Table of forking built-in functions (things that fork cannot change global
155 * variables in the parent process, such as the current working directory) */
156static struct built_in_command bltins_forking[] = {
157 {"pwd", "Print current directory", builtin_pwd},
158 {"help", "List shell built-in commands", builtin_help},
159 {NULL, NULL, NULL}
160};
161
162
163static int shell_context; /* Type prompt trigger (PS1 or PS2) */
164
165
166/* Globals that are static to this file */
167static const char *cwd;
168static char *local_pending_command = NULL;
169static struct jobset job_list = { NULL, NULL };
170static int argc;
171static char **argv;
172static llist_t *close_me_list;
173static int last_return_code;
174static int last_bg_pid;
175static unsigned int last_jobid;
176static int shell_terminal;
177static char *PS1;
178static char *PS2 = "> ";
179
180
181#ifdef DEBUG_SHELL
182static inline void debug_printf(const char *format, ...)
183{
184 va_list args;
185 va_start(args, format);
186 vfprintf(stderr, format, args);
187 va_end(args);
188}
189#else
190static inline void debug_printf(const char *format, ...) { }
191#endif
192
193/*
194 Most builtins need access to the struct child_prog that has
195 their arguments, previously coded as cmd->progs[0]. That coding
196 can exhibit a bug, if the builtin is not the first command in
197 a pipeline: "echo foo | exec sort" will attempt to exec foo.
198
199builtin previous use notes
200------ ----------------- ---------
201cd cmd->progs[0]
202exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins
203exit cmd->progs[0]
204fg_bg cmd->progs[0], job_list->head, job_list->fg
205help 0
206jobs job_list->head
207pwd 0
208export cmd->progs[0]
209source cmd->progs[0]
210unset cmd->progs[0]
211read cmd->progs[0]
212
213I added "struct job *family;" to struct child_prog,
214and switched API to builtin_foo(struct child_prog *child);
215So cmd->text becomes child->family->text
216 cmd->job_context becomes child->family->job_context
217 cmd->progs[0] becomes *child
218 job_list becomes child->family->job_list
219 */
220
221/* built-in 'cd <path>' handler */
222static int builtin_cd(struct child_prog *child)
223{
224 char *newdir;
225
226 if (child->argv[1] == NULL)
227 newdir = getenv("HOME");
228 else
229 newdir = child->argv[1];
230 if (chdir(newdir)) {
231 bb_perror_msg("cd: %s", newdir);
232 return EXIT_FAILURE;
233 }
234 cwd = xgetcwd((char *)cwd);
235 if (!cwd)
236 cwd = bb_msg_unknown;
237 return EXIT_SUCCESS;
238}
239
240/* built-in 'exec' handler */
241static int builtin_exec(struct child_prog *child)
242{
243 if (child->argv[1] == NULL)
244 return EXIT_SUCCESS; /* Really? */
245 child->argv++;
246 while(close_me_list) close((long)llist_pop(&close_me_list));
247 pseudo_exec(child);
248 /* never returns */
249}
250
251/* built-in 'exit' handler */
252static int builtin_exit(struct child_prog *child)
253{
254 if (child->argv[1] == NULL)
255 exit(EXIT_SUCCESS);
256
257 exit (atoi(child->argv[1]));
258}
259
260/* built-in 'fg' and 'bg' handler */
261static int builtin_fg_bg(struct child_prog *child)
262{
263 int i, jobnum;
264 struct job *job=NULL;
265
266 /* If they gave us no args, assume they want the last backgrounded task */
267 if (!child->argv[1]) {
268 for (job = child->family->job_list->head; job; job = job->next) {
269 if (job->jobid == last_jobid) {
270 break;
271 }
272 }
273 if (!job) {
274 bb_error_msg("%s: no current job", child->argv[0]);
275 return EXIT_FAILURE;
276 }
277 } else {
278 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
279 bb_error_msg(bb_msg_invalid_arg, child->argv[1], child->argv[0]);
280 return EXIT_FAILURE;
281 }
282 for (job = child->family->job_list->head; job; job = job->next) {
283 if (job->jobid == jobnum) {
284 break;
285 }
286 }
287 if (!job) {
288 bb_error_msg("%s: %d: no such job", child->argv[0], jobnum);
289 return EXIT_FAILURE;
290 }
291 }
292
293 if (*child->argv[0] == 'f') {
294 /* Put the job into the foreground. */
295 tcsetpgrp(shell_terminal, job->pgrp);
296
297 child->family->job_list->fg = job;
298 }
299
300 /* Restart the processes in the job */
301 for (i = 0; i < job->num_progs; i++)
302 job->progs[i].is_stopped = 0;
303
304 job->stopped_progs = 0;
305
306 if ( (i=kill(- job->pgrp, SIGCONT)) < 0) {
307 if (i == ESRCH) {
308 remove_job(&job_list, job);
309 } else {
310 bb_perror_msg("kill (SIGCONT)");
311 }
312 }
313
314 return EXIT_SUCCESS;
315}
316
317/* built-in 'help' handler */
318static int builtin_help(struct child_prog *dummy)
319{
320 struct built_in_command *x;
321
322 printf("\nBuilt-in commands:\n");
323 printf("-------------------\n");
324 for (x = bltins; x->cmd; x++) {
325 if (x->descr==NULL)
326 continue;
327 printf("%s\t%s\n", x->cmd, x->descr);
328 }
329 for (x = bltins_forking; x->cmd; x++) {
330 if (x->descr==NULL)
331 continue;
332 printf("%s\t%s\n", x->cmd, x->descr);
333 }
334 printf("\n\n");
335 return EXIT_SUCCESS;
336}
337
338/* built-in 'jobs' handler */
339static int builtin_jobs(struct child_prog *child)
340{
341 struct job *job;
342 char *status_string;
343
344 for (job = child->family->job_list->head; job; job = job->next) {
345 if (job->running_progs == job->stopped_progs)
346 status_string = "Stopped";
347 else
348 status_string = "Running";
349
350 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
351 }
352 return EXIT_SUCCESS;
353}
354
355
356/* built-in 'pwd' handler */
357static int builtin_pwd(struct child_prog *dummy)
358{
359 cwd = xgetcwd((char *)cwd);
360 if (!cwd)
361 cwd = bb_msg_unknown;
362 puts(cwd);
363 return EXIT_SUCCESS;
364}
365
366/* built-in 'export VAR=value' handler */
367static int builtin_export(struct child_prog *child)
368{
369 int res;
370 char *v = child->argv[1];
371
372 if (v == NULL) {
373 char **e;
374 for (e = environ; *e; e++) {
375 puts(*e);
376 }
377 return 0;
378 }
379 res = putenv(v);
380 if (res)
381 bb_perror_msg("export");
382#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
383 if (strncmp(v, "PS1=", 4)==0)
384 PS1 = getenv("PS1");
385#endif
386
387#ifdef CONFIG_LOCALE_SUPPORT
388 if(strncmp(v, "LC_ALL=", 7)==0)
389 setlocale(LC_ALL, getenv("LC_ALL"));
390 if(strncmp(v, "LC_CTYPE=", 9)==0)
391 setlocale(LC_CTYPE, getenv("LC_CTYPE"));
392#endif
393
394 return (res);
395}
396
397/* built-in 'read VAR' handler */
398static int builtin_read(struct child_prog *child)
399{
400 int res = 0, len, newlen;
401 char *s;
402 char string[MAX_READ];
403
404 if (child->argv[1]) {
405 /* argument (VAR) given: put "VAR=" into buffer */
406 safe_strncpy(string, child->argv[1], MAX_READ-1);
407 len = strlen(string);
408 string[len++] = '=';
409 string[len] = '\0';
410 fgets(&string[len], sizeof(string) - len, stdin); /* read string */
411 newlen = strlen(string);
412 if(newlen > len)
413 string[--newlen] = '\0'; /* chomp trailing newline */
414 /*
415 ** string should now contain "VAR=<value>"
416 ** copy it (putenv() won't do that, so we must make sure
417 ** the string resides in a static buffer!)
418 */
419 res = -1;
420 if((s = strdup(string)))
421 res = putenv(s);
422 if (res)
423 bb_perror_msg("read");
424 }
425 else
426 fgets(string, sizeof(string), stdin);
427
428 return (res);
429}
430
431/* Built-in '.' handler (read-in and execute commands from file) */
432static int builtin_source(struct child_prog *child)
433{
434 FILE *input;
435 int status;
436
437 if (child->argv[1] == NULL)
438 return EXIT_FAILURE;
439
440 input = fopen(child->argv[1], "r");
441 if (!input) {
442 printf( "Couldn't open file '%s'\n", child->argv[1]);
443 return EXIT_FAILURE;
444 }
445
446 llist_add_to(&close_me_list, (void *)(long)fileno(input));
447 /* Now run the file */
448 status = busy_loop(input);
449 fclose(input);
450 llist_pop(&close_me_list);
451 return (status);
452}
453
454/* built-in 'unset VAR' handler */
455static int builtin_unset(struct child_prog *child)
456{
457 if (child->argv[1] == NULL) {
458 printf(bb_msg_requires_arg, "unset");
459 return EXIT_FAILURE;
460 }
461 unsetenv(child->argv[1]);
462 return EXIT_SUCCESS;
463}
464
465#ifdef CONFIG_LASH_JOB_CONTROL
466/* free up all memory from a job */
467static void free_job(struct job *cmd)
468{
469 int i;
470 struct jobset *keep;
471
472 for (i = 0; i < cmd->num_progs; i++) {
473 free(cmd->progs[i].argv);
474#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
475 if (cmd->progs[i].redirects)
476 free(cmd->progs[i].redirects);
477#endif
478 }
479 free(cmd->progs);
480 free(cmd->text);
481 free(cmd->cmdbuf);
482 keep = cmd->job_list;
483 memset(cmd, 0, sizeof(struct job));
484 cmd->job_list = keep;
485}
486
487/* remove a job from a jobset */
488static void remove_job(struct jobset *j_list, struct job *job)
489{
490 struct job *prevjob;
491
492 free_job(job);
493 if (job == j_list->head) {
494 j_list->head = job->next;
495 } else {
496 prevjob = j_list->head;
497 while (prevjob->next != job)
498 prevjob = prevjob->next;
499 prevjob->next = job->next;
500 }
501
502 if (j_list->head)
503 last_jobid = j_list->head->jobid;
504 else
505 last_jobid = 0;
506
507 free(job);
508}
509
510/* Checks to see if any background processes have exited -- if they
511 have, figure out why and see if a job has completed */
512static void checkjobs(struct jobset *j_list)
513{
514 struct job *job;
515 pid_t childpid;
516 int status;
517 int prognum = 0;
518
519 while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
520 for (job = j_list->head; job; job = job->next) {
521 prognum = 0;
522 while (prognum < job->num_progs &&
523 job->progs[prognum].pid != childpid) prognum++;
524 if (prognum < job->num_progs)
525 break;
526 }
527
528 /* This happens on backticked commands */
529 if(job==NULL)
530 return;
531
532 if (WIFEXITED(status) || WIFSIGNALED(status)) {
533 /* child exited */
534 job->running_progs--;
535 job->progs[prognum].pid = 0;
536
537 if (!job->running_progs) {
538 printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text);
539 last_jobid=0;
540 remove_job(j_list, job);
541 }
542 } else {
543 /* child stopped */
544 job->stopped_progs++;
545 job->progs[prognum].is_stopped = 1;
546
547#if 0
548 /* Printing this stuff is a pain, since it tends to
549 * overwrite the prompt an inconveinient moments. So
550 * don't do that. */
551 if (job->stopped_progs == job->num_progs) {
552 printf(JOB_STATUS_FORMAT, job->jobid, "Stopped",
553 job->text);
554 }
555#endif
556 }
557 }
558
559 if (childpid == -1 && errno != ECHILD)
560 bb_perror_msg("waitpid");
561}
562#else
563static void checkjobs(struct jobset *j_list)
564{
565}
566static void free_job(struct job *cmd)
567{
568}
569static void remove_job(struct jobset *j_list, struct job *job)
570{
571}
572#endif
573
574#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
575/* squirrel != NULL means we squirrel away copies of stdin, stdout,
576 * and stderr if they are redirected. */
577static int setup_redirects(struct child_prog *prog, int squirrel[])
578{
579 int i;
580 int openfd;
581 int mode = O_RDONLY;
582 struct redir_struct *redir = prog->redirects;
583
584 for (i = 0; i < prog->num_redirects; i++, redir++) {
585 switch (redir->type) {
586 case REDIRECT_INPUT:
587 mode = O_RDONLY;
588 break;
589 case REDIRECT_OVERWRITE:
590 mode = O_WRONLY | O_CREAT | O_TRUNC;
591 break;
592 case REDIRECT_APPEND:
593 mode = O_WRONLY | O_CREAT | O_APPEND;
594 break;
595 }
596
597 openfd = open(redir->filename, mode, 0666);
598 if (openfd < 0) {
599 /* this could get lost if stderr has been redirected, but
600 bash and ash both lose it as well (though zsh doesn't!) */
601 bb_perror_msg("error opening %s", redir->filename);
602 return 1;
603 }
604
605 if (openfd != redir->fd) {
606 if (squirrel && redir->fd < 3) {
607 squirrel[redir->fd] = dup(redir->fd);
608 fcntl (squirrel[redir->fd], F_SETFD, FD_CLOEXEC);
609 }
610 dup2(openfd, redir->fd);
611 close(openfd);
612 }
613 }
614
615 return 0;
616}
617
618static void restore_redirects(int squirrel[])
619{
620 int i, fd;
621 for (i=0; i<3; i++) {
622 fd = squirrel[i];
623 if (fd != -1) {
624 /* No error checking. I sure wouldn't know what
625 * to do with an error if I found one! */
626 dup2(fd, i);
627 close(fd);
628 }
629 }
630}
631#else
632static inline int setup_redirects(struct child_prog *prog, int squirrel[])
633{
634 return 0;
635}
636static inline void restore_redirects(int squirrel[])
637{
638}
639#endif
640
641static inline void cmdedit_set_initial_prompt(void)
642{
643#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
644 PS1 = NULL;
645#else
646 PS1 = getenv("PS1");
647 if(PS1==0)
648 PS1 = "\\w \\$ ";
649#endif
650}
651
652static inline void setup_prompt_string(char **prompt_str)
653{
654#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
655 /* Set up the prompt */
656 if (shell_context == 0) {
657 free(PS1);
658 PS1=xmalloc(strlen(cwd)+4);
659 sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# ");
660 *prompt_str = PS1;
661 } else {
662 *prompt_str = PS2;
663 }
664#else
665 *prompt_str = (shell_context==0)? PS1 : PS2;
666#endif
667}
668
669static int get_command(FILE * source, char *command)
670{
671 char *prompt_str;
672
673 if (source == NULL) {
674 if (local_pending_command) {
675 /* a command specified (-c option): return it & mark it done */
676 strcpy(command, local_pending_command);
677 free(local_pending_command);
678 local_pending_command = NULL;
679 return 0;
680 }
681 return 1;
682 }
683
684 if (source == stdin) {
685 setup_prompt_string(&prompt_str);
686
687#ifdef CONFIG_FEATURE_COMMAND_EDITING
688 /*
689 ** enable command line editing only while a command line
690 ** is actually being read; otherwise, we'll end up bequeathing
691 ** atexit() handlers and other unwanted stuff to our
692 ** child processes (rob@sysgo.de)
693 */
694 cmdedit_read_input(prompt_str, command);
695 return 0;
696#else
697 fputs(prompt_str, stdout);
698#endif
699 }
700
701 if (!fgets(command, BUFSIZ - 2, source)) {
702 if (source == stdin)
703 printf("\n");
704 return 1;
705 }
706
707 return 0;
708}
709
710static char* itoa(register int i)
711{
712 static char a[7]; /* Max 7 ints */
713 register char *b = a + sizeof(a) - 1;
714 int sign = (i < 0);
715
716 if (sign)
717 i = -i;
718 *b = 0;
719 do
720 {
721 *--b = '0' + (i % 10);
722 i /= 10;
723 }
724 while (i);
725 if (sign)
726 *--b = '-';
727 return b;
728}
729
730static char * strsep_space( char *string, int * ix)
731{
732 char *token;
733
734 /* Short circuit the trivial case */
735 if ( !string || ! string[*ix])
736 return NULL;
737
738 /* Find the end of the token. */
739 while( string[*ix] && !isspace(string[*ix]) ) {
740 (*ix)++;
741 }
742
743 /* Find the end of any whitespace trailing behind
744 * the token and let that be part of the token */
745 while( string[*ix] && isspace(string[*ix]) ) {
746 (*ix)++;
747 }
748
749 if (!*ix) {
750 /* Nothing useful was found */
751 return NULL;
752 }
753
754 token = bb_xstrndup(string, *ix);
755
756 return token;
757}
758
759static int expand_arguments(char *command)
760{
761 int total_length=0, length, i, retval, ix = 0;
762 expand_t expand_result;
763 char *tmpcmd, *cmd, *cmd_copy;
764 char *src, *dst, *var;
765 const char *out_of_space = "out of space during expansion";
766 int flags = GLOB_NOCHECK
767#ifdef GLOB_BRACE
768 | GLOB_BRACE
769#endif
770#ifdef GLOB_TILDE
771 | GLOB_TILDE
772#endif
773 ;
774
775 /* get rid of the terminating \n */
776 chomp(command);
777
778 /* Fix up escape sequences to be the Real Thing(tm) */
779 while( command && command[ix]) {
780 if (command[ix] == '\\') {
781 const char *tmp = command+ix+1;
782 command[ix] = bb_process_escape_sequence( &tmp );
783 memmove(command+ix + 1, tmp, strlen(tmp)+1);
784 }
785 ix++;
786 }
787 /* Use glob and then fixup environment variables and such */
788
789 /* It turns out that glob is very stupid. We have to feed it one word at a
790 * time since it can't cope with a full string. Here we convert command
791 * (char*) into cmd (char**, one word per string) */
792
793 /* We need a clean copy, so strsep can mess up the copy while
794 * we write stuff into the original (in a minute) */
795 cmd = cmd_copy = bb_xstrdup(command);
796 *command = '\0';
797 for (ix = 0, tmpcmd = cmd;
798 (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) {
799 if (*tmpcmd == '\0')
800 break;
801 /* we need to trim() the result for glob! */
802 trim(tmpcmd);
803 retval = glob(tmpcmd, flags, NULL, &expand_result);
804 free(tmpcmd); /* Free mem allocated by strsep_space */
805 if (retval == GLOB_NOSPACE) {
806 /* Mem may have been allocated... */
807 globfree (&expand_result);
808 bb_error_msg(out_of_space);
809 return FALSE;
810 } else if (retval != 0) {
811 /* Some other error. GLOB_NOMATCH shouldn't
812 * happen because of the GLOB_NOCHECK flag in
813 * the glob call. */
814 bb_error_msg("syntax error");
815 return FALSE;
816 } else {
817 /* Convert from char** (one word per string) to a simple char*,
818 * but don't overflow command which is BUFSIZ in length */
819 for (i=0; i < expand_result.gl_pathc; i++) {
820 length=strlen(expand_result.gl_pathv[i]);
821 if (total_length+length+1 >= BUFSIZ) {
822 bb_error_msg(out_of_space);
823 return FALSE;
824 }
825 strcat(command+total_length, " ");
826 total_length+=1;
827 strcat(command+total_length, expand_result.gl_pathv[i]);
828 total_length+=length;
829 }
830 globfree (&expand_result);
831 }
832 }
833 free(cmd_copy);
834 trim(command);
835
836 /* Now do the shell variable substitutions which
837 * wordexp can't do for us, namely $? and $! */
838 src = command;
839 while((dst = strchr(src,'$')) != NULL){
840 var = NULL;
841 switch(*(dst+1)) {
842 case '?':
843 var = itoa(last_return_code);
844 break;
845 case '!':
846 if (last_bg_pid==-1)
847 *(var)='\0';
848 else
849 var = itoa(last_bg_pid);
850 break;
851 /* Everything else like $$, $#, $[0-9], etc. should all be
852 * expanded by wordexp(), so we can in theory skip that stuff
853 * here, but just to be on the safe side (i.e., since uClibc
854 * wordexp doesn't do this stuff yet), lets leave it in for
855 * now. */
856 case '$':
857 var = itoa(getpid());
858 break;
859 case '#':
860 var = itoa(argc-1);
861 break;
862 case '0':case '1':case '2':case '3':case '4':
863 case '5':case '6':case '7':case '8':case '9':
864 {
865 int ixx=*(dst+1)-48+1;
866 if (ixx >= argc) {
867 var='\0';
868 } else {
869 var = argv[ixx];
870 }
871 }
872 break;
873
874 }
875 if (var) {
876 /* a single character construction was found, and
877 * already handled in the case statement */
878 src=dst+2;
879 } else {
880 /* Looks like an environment variable */
881 char delim_hold;
882 int num_skip_chars=0;
883 int dstlen = strlen(dst);
884 /* Is this a ${foo} type variable? */
885 if (dstlen >=2 && *(dst+1) == '{') {
886 src=strchr(dst+1, '}');
887 num_skip_chars=1;
888 } else {
889 src=dst+1;
890 while(isalnum(*src) || *src=='_') src++;
891 }
892 if (src == NULL) {
893 src = dst+dstlen;
894 }
895 delim_hold=*src;
896 *src='\0'; /* temporary */
897 var = getenv(dst + 1 + num_skip_chars);
898 *src=delim_hold;
899 src += num_skip_chars;
900 }
901 if (var == NULL) {
902 /* Seems we got an un-expandable variable. So delete it. */
903 var = "";
904 }
905 {
906 int subst_len = strlen(var);
907 int trail_len = strlen(src);
908 if (dst+subst_len+trail_len >= command+BUFSIZ) {
909 bb_error_msg(out_of_space);
910 return FALSE;
911 }
912 /* Move stuff to the end of the string to accommodate
913 * filling the created gap with the new stuff */
914 memmove(dst+subst_len, src, trail_len+1);
915 /* Now copy in the new stuff */
916 memcpy(dst, var, subst_len);
917 src = dst+subst_len;
918 }
919 }
920
921 return TRUE;
922}
923
924/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
925 line). If a valid command is found, command_ptr is set to point to
926 the beginning of the next command (if the original command had more
927 then one job associated with it) or NULL if no more commands are
928 present. */
929static int parse_command(char **command_ptr, struct job *job, int *inbg)
930{
931 char *command;
932 char *return_command = NULL;
933 char *src, *buf;
934 int argc_l = 0;
935 int done = 0;
936 int argv_alloced;
937 int saw_quote = 0;
938 char quote = '\0';
939 struct child_prog *prog;
940#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
941 int i;
942 char *chptr;
943#endif
944
945 /* skip leading white space */
946 while (**command_ptr && isspace(**command_ptr))
947 (*command_ptr)++;
948
949 /* this handles empty lines or leading '#' characters */
950 if (!**command_ptr || (**command_ptr == '#')) {
951 job->num_progs=0;
952 return 0;
953 }
954
955 *inbg = 0;
956 job->num_progs = 1;
957 job->progs = xmalloc(sizeof(*job->progs));
958
959 /* We set the argv elements to point inside of this string. The
960 memory is freed by free_job(). Allocate twice the original
961 length in case we need to quote every single character.
962
963 Getting clean memory relieves us of the task of NULL
964 terminating things and makes the rest of this look a bit
965 cleaner (though it is, admittedly, a tad less efficient) */
966 job->cmdbuf = command = xzalloc(2*strlen(*command_ptr) + 1);
967 job->text = NULL;
968
969 prog = job->progs;
970 prog->num_redirects = 0;
971 prog->is_stopped = 0;
972 prog->family = job;
973#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
974 prog->redirects = NULL;
975#endif
976
977 argv_alloced = 5;
978 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
979 prog->argv[0] = job->cmdbuf;
980
981 buf = command;
982 src = *command_ptr;
983 while (*src && !done) {
984 if (quote == *src) {
985 quote = '\0';
986 } else if (quote) {
987 if (*src == '\\') {
988 src++;
989 if (!*src) {
990 bb_error_msg("character expected after \\");
991 free_job(job);
992 return 1;
993 }
994
995 /* in shell, "\'" should yield \' */
996 if (*src != quote) {
997 *buf++ = '\\';
998 *buf++ = '\\';
999 }
1000 } else if (*src == '*' || *src == '?' || *src == '[' ||
1001 *src == ']') *buf++ = '\\';
1002 *buf++ = *src;
1003 } else if (isspace(*src)) {
1004 if (*prog->argv[argc_l] || saw_quote) {
1005 buf++, argc_l++;
1006 /* +1 here leaves room for the NULL which ends argv */
1007 if ((argc_l + 1) == argv_alloced) {
1008 argv_alloced += 5;
1009 prog->argv = xrealloc(prog->argv,
1010 sizeof(*prog->argv) *
1011 argv_alloced);
1012 }
1013 prog->argv[argc_l] = buf;
1014 saw_quote = 0;
1015 }
1016 } else
1017 switch (*src) {
1018 case '"':
1019 case '\'':
1020 quote = *src;
1021 saw_quote = 1;
1022 break;
1023
1024 case '#': /* comment */
1025 if (*(src-1)== '$')
1026 *buf++ = *src;
1027 else
1028 done = 1;
1029 break;
1030
1031#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
1032 case '>': /* redirects */
1033 case '<':
1034 i = prog->num_redirects++;
1035 prog->redirects = xrealloc(prog->redirects,
1036 sizeof(*prog->redirects) *
1037 (i + 1));
1038
1039 prog->redirects[i].fd = -1;
1040 if (buf != prog->argv[argc_l]) {
1041 /* the stuff before this character may be the file number
1042 being redirected */
1043 prog->redirects[i].fd =
1044 strtol(prog->argv[argc_l], &chptr, 10);
1045
1046 if (*chptr && *prog->argv[argc_l]) {
1047 buf++, argc_l++;
1048 prog->argv[argc_l] = buf;
1049 }
1050 }
1051
1052 if (prog->redirects[i].fd == -1) {
1053 if (*src == '>')
1054 prog->redirects[i].fd = 1;
1055 else
1056 prog->redirects[i].fd = 0;
1057 }
1058
1059 if (*src++ == '>') {
1060 if (*src == '>')
1061 prog->redirects[i].type =
1062 REDIRECT_APPEND, src++;
1063 else
1064 prog->redirects[i].type = REDIRECT_OVERWRITE;
1065 } else {
1066 prog->redirects[i].type = REDIRECT_INPUT;
1067 }
1068
1069 /* This isn't POSIX sh compliant. Oh well. */
1070 chptr = src;
1071 while (isspace(*chptr))
1072 chptr++;
1073
1074 if (!*chptr) {
1075 bb_error_msg("file name expected after %c", *(src-1));
1076 free_job(job);
1077 job->num_progs=0;
1078 return 1;
1079 }
1080
1081 prog->redirects[i].filename = buf;
1082 while (*chptr && !isspace(*chptr))
1083 *buf++ = *chptr++;
1084
1085 src = chptr - 1; /* we src++ later */
1086 prog->argv[argc_l] = ++buf;
1087 break;
1088
1089 case '|': /* pipe */
1090 /* finish this command */
1091 if (*prog->argv[argc_l] || saw_quote)
1092 argc_l++;
1093 if (!argc_l) {
1094 bb_error_msg("empty command in pipe");
1095 free_job(job);
1096 job->num_progs=0;
1097 return 1;
1098 }
1099 prog->argv[argc_l] = NULL;
1100
1101 /* and start the next */
1102 job->num_progs++;
1103 job->progs = xrealloc(job->progs,
1104 sizeof(*job->progs) * job->num_progs);
1105 prog = job->progs + (job->num_progs - 1);
1106 prog->num_redirects = 0;
1107 prog->redirects = NULL;
1108 prog->is_stopped = 0;
1109 prog->family = job;
1110 argc_l = 0;
1111
1112 argv_alloced = 5;
1113 prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
1114 prog->argv[0] = ++buf;
1115
1116 src++;
1117 while (*src && isspace(*src))
1118 src++;
1119
1120 if (!*src) {
1121 bb_error_msg("empty command in pipe");
1122 free_job(job);
1123 job->num_progs=0;
1124 return 1;
1125 }
1126 src--; /* we'll ++ it at the end of the loop */
1127
1128 break;
1129#endif
1130
1131#ifdef CONFIG_LASH_JOB_CONTROL
1132 case '&': /* background */
1133 *inbg = 1;
1134#endif
1135 case ';': /* multiple commands */
1136 done = 1;
1137 return_command = *command_ptr + (src - *command_ptr) + 1;
1138 break;
1139
1140 case '\\':
1141 src++;
1142 if (!*src) {
1143 bb_error_msg("character expected after \\");
1144 free_job(job);
1145 return 1;
1146 }
1147 if (*src == '*' || *src == '[' || *src == ']'
1148 || *src == '?') *buf++ = '\\';
1149 /* fallthrough */
1150 default:
1151 *buf++ = *src;
1152 }
1153
1154 src++;
1155 }
1156
1157 if (*prog->argv[argc_l] || saw_quote) {
1158 argc_l++;
1159 }
1160 if (!argc_l) {
1161 free_job(job);
1162 return 0;
1163 }
1164 prog->argv[argc_l] = NULL;
1165
1166 if (!return_command) {
1167 job->text = bb_xstrdup(*command_ptr);
1168 } else {
1169 /* This leaves any trailing spaces, which is a bit sloppy */
1170 job->text = bb_xstrndup(*command_ptr, return_command - *command_ptr);
1171 }
1172
1173 *command_ptr = return_command;
1174
1175 return 0;
1176}
1177
1178/* Run the child_prog, no matter what kind of command it uses.
1179 */
1180static int pseudo_exec(struct child_prog *child)
1181{
1182 struct built_in_command *x;
1183
1184 /* Check if the command matches any of the non-forking builtins.
1185 * Depending on context, this might be redundant. But it's
1186 * easier to waste a few CPU cycles than it is to figure out
1187 * if this is one of those cases.
1188 */
1189 for (x = bltins; x->cmd; x++) {
1190 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1191 _exit(x->function(child));
1192 }
1193 }
1194
1195 /* Check if the command matches any of the forking builtins. */
1196 for (x = bltins_forking; x->cmd; x++) {
1197 if (strcmp(child->argv[0], x->cmd) == 0) {
1198 bb_applet_name=x->cmd;
1199 _exit (x->function(child));
1200 }
1201 }
1202
1203 /* Check if the command matches any busybox internal
1204 * commands ("applets") here. Following discussions from
1205 * November 2000 on busybox@busybox.net, don't use
1206 * bb_get_last_path_component(). This way explicit (with
1207 * slashes) filenames will never be interpreted as an
1208 * applet, just like with builtins. This way the user can
1209 * override an applet with an explicit filename reference.
1210 * The only downside to this change is that an explicit
1211 * /bin/foo invocation will fork and exec /bin/foo, even if
1212 * /bin/foo is a symlink to busybox.
1213 */
1214
1215 if (ENABLE_FEATURE_SH_STANDALONE_SHELL) {
1216 char **argv_l = child->argv;
1217 int argc_l;
1218
1219 for(argc_l=0; *argv_l; argv_l++, argc_l++);
1220 optind = 1;
1221 run_applet_by_name(child->argv[0], argc_l, child->argv);
1222 }
1223
1224 execvp(child->argv[0], child->argv);
1225
1226 /* Do not use bb_perror_msg_and_die() here, since we must not
1227 * call exit() but should call _exit() instead */
1228 bb_perror_msg("%s", child->argv[0]);
1229 _exit(EXIT_FAILURE);
1230}
1231
1232static void insert_job(struct job *newjob, int inbg)
1233{
1234 struct job *thejob;
1235 struct jobset *j_list=newjob->job_list;
1236
1237 /* find the ID for thejob to use */
1238 newjob->jobid = 1;
1239 for (thejob = j_list->head; thejob; thejob = thejob->next)
1240 if (thejob->jobid >= newjob->jobid)
1241 newjob->jobid = thejob->jobid + 1;
1242
1243 /* add thejob to the list of running jobs */
1244 if (!j_list->head) {
1245 thejob = j_list->head = xmalloc(sizeof(*thejob));
1246 } else {
1247 for (thejob = j_list->head; thejob->next; thejob = thejob->next) /* nothing */;
1248 thejob->next = xmalloc(sizeof(*thejob));
1249 thejob = thejob->next;
1250 }
1251
1252 *thejob = *newjob; /* physically copy the struct job */
1253 thejob->next = NULL;
1254 thejob->running_progs = thejob->num_progs;
1255 thejob->stopped_progs = 0;
1256
1257#ifdef CONFIG_LASH_JOB_CONTROL
1258 if (inbg) {
1259 /* we don't wait for background thejobs to return -- append it
1260 to the list of backgrounded thejobs and leave it alone */
1261 printf("[%d] %d\n", thejob->jobid,
1262 newjob->progs[newjob->num_progs - 1].pid);
1263 last_jobid = newjob->jobid;
1264 last_bg_pid=newjob->progs[newjob->num_progs - 1].pid;
1265 } else {
1266 newjob->job_list->fg = thejob;
1267
1268 /* move the new process group into the foreground */
1269 /* Ignore errors since child could have already exited */
1270 tcsetpgrp(shell_terminal, newjob->pgrp);
1271 }
1272#endif
1273}
1274
1275static int run_command(struct job *newjob, int inbg, int outpipe[2])
1276{
1277 /* struct job *thejob; */
1278 int i;
1279 int nextin, nextout;
1280 int pipefds[2]; /* pipefd[0] is for reading */
1281 struct built_in_command *x;
1282 struct child_prog *child;
1283
1284 nextin = 0, nextout = 1;
1285 for (i = 0; i < newjob->num_progs; i++) {
1286 child = & (newjob->progs[i]);
1287
1288 if ((i + 1) < newjob->num_progs) {
1289 if (pipe(pipefds)<0) bb_perror_msg_and_die("pipe");
1290 nextout = pipefds[1];
1291 } else {
1292 if (outpipe[1]!=-1) {
1293 nextout = outpipe[1];
1294 } else {
1295 nextout = 1;
1296 }
1297 }
1298
1299
1300 /* Check if the command matches any non-forking builtins,
1301 * but only if this is a simple command.
1302 * Non-forking builtins within pipes have to fork anyway,
1303 * and are handled in pseudo_exec. "echo foo | read bar"
1304 * is doomed to failure, and doesn't work on bash, either.
1305 */
1306 if (newjob->num_progs == 1) {
1307 /* Check if the command sets an environment variable. */
1308 if (strchr(child->argv[0], '=') != NULL) {
1309 child->argv[1] = child->argv[0];
1310 return builtin_export(child);
1311 }
1312
1313 for (x = bltins; x->cmd; x++) {
1314 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1315 int rcode;
1316 int squirrel[] = {-1, -1, -1};
1317 setup_redirects(child, squirrel);
1318 rcode = x->function(child);
1319 restore_redirects(squirrel);
1320 return rcode;
1321 }
1322 }
1323 }
1324
1325#if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
1326 if (!(child->pid = fork()))
1327#else
1328 if (!(child->pid = vfork()))
1329#endif
1330 {
1331 /* Set the handling for job control signals back to the default. */
1332 signal(SIGINT, SIG_DFL);
1333 signal(SIGQUIT, SIG_DFL);
1334 signal(SIGTSTP, SIG_DFL);
1335 signal(SIGTTIN, SIG_DFL);
1336 signal(SIGTTOU, SIG_DFL);
1337 signal(SIGCHLD, SIG_DFL);
1338
1339 // Close all open filehandles.
1340 while(close_me_list) close((long)llist_pop(&close_me_list));
1341
1342 if (outpipe[1]!=-1) {
1343 close(outpipe[0]);
1344 }
1345 if (nextin != 0) {
1346 dup2(nextin, 0);
1347 close(nextin);
1348 }
1349
1350 if (nextout != 1) {
1351 dup2(nextout, 1);
1352 dup2(nextout, 2); /* Really? */
1353 close(nextout);
1354 close(pipefds[0]);
1355 }
1356
1357 /* explicit redirects override pipes */
1358 setup_redirects(child,NULL);
1359
1360 pseudo_exec(child);
1361 }
1362 if (outpipe[1]!=-1) {
1363 close(outpipe[1]);
1364 }
1365
1366 /* put our child in the process group whose leader is the
1367 first process in this pipe */
1368 setpgid(child->pid, newjob->progs[0].pid);
1369 if (nextin != 0)
1370 close(nextin);
1371 if (nextout != 1)
1372 close(nextout);
1373
1374 /* If there isn't another process, nextin is garbage
1375 but it doesn't matter */
1376 nextin = pipefds[0];
1377 }
1378
1379 newjob->pgrp = newjob->progs[0].pid;
1380
1381 insert_job(newjob, inbg);
1382
1383 return 0;
1384}
1385
1386static int busy_loop(FILE * input)
1387{
1388 char *command;
1389 char *next_command = NULL;
1390 struct job newjob;
1391 int i;
1392 int inbg = 0;
1393 int status;
1394#ifdef CONFIG_LASH_JOB_CONTROL
1395 pid_t parent_pgrp;
1396 /* save current owner of TTY so we can restore it on exit */
1397 parent_pgrp = tcgetpgrp(shell_terminal);
1398#endif
1399 newjob.job_list = &job_list;
1400 newjob.job_context = DEFAULT_CONTEXT;
1401
1402 command = xzalloc(BUFSIZ);
1403
1404 while (1) {
1405 if (!job_list.fg) {
1406 /* no job is in the foreground */
1407
1408 /* see if any background processes have exited */
1409 checkjobs(&job_list);
1410
1411 if (!next_command) {
1412 if (get_command(input, command))
1413 break;
1414 next_command = command;
1415 }
1416
1417 if (! expand_arguments(next_command)) {
1418 free(command);
1419 command = xzalloc(BUFSIZ);
1420 next_command = NULL;
1421 continue;
1422 }
1423
1424 if (!parse_command(&next_command, &newjob, &inbg) &&
1425 newjob.num_progs) {
1426 int pipefds[2] = {-1,-1};
1427 debug_printf( "job=%p fed to run_command by busy_loop()'\n",
1428 &newjob);
1429 run_command(&newjob, inbg, pipefds);
1430 }
1431 else {
1432 free(command);
1433 command = (char *) xzalloc(BUFSIZ);
1434 next_command = NULL;
1435 }
1436 } else {
1437 /* a job is running in the foreground; wait for it */
1438 i = 0;
1439 while (!job_list.fg->progs[i].pid ||
1440 job_list.fg->progs[i].is_stopped == 1) i++;
1441
1442 if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0) {
1443 if (errno != ECHILD) {
1444 bb_perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid);
1445 }
1446 }
1447
1448 if (WIFEXITED(status) || WIFSIGNALED(status)) {
1449 /* the child exited */
1450 job_list.fg->running_progs--;
1451 job_list.fg->progs[i].pid = 0;
1452
1453 last_return_code=WEXITSTATUS(status);
1454
1455 if (!job_list.fg->running_progs) {
1456 /* child exited */
1457 remove_job(&job_list, job_list.fg);
1458 job_list.fg = NULL;
1459 }
1460 }
1461#ifdef CONFIG_LASH_JOB_CONTROL
1462 else {
1463 /* the child was stopped */
1464 job_list.fg->stopped_progs++;
1465 job_list.fg->progs[i].is_stopped = 1;
1466
1467 if (job_list.fg->stopped_progs == job_list.fg->running_progs) {
1468 printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid,
1469 "Stopped", job_list.fg->text);
1470 job_list.fg = NULL;
1471 }
1472 }
1473
1474 if (!job_list.fg) {
1475 /* move the shell to the foreground */
1476 /* suppress messages when run from /linuxrc mag@sysgo.de */
1477 if (tcsetpgrp(shell_terminal, getpgrp()) && errno != ENOTTY)
1478 bb_perror_msg("tcsetpgrp");
1479 }
1480#endif
1481 }
1482 }
1483 free(command);
1484
1485#ifdef CONFIG_LASH_JOB_CONTROL
1486 /* return controlling TTY back to parent process group before exiting */
1487 if (tcsetpgrp(shell_terminal, parent_pgrp) && errno != ENOTTY)
1488 bb_perror_msg("tcsetpgrp");
1489#endif
1490
1491 /* return exit status if called with "-c" */
1492 if (input == NULL && WIFEXITED(status))
1493 return WEXITSTATUS(status);
1494
1495 return 0;
1496}
1497
1498#ifdef CONFIG_FEATURE_CLEAN_UP
1499static void free_memory(void)
1500{
1501 if (cwd && cwd!=bb_msg_unknown) {
1502 free((char*)cwd);
1503 }
1504 if (local_pending_command)
1505 free(local_pending_command);
1506
1507 if (job_list.fg && !job_list.fg->running_progs) {
1508 remove_job(&job_list, job_list.fg);
1509 }
1510}
1511#else
1512void free_memory(void);
1513#endif
1514
1515#ifdef CONFIG_LASH_JOB_CONTROL
1516/* Make sure we have a controlling tty. If we get started under a job
1517 * aware app (like bash for example), make sure we are now in charge so
1518 * we don't fight over who gets the foreground */
1519static void setup_job_control(void)
1520{
1521 int status;
1522 pid_t shell_pgrp;
1523
1524 /* Loop until we are in the foreground. */
1525 while ((status = tcgetpgrp (shell_terminal)) >= 0) {
1526 if (status == (shell_pgrp = getpgrp ())) {
1527 break;
1528 }
1529 kill (- shell_pgrp, SIGTTIN);
1530 }
1531
1532 /* Ignore interactive and job-control signals. */
1533 signal(SIGINT, SIG_IGN);
1534 signal(SIGQUIT, SIG_IGN);
1535 signal(SIGTSTP, SIG_IGN);
1536 signal(SIGTTIN, SIG_IGN);
1537 signal(SIGTTOU, SIG_IGN);
1538 signal(SIGCHLD, SIG_IGN);
1539
1540 /* Put ourselves in our own process group. */
1541 setsid();
1542 shell_pgrp = getpid ();
1543 setpgid(shell_pgrp, shell_pgrp);
1544
1545 /* Grab control of the terminal. */
1546 tcsetpgrp(shell_terminal, shell_pgrp);
1547}
1548#else
1549static inline void setup_job_control(void)
1550{
1551}
1552#endif
1553
1554int lash_main(int argc_l, char **argv_l)
1555{
1556 int opt, interactive=FALSE;
1557 FILE *input = stdin;
1558 argc = argc_l;
1559 argv = argv_l;
1560
1561 /* These variables need re-initializing when recursing */
1562 last_jobid = 0;
1563 local_pending_command = NULL;
1564 close_me_list = NULL;
1565 job_list.head = NULL;
1566 job_list.fg = NULL;
1567 last_return_code=1;
1568
1569 if (argv[0] && argv[0][0] == '-') {
1570 FILE *prof_input;
1571 prof_input = fopen("/etc/profile", "r");
1572 if (prof_input) {
1573 llist_add_to(&close_me_list, (void *)(long)fileno(prof_input));
1574 /* Now run the file */
1575 busy_loop(prof_input);
1576 fclose(prof_input);
1577 llist_pop(&close_me_list);
1578 }
1579 }
1580
1581 while ((opt = getopt(argc_l, argv_l, "cxi")) > 0) {
1582 switch (opt) {
1583 case 'c':
1584 input = NULL;
1585 if (local_pending_command != 0)
1586 bb_error_msg_and_die("multiple -c arguments");
1587 local_pending_command = bb_xstrdup(argv[optind]);
1588 optind++;
1589 argv = argv+optind;
1590 break;
1591 case 'i':
1592 interactive++;
1593 break;
1594 default:
1595 bb_show_usage();
1596 }
1597 }
1598 /* A shell is interactive if the `-i' flag was given, or if all of
1599 * the following conditions are met:
1600 * no -c command
1601 * no arguments remaining or the -s flag given
1602 * standard input is a terminal
1603 * standard output is a terminal
1604 * Refer to Posix.2, the description of the `sh' utility. */
1605 if (argv[optind]==NULL && input==stdin &&
1606 isatty(STDIN_FILENO) && isatty(STDOUT_FILENO))
1607 {
1608 interactive++;
1609 }
1610 setup_job_control();
1611 if (interactive) {
1612 /* Looks like they want an interactive shell */
1613 if (!ENABLE_FEATURE_SH_EXTRA_QUIET) {
1614 printf( "\n\n%s Built-in shell (lash)\n", BB_BANNER);
1615 printf( "Enter 'help' for a list of built-in commands.\n\n");
1616 }
1617 } else if (!local_pending_command && argv[optind]) {
1618 //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
1619 input = bb_xfopen(argv[optind], "r");
1620 /* be lazy, never mark this closed */
1621 llist_add_to(&close_me_list, (void *)(long)fileno(input));
1622 }
1623
1624 /* initialize the cwd -- this is never freed...*/
1625 cwd = xgetcwd(0);
1626 if (!cwd)
1627 cwd = bb_msg_unknown;
1628
1629 if (ENABLE_FEATURE_CLEAN_UP) atexit(free_memory);
1630
1631 if (ENABLE_FEATURE_COMMAND_EDITING) cmdedit_set_initial_prompt();
1632 else PS1 = NULL;
1633
1634 return (busy_loop(input));
1635}
Note: See TracBrowser for help on using the repository browser.