Magellan Linux

Contents of /trunk/mkinitrd-magellan/busybox/shell/lash_unused.c

Parent Directory Parent Directory | Revision Log Revision Log


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