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