Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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