diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-02-23 21:10:47 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-02-23 21:10:47 +0000 |
commit | 0dec6de38b721b4faae5567f8b4643df1055a175 (patch) | |
tree | 80dca3727327907efc3e9d6d6261eecc248fa72e | |
parent | cc5715184bf91fa5a6bb7d4423e6c7aed71a98ef (diff) | |
download | busybox-w32-0dec6de38b721b4faae5567f8b4643df1055a175.tar.gz busybox-w32-0dec6de38b721b4faae5567f8b4643df1055a175.tar.bz2 busybox-w32-0dec6de38b721b4faae5567f8b4643df1055a175.zip |
ash: cleanup part 2.7
-rw-r--r-- | shell/ash.c | 962 |
1 files changed, 471 insertions, 491 deletions
diff --git a/shell/ash.c b/shell/ash.c index 5c9060cad..1de4cb50b 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -1593,6 +1593,21 @@ struct shparam { | |||
1593 | 1593 | ||
1594 | static struct shparam shellparam; /* $@ current positional parameters */ | 1594 | static struct shparam shellparam; /* $@ current positional parameters */ |
1595 | 1595 | ||
1596 | /* | ||
1597 | * Free the list of positional parameters. | ||
1598 | */ | ||
1599 | static void | ||
1600 | freeparam(volatile struct shparam *param) | ||
1601 | { | ||
1602 | char **ap; | ||
1603 | |||
1604 | if (param->malloc) { | ||
1605 | for (ap = param->p; *ap; ap++) | ||
1606 | free(*ap); | ||
1607 | free(param->p); | ||
1608 | } | ||
1609 | } | ||
1610 | |||
1596 | #if ENABLE_ASH_GETOPTS | 1611 | #if ENABLE_ASH_GETOPTS |
1597 | static void | 1612 | static void |
1598 | getoptsreset(const char *value) | 1613 | getoptsreset(const char *value) |
@@ -2871,29 +2886,6 @@ static const char syntax_index_table[258] = { | |||
2871 | #endif /* USE_SIT_FUNCTION */ | 2886 | #endif /* USE_SIT_FUNCTION */ |
2872 | 2887 | ||
2873 | 2888 | ||
2874 | /* options.h */ | ||
2875 | |||
2876 | static void optschanged(void); | ||
2877 | static void setparam(char **); | ||
2878 | static void freeparam(volatile struct shparam *); | ||
2879 | static int shiftcmd(int, char **); | ||
2880 | static int setcmd(int, char **); | ||
2881 | static int nextopt(const char *); | ||
2882 | |||
2883 | |||
2884 | /* redir.h */ | ||
2885 | |||
2886 | /* flags passed to redirect */ | ||
2887 | #define REDIR_PUSH 01 /* save previous values of file descriptors */ | ||
2888 | #define REDIR_SAVEFD2 03 /* set preverrout */ | ||
2889 | |||
2890 | static void redirect(union node *, int); | ||
2891 | static void popredir(int); | ||
2892 | static void clearredir(int); | ||
2893 | static int copyfd(int, int); | ||
2894 | static int redirectsafe(union node *, int); | ||
2895 | |||
2896 | |||
2897 | /* ============ Alias handling */ | 2889 | /* ============ Alias handling */ |
2898 | 2890 | ||
2899 | #if ENABLE_ASH_ALIAS | 2891 | #if ENABLE_ASH_ALIAS |
@@ -4622,6 +4614,357 @@ stoppedjobs(void) | |||
4622 | } | 4614 | } |
4623 | 4615 | ||
4624 | 4616 | ||
4617 | /* ============ redir.c | ||
4618 | * | ||
4619 | * Code for dealing with input/output redirection. | ||
4620 | */ | ||
4621 | |||
4622 | #define EMPTY -2 /* marks an unused slot in redirtab */ | ||
4623 | #ifndef PIPE_BUF | ||
4624 | # define PIPESIZE 4096 /* amount of buffering in a pipe */ | ||
4625 | #else | ||
4626 | # define PIPESIZE PIPE_BUF | ||
4627 | #endif | ||
4628 | |||
4629 | /* | ||
4630 | * Open a file in noclobber mode. | ||
4631 | * The code was copied from bash. | ||
4632 | */ | ||
4633 | static int | ||
4634 | noclobberopen(const char *fname) | ||
4635 | { | ||
4636 | int r, fd; | ||
4637 | struct stat finfo, finfo2; | ||
4638 | |||
4639 | /* | ||
4640 | * If the file exists and is a regular file, return an error | ||
4641 | * immediately. | ||
4642 | */ | ||
4643 | r = stat(fname, &finfo); | ||
4644 | if (r == 0 && S_ISREG(finfo.st_mode)) { | ||
4645 | errno = EEXIST; | ||
4646 | return -1; | ||
4647 | } | ||
4648 | |||
4649 | /* | ||
4650 | * If the file was not present (r != 0), make sure we open it | ||
4651 | * exclusively so that if it is created before we open it, our open | ||
4652 | * will fail. Make sure that we do not truncate an existing file. | ||
4653 | * Note that we don't turn on O_EXCL unless the stat failed -- if the | ||
4654 | * file was not a regular file, we leave O_EXCL off. | ||
4655 | */ | ||
4656 | if (r != 0) | ||
4657 | return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); | ||
4658 | fd = open(fname, O_WRONLY|O_CREAT, 0666); | ||
4659 | |||
4660 | /* If the open failed, return the file descriptor right away. */ | ||
4661 | if (fd < 0) | ||
4662 | return fd; | ||
4663 | |||
4664 | /* | ||
4665 | * OK, the open succeeded, but the file may have been changed from a | ||
4666 | * non-regular file to a regular file between the stat and the open. | ||
4667 | * We are assuming that the O_EXCL open handles the case where FILENAME | ||
4668 | * did not exist and is symlinked to an existing file between the stat | ||
4669 | * and open. | ||
4670 | */ | ||
4671 | |||
4672 | /* | ||
4673 | * If we can open it and fstat the file descriptor, and neither check | ||
4674 | * revealed that it was a regular file, and the file has not been | ||
4675 | * replaced, return the file descriptor. | ||
4676 | */ | ||
4677 | if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) | ||
4678 | && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) | ||
4679 | return fd; | ||
4680 | |||
4681 | /* The file has been replaced. badness. */ | ||
4682 | close(fd); | ||
4683 | errno = EEXIST; | ||
4684 | return -1; | ||
4685 | } | ||
4686 | |||
4687 | /* | ||
4688 | * Handle here documents. Normally we fork off a process to write the | ||
4689 | * data to a pipe. If the document is short, we can stuff the data in | ||
4690 | * the pipe without forking. | ||
4691 | */ | ||
4692 | /* openhere needs this forward reference */ | ||
4693 | static void expandhere(union node *arg, int fd); | ||
4694 | static int | ||
4695 | openhere(union node *redir) | ||
4696 | { | ||
4697 | int pip[2]; | ||
4698 | size_t len = 0; | ||
4699 | |||
4700 | if (pipe(pip) < 0) | ||
4701 | ash_msg_and_raise_error("Pipe call failed"); | ||
4702 | if (redir->type == NHERE) { | ||
4703 | len = strlen(redir->nhere.doc->narg.text); | ||
4704 | if (len <= PIPESIZE) { | ||
4705 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
4706 | goto out; | ||
4707 | } | ||
4708 | } | ||
4709 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | ||
4710 | close(pip[0]); | ||
4711 | signal(SIGINT, SIG_IGN); | ||
4712 | signal(SIGQUIT, SIG_IGN); | ||
4713 | signal(SIGHUP, SIG_IGN); | ||
4714 | #ifdef SIGTSTP | ||
4715 | signal(SIGTSTP, SIG_IGN); | ||
4716 | #endif | ||
4717 | signal(SIGPIPE, SIG_DFL); | ||
4718 | if (redir->type == NHERE) | ||
4719 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
4720 | else | ||
4721 | expandhere(redir->nhere.doc, pip[1]); | ||
4722 | _exit(0); | ||
4723 | } | ||
4724 | out: | ||
4725 | close(pip[1]); | ||
4726 | return pip[0]; | ||
4727 | } | ||
4728 | |||
4729 | static int | ||
4730 | openredirect(union node *redir) | ||
4731 | { | ||
4732 | char *fname; | ||
4733 | int f; | ||
4734 | |||
4735 | switch (redir->nfile.type) { | ||
4736 | case NFROM: | ||
4737 | fname = redir->nfile.expfname; | ||
4738 | f = open(fname, O_RDONLY); | ||
4739 | if (f < 0) | ||
4740 | goto eopen; | ||
4741 | break; | ||
4742 | case NFROMTO: | ||
4743 | fname = redir->nfile.expfname; | ||
4744 | f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); | ||
4745 | if (f < 0) | ||
4746 | goto ecreate; | ||
4747 | break; | ||
4748 | case NTO: | ||
4749 | /* Take care of noclobber mode. */ | ||
4750 | if (Cflag) { | ||
4751 | fname = redir->nfile.expfname; | ||
4752 | f = noclobberopen(fname); | ||
4753 | if (f < 0) | ||
4754 | goto ecreate; | ||
4755 | break; | ||
4756 | } | ||
4757 | /* FALLTHROUGH */ | ||
4758 | case NCLOBBER: | ||
4759 | fname = redir->nfile.expfname; | ||
4760 | f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); | ||
4761 | if (f < 0) | ||
4762 | goto ecreate; | ||
4763 | break; | ||
4764 | case NAPPEND: | ||
4765 | fname = redir->nfile.expfname; | ||
4766 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); | ||
4767 | if (f < 0) | ||
4768 | goto ecreate; | ||
4769 | break; | ||
4770 | default: | ||
4771 | #if DEBUG | ||
4772 | abort(); | ||
4773 | #endif | ||
4774 | /* Fall through to eliminate warning. */ | ||
4775 | case NTOFD: | ||
4776 | case NFROMFD: | ||
4777 | f = -1; | ||
4778 | break; | ||
4779 | case NHERE: | ||
4780 | case NXHERE: | ||
4781 | f = openhere(redir); | ||
4782 | break; | ||
4783 | } | ||
4784 | |||
4785 | return f; | ||
4786 | ecreate: | ||
4787 | ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "Directory nonexistent")); | ||
4788 | eopen: | ||
4789 | ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "No such file")); | ||
4790 | } | ||
4791 | |||
4792 | /* | ||
4793 | * Copy a file descriptor to be >= to. Returns -1 | ||
4794 | * if the source file descriptor is closed, EMPTY if there are no unused | ||
4795 | * file descriptors left. | ||
4796 | */ | ||
4797 | static int | ||
4798 | copyfd(int from, int to) | ||
4799 | { | ||
4800 | int newfd; | ||
4801 | |||
4802 | newfd = fcntl(from, F_DUPFD, to); | ||
4803 | if (newfd < 0) { | ||
4804 | if (errno == EMFILE) | ||
4805 | return EMPTY; | ||
4806 | ash_msg_and_raise_error("%d: %m", from); | ||
4807 | } | ||
4808 | return newfd; | ||
4809 | } | ||
4810 | |||
4811 | static void | ||
4812 | dupredirect(union node *redir, int f) | ||
4813 | { | ||
4814 | int fd = redir->nfile.fd; | ||
4815 | |||
4816 | if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { | ||
4817 | if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ | ||
4818 | copyfd(redir->ndup.dupfd, fd); | ||
4819 | } | ||
4820 | return; | ||
4821 | } | ||
4822 | |||
4823 | if (f != fd) { | ||
4824 | copyfd(f, fd); | ||
4825 | close(f); | ||
4826 | } | ||
4827 | } | ||
4828 | |||
4829 | /* | ||
4830 | * Process a list of redirection commands. If the REDIR_PUSH flag is set, | ||
4831 | * old file descriptors are stashed away so that the redirection can be | ||
4832 | * undone by calling popredir. If the REDIR_BACKQ flag is set, then the | ||
4833 | * standard output, and the standard error if it becomes a duplicate of | ||
4834 | * stdout, is saved in memory. | ||
4835 | */ | ||
4836 | /* flags passed to redirect */ | ||
4837 | #define REDIR_PUSH 01 /* save previous values of file descriptors */ | ||
4838 | #define REDIR_SAVEFD2 03 /* set preverrout */ | ||
4839 | static void | ||
4840 | redirect(union node *redir, int flags) | ||
4841 | { | ||
4842 | union node *n; | ||
4843 | struct redirtab *sv; | ||
4844 | int i; | ||
4845 | int fd; | ||
4846 | int newfd; | ||
4847 | int *p; | ||
4848 | nullredirs++; | ||
4849 | if (!redir) { | ||
4850 | return; | ||
4851 | } | ||
4852 | sv = NULL; | ||
4853 | INT_OFF; | ||
4854 | if (flags & REDIR_PUSH) { | ||
4855 | struct redirtab *q; | ||
4856 | q = ckmalloc(sizeof(struct redirtab)); | ||
4857 | q->next = redirlist; | ||
4858 | redirlist = q; | ||
4859 | q->nullredirs = nullredirs - 1; | ||
4860 | for (i = 0; i < 10; i++) | ||
4861 | q->renamed[i] = EMPTY; | ||
4862 | nullredirs = 0; | ||
4863 | sv = q; | ||
4864 | } | ||
4865 | n = redir; | ||
4866 | do { | ||
4867 | fd = n->nfile.fd; | ||
4868 | if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) | ||
4869 | && n->ndup.dupfd == fd) | ||
4870 | continue; /* redirect from/to same file descriptor */ | ||
4871 | |||
4872 | newfd = openredirect(n); | ||
4873 | if (fd == newfd) | ||
4874 | continue; | ||
4875 | if (sv && *(p = &sv->renamed[fd]) == EMPTY) { | ||
4876 | i = fcntl(fd, F_DUPFD, 10); | ||
4877 | |||
4878 | if (i == -1) { | ||
4879 | i = errno; | ||
4880 | if (i != EBADF) { | ||
4881 | close(newfd); | ||
4882 | errno = i; | ||
4883 | ash_msg_and_raise_error("%d: %m", fd); | ||
4884 | /* NOTREACHED */ | ||
4885 | } | ||
4886 | } else { | ||
4887 | *p = i; | ||
4888 | close(fd); | ||
4889 | } | ||
4890 | } else { | ||
4891 | close(fd); | ||
4892 | } | ||
4893 | dupredirect(n, newfd); | ||
4894 | } while ((n = n->nfile.next)); | ||
4895 | INT_ON; | ||
4896 | if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0) | ||
4897 | preverrout_fd = sv->renamed[2]; | ||
4898 | } | ||
4899 | |||
4900 | /* | ||
4901 | * Undo the effects of the last redirection. | ||
4902 | */ | ||
4903 | static void | ||
4904 | popredir(int drop) | ||
4905 | { | ||
4906 | struct redirtab *rp; | ||
4907 | int i; | ||
4908 | |||
4909 | if (--nullredirs >= 0) | ||
4910 | return; | ||
4911 | INT_OFF; | ||
4912 | rp = redirlist; | ||
4913 | for (i = 0; i < 10; i++) { | ||
4914 | if (rp->renamed[i] != EMPTY) { | ||
4915 | if (!drop) { | ||
4916 | close(i); | ||
4917 | copyfd(rp->renamed[i], i); | ||
4918 | } | ||
4919 | close(rp->renamed[i]); | ||
4920 | } | ||
4921 | } | ||
4922 | redirlist = rp->next; | ||
4923 | nullredirs = rp->nullredirs; | ||
4924 | free(rp); | ||
4925 | INT_ON; | ||
4926 | } | ||
4927 | |||
4928 | /* | ||
4929 | * Undo all redirections. Called on error or interrupt. | ||
4930 | */ | ||
4931 | |||
4932 | /* | ||
4933 | * Discard all saved file descriptors. | ||
4934 | */ | ||
4935 | static void | ||
4936 | clearredir(int drop) | ||
4937 | { | ||
4938 | for (;;) { | ||
4939 | nullredirs = 0; | ||
4940 | if (!redirlist) | ||
4941 | break; | ||
4942 | popredir(drop); | ||
4943 | } | ||
4944 | } | ||
4945 | |||
4946 | static int | ||
4947 | redirectsafe(union node *redir, int flags) | ||
4948 | { | ||
4949 | int err; | ||
4950 | volatile int saveint; | ||
4951 | struct jmploc *volatile savehandler = exception_handler; | ||
4952 | struct jmploc jmploc; | ||
4953 | |||
4954 | SAVE_INT(saveint); | ||
4955 | err = setjmp(jmploc.loc) * 2; | ||
4956 | if (!err) { | ||
4957 | exception_handler = &jmploc; | ||
4958 | redirect(redir, flags); | ||
4959 | } | ||
4960 | exception_handler = savehandler; | ||
4961 | if (err && exception != EXERROR) | ||
4962 | longjmp(exception_handler->loc, 1); | ||
4963 | RESTORE_INT(saveint); | ||
4964 | return err; | ||
4965 | } | ||
4966 | |||
4967 | |||
4625 | /* ============ Routines to expand arguments to commands | 4968 | /* ============ Routines to expand arguments to commands |
4626 | * | 4969 | * |
4627 | * We have to deal with backquotes, shell variables, and file metacharacters. | 4970 | * We have to deal with backquotes, shell variables, and file metacharacters. |
@@ -7475,6 +7818,58 @@ evalpipe(union node *n, int flags) | |||
7475 | INT_ON; | 7818 | INT_ON; |
7476 | } | 7819 | } |
7477 | 7820 | ||
7821 | /* | ||
7822 | * Controls whether the shell is interactive or not. | ||
7823 | */ | ||
7824 | static void | ||
7825 | setinteractive(int on) | ||
7826 | { | ||
7827 | static int is_interactive; | ||
7828 | |||
7829 | if (++on == is_interactive) | ||
7830 | return; | ||
7831 | is_interactive = on; | ||
7832 | setsignal(SIGINT); | ||
7833 | setsignal(SIGQUIT); | ||
7834 | setsignal(SIGTERM); | ||
7835 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET | ||
7836 | if (is_interactive > 1) { | ||
7837 | /* Looks like they want an interactive shell */ | ||
7838 | static smallint do_banner; | ||
7839 | |||
7840 | if (!do_banner) { | ||
7841 | out1fmt( | ||
7842 | "\n\n" | ||
7843 | "%s Built-in shell (ash)\n" | ||
7844 | "Enter 'help' for a list of built-in commands." | ||
7845 | "\n\n", | ||
7846 | BB_BANNER); | ||
7847 | do_banner = 1; | ||
7848 | } | ||
7849 | } | ||
7850 | #endif | ||
7851 | } | ||
7852 | |||
7853 | #if ENABLE_FEATURE_EDITING_VI | ||
7854 | #define setvimode(on) do { \ | ||
7855 | if (on) line_input_state->flags |= VI_MODE; \ | ||
7856 | else line_input_state->flags &= ~VI_MODE; \ | ||
7857 | } while (0) | ||
7858 | #else | ||
7859 | #define setvimode(on) viflag = 0 /* forcibly keep the option off */ | ||
7860 | #endif | ||
7861 | |||
7862 | static void | ||
7863 | optschanged(void) | ||
7864 | { | ||
7865 | #if DEBUG | ||
7866 | opentrace(); | ||
7867 | #endif | ||
7868 | setinteractive(iflag); | ||
7869 | setjobctl(mflag); | ||
7870 | setvimode(viflag); | ||
7871 | } | ||
7872 | |||
7478 | static struct localvar *localvars; | 7873 | static struct localvar *localvars; |
7479 | 7874 | ||
7480 | /* | 7875 | /* |
@@ -7894,7 +8289,7 @@ evalcommand(union node *cmd, int flags) | |||
7894 | 8289 | ||
7895 | preverrout_fd = 2; | 8290 | preverrout_fd = 2; |
7896 | expredir(cmd->ncmd.redirect); | 8291 | expredir(cmd->ncmd.redirect); |
7897 | status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2); | 8292 | status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); |
7898 | 8293 | ||
7899 | path = vpath.text; | 8294 | path = vpath.text; |
7900 | for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { | 8295 | for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { |
@@ -8678,88 +9073,35 @@ changemail(const char *val) | |||
8678 | /* ============ ??? */ | 9073 | /* ============ ??? */ |
8679 | 9074 | ||
8680 | /* | 9075 | /* |
8681 | * Take commands from a file. To be compatible we should do a path | 9076 | * Set the shell parameters. |
8682 | * search for the file, which is necessary to find sub-commands. | ||
8683 | */ | ||
8684 | static char * | ||
8685 | find_dot_file(char *name) | ||
8686 | { | ||
8687 | char *fullname; | ||
8688 | const char *path = pathval(); | ||
8689 | struct stat statb; | ||
8690 | |||
8691 | /* don't try this for absolute or relative paths */ | ||
8692 | if (strchr(name, '/')) | ||
8693 | return name; | ||
8694 | |||
8695 | while ((fullname = padvance(&path, name)) != NULL) { | ||
8696 | if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { | ||
8697 | /* | ||
8698 | * Don't bother freeing here, since it will | ||
8699 | * be freed by the caller. | ||
8700 | */ | ||
8701 | return fullname; | ||
8702 | } | ||
8703 | stunalloc(fullname); | ||
8704 | } | ||
8705 | |||
8706 | /* not found in the PATH */ | ||
8707 | ash_msg_and_raise_error("%s: not found", name); | ||
8708 | /* NOTREACHED */ | ||
8709 | } | ||
8710 | |||
8711 | /* | ||
8712 | * Controls whether the shell is interactive or not. | ||
8713 | */ | 9077 | */ |
8714 | static void | 9078 | static void |
8715 | setinteractive(int on) | 9079 | setparam(char **argv) |
8716 | { | 9080 | { |
8717 | static int is_interactive; | 9081 | char **newparam; |
8718 | 9082 | char **ap; | |
8719 | if (++on == is_interactive) | 9083 | int nparam; |
8720 | return; | ||
8721 | is_interactive = on; | ||
8722 | setsignal(SIGINT); | ||
8723 | setsignal(SIGQUIT); | ||
8724 | setsignal(SIGTERM); | ||
8725 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET | ||
8726 | if (is_interactive > 1) { | ||
8727 | /* Looks like they want an interactive shell */ | ||
8728 | static smallint do_banner; | ||
8729 | 9084 | ||
8730 | if (!do_banner) { | 9085 | for (nparam = 0; argv[nparam]; nparam++); |
8731 | out1fmt( | 9086 | ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap)); |
8732 | "\n\n" | 9087 | while (*argv) { |
8733 | "%s Built-in shell (ash)\n" | 9088 | *ap++ = ckstrdup(*argv++); |
8734 | "Enter 'help' for a list of built-in commands." | ||
8735 | "\n\n", | ||
8736 | BB_BANNER); | ||
8737 | do_banner = 1; | ||
8738 | } | ||
8739 | } | 9089 | } |
9090 | *ap = NULL; | ||
9091 | freeparam(&shellparam); | ||
9092 | shellparam.malloc = 1; | ||
9093 | shellparam.nparam = nparam; | ||
9094 | shellparam.p = newparam; | ||
9095 | #if ENABLE_ASH_GETOPTS | ||
9096 | shellparam.optind = 1; | ||
9097 | shellparam.optoff = -1; | ||
8740 | #endif | 9098 | #endif |
8741 | } | 9099 | } |
8742 | 9100 | ||
8743 | #if ENABLE_FEATURE_EDITING_VI | 9101 | /* |
8744 | #define setvimode(on) do { \ | 9102 | * Process shell options. The global variable argptr contains a pointer |
8745 | if (on) line_input_state->flags |= VI_MODE; \ | 9103 | * to the argument list; we advance it past the options. |
8746 | else line_input_state->flags &= ~VI_MODE; \ | 9104 | */ |
8747 | } while (0) | ||
8748 | #else | ||
8749 | #define setvimode(on) viflag = 0 /* forcibly keep the option off */ | ||
8750 | #endif | ||
8751 | |||
8752 | static void | ||
8753 | optschanged(void) | ||
8754 | { | ||
8755 | #if DEBUG | ||
8756 | opentrace(); | ||
8757 | #endif | ||
8758 | setinteractive(iflag); | ||
8759 | setjobctl(mflag); | ||
8760 | setvimode(viflag); | ||
8761 | } | ||
8762 | |||
8763 | static void | 9105 | static void |
8764 | minus_o(char *name, int val) | 9106 | minus_o(char *name, int val) |
8765 | { | 9107 | { |
@@ -8779,7 +9121,6 @@ minus_o(char *name, int val) | |||
8779 | out1fmt("%-16s%s\n", optnames(i), | 9121 | out1fmt("%-16s%s\n", optnames(i), |
8780 | optlist[i] ? "on" : "off"); | 9122 | optlist[i] ? "on" : "off"); |
8781 | } | 9123 | } |
8782 | |||
8783 | static void | 9124 | static void |
8784 | setoption(int flag, int val) | 9125 | setoption(int flag, int val) |
8785 | { | 9126 | { |
@@ -8794,11 +9135,6 @@ setoption(int flag, int val) | |||
8794 | ash_msg_and_raise_error("Illegal option -%c", flag); | 9135 | ash_msg_and_raise_error("Illegal option -%c", flag); |
8795 | /* NOTREACHED */ | 9136 | /* NOTREACHED */ |
8796 | } | 9137 | } |
8797 | |||
8798 | /* | ||
8799 | * Process shell options. The global variable argptr contains a pointer | ||
8800 | * to the argument list; we advance it past the options. | ||
8801 | */ | ||
8802 | static void | 9138 | static void |
8803 | options(int cmdline) | 9139 | options(int cmdline) |
8804 | { | 9140 | { |
@@ -8849,47 +9185,6 @@ options(int cmdline) | |||
8849 | } | 9185 | } |
8850 | 9186 | ||
8851 | /* | 9187 | /* |
8852 | * Set the shell parameters. | ||
8853 | */ | ||
8854 | static void | ||
8855 | setparam(char **argv) | ||
8856 | { | ||
8857 | char **newparam; | ||
8858 | char **ap; | ||
8859 | int nparam; | ||
8860 | |||
8861 | for (nparam = 0; argv[nparam]; nparam++); | ||
8862 | ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap)); | ||
8863 | while (*argv) { | ||
8864 | *ap++ = ckstrdup(*argv++); | ||
8865 | } | ||
8866 | *ap = NULL; | ||
8867 | freeparam(&shellparam); | ||
8868 | shellparam.malloc = 1; | ||
8869 | shellparam.nparam = nparam; | ||
8870 | shellparam.p = newparam; | ||
8871 | #if ENABLE_ASH_GETOPTS | ||
8872 | shellparam.optind = 1; | ||
8873 | shellparam.optoff = -1; | ||
8874 | #endif | ||
8875 | } | ||
8876 | |||
8877 | /* | ||
8878 | * Free the list of positional parameters. | ||
8879 | */ | ||
8880 | static void | ||
8881 | freeparam(volatile struct shparam *param) | ||
8882 | { | ||
8883 | char **ap; | ||
8884 | |||
8885 | if (param->malloc) { | ||
8886 | for (ap = param->p; *ap; ap++) | ||
8887 | free(*ap); | ||
8888 | free(param->p); | ||
8889 | } | ||
8890 | } | ||
8891 | |||
8892 | /* | ||
8893 | * The shift builtin command. | 9188 | * The shift builtin command. |
8894 | */ | 9189 | */ |
8895 | static int | 9190 | static int |
@@ -10720,6 +11015,37 @@ cmdloop(int top) | |||
10720 | return 0; | 11015 | return 0; |
10721 | } | 11016 | } |
10722 | 11017 | ||
11018 | /* | ||
11019 | * Take commands from a file. To be compatible we should do a path | ||
11020 | * search for the file, which is necessary to find sub-commands. | ||
11021 | */ | ||
11022 | static char * | ||
11023 | find_dot_file(char *name) | ||
11024 | { | ||
11025 | char *fullname; | ||
11026 | const char *path = pathval(); | ||
11027 | struct stat statb; | ||
11028 | |||
11029 | /* don't try this for absolute or relative paths */ | ||
11030 | if (strchr(name, '/')) | ||
11031 | return name; | ||
11032 | |||
11033 | while ((fullname = padvance(&path, name)) != NULL) { | ||
11034 | if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { | ||
11035 | /* | ||
11036 | * Don't bother freeing here, since it will | ||
11037 | * be freed by the caller. | ||
11038 | */ | ||
11039 | return fullname; | ||
11040 | } | ||
11041 | stunalloc(fullname); | ||
11042 | } | ||
11043 | |||
11044 | /* not found in the PATH */ | ||
11045 | ash_msg_and_raise_error("%s: not found", name); | ||
11046 | /* NOTREACHED */ | ||
11047 | } | ||
11048 | |||
10723 | static int | 11049 | static int |
10724 | dotcmd(int argc, char **argv) | 11050 | dotcmd(int argc, char **argv) |
10725 | { | 11051 | { |
@@ -10982,352 +11308,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
10982 | } | 11308 | } |
10983 | 11309 | ||
10984 | 11310 | ||
10985 | /* ============ redir.c | ||
10986 | * | ||
10987 | * Code for dealing with input/output redirection. | ||
10988 | */ | ||
10989 | |||
10990 | #define EMPTY -2 /* marks an unused slot in redirtab */ | ||
10991 | #ifndef PIPE_BUF | ||
10992 | # define PIPESIZE 4096 /* amount of buffering in a pipe */ | ||
10993 | #else | ||
10994 | # define PIPESIZE PIPE_BUF | ||
10995 | #endif | ||
10996 | |||
10997 | /* | ||
10998 | * Open a file in noclobber mode. | ||
10999 | * The code was copied from bash. | ||
11000 | */ | ||
11001 | static int | ||
11002 | noclobberopen(const char *fname) | ||
11003 | { | ||
11004 | int r, fd; | ||
11005 | struct stat finfo, finfo2; | ||
11006 | |||
11007 | /* | ||
11008 | * If the file exists and is a regular file, return an error | ||
11009 | * immediately. | ||
11010 | */ | ||
11011 | r = stat(fname, &finfo); | ||
11012 | if (r == 0 && S_ISREG(finfo.st_mode)) { | ||
11013 | errno = EEXIST; | ||
11014 | return -1; | ||
11015 | } | ||
11016 | |||
11017 | /* | ||
11018 | * If the file was not present (r != 0), make sure we open it | ||
11019 | * exclusively so that if it is created before we open it, our open | ||
11020 | * will fail. Make sure that we do not truncate an existing file. | ||
11021 | * Note that we don't turn on O_EXCL unless the stat failed -- if the | ||
11022 | * file was not a regular file, we leave O_EXCL off. | ||
11023 | */ | ||
11024 | if (r != 0) | ||
11025 | return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); | ||
11026 | fd = open(fname, O_WRONLY|O_CREAT, 0666); | ||
11027 | |||
11028 | /* If the open failed, return the file descriptor right away. */ | ||
11029 | if (fd < 0) | ||
11030 | return fd; | ||
11031 | |||
11032 | /* | ||
11033 | * OK, the open succeeded, but the file may have been changed from a | ||
11034 | * non-regular file to a regular file between the stat and the open. | ||
11035 | * We are assuming that the O_EXCL open handles the case where FILENAME | ||
11036 | * did not exist and is symlinked to an existing file between the stat | ||
11037 | * and open. | ||
11038 | */ | ||
11039 | |||
11040 | /* | ||
11041 | * If we can open it and fstat the file descriptor, and neither check | ||
11042 | * revealed that it was a regular file, and the file has not been | ||
11043 | * replaced, return the file descriptor. | ||
11044 | */ | ||
11045 | if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) | ||
11046 | && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) | ||
11047 | return fd; | ||
11048 | |||
11049 | /* The file has been replaced. badness. */ | ||
11050 | close(fd); | ||
11051 | errno = EEXIST; | ||
11052 | return -1; | ||
11053 | } | ||
11054 | |||
11055 | /* | ||
11056 | * Handle here documents. Normally we fork off a process to write the | ||
11057 | * data to a pipe. If the document is short, we can stuff the data in | ||
11058 | * the pipe without forking. | ||
11059 | */ | ||
11060 | static int | ||
11061 | openhere(union node *redir) | ||
11062 | { | ||
11063 | int pip[2]; | ||
11064 | size_t len = 0; | ||
11065 | |||
11066 | if (pipe(pip) < 0) | ||
11067 | ash_msg_and_raise_error("Pipe call failed"); | ||
11068 | if (redir->type == NHERE) { | ||
11069 | len = strlen(redir->nhere.doc->narg.text); | ||
11070 | if (len <= PIPESIZE) { | ||
11071 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
11072 | goto out; | ||
11073 | } | ||
11074 | } | ||
11075 | if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { | ||
11076 | close(pip[0]); | ||
11077 | signal(SIGINT, SIG_IGN); | ||
11078 | signal(SIGQUIT, SIG_IGN); | ||
11079 | signal(SIGHUP, SIG_IGN); | ||
11080 | #ifdef SIGTSTP | ||
11081 | signal(SIGTSTP, SIG_IGN); | ||
11082 | #endif | ||
11083 | signal(SIGPIPE, SIG_DFL); | ||
11084 | if (redir->type == NHERE) | ||
11085 | full_write(pip[1], redir->nhere.doc->narg.text, len); | ||
11086 | else | ||
11087 | expandhere(redir->nhere.doc, pip[1]); | ||
11088 | _exit(0); | ||
11089 | } | ||
11090 | out: | ||
11091 | close(pip[1]); | ||
11092 | return pip[0]; | ||
11093 | } | ||
11094 | |||
11095 | static int | ||
11096 | openredirect(union node *redir) | ||
11097 | { | ||
11098 | char *fname; | ||
11099 | int f; | ||
11100 | |||
11101 | switch (redir->nfile.type) { | ||
11102 | case NFROM: | ||
11103 | fname = redir->nfile.expfname; | ||
11104 | f = open(fname, O_RDONLY); | ||
11105 | if (f < 0) | ||
11106 | goto eopen; | ||
11107 | break; | ||
11108 | case NFROMTO: | ||
11109 | fname = redir->nfile.expfname; | ||
11110 | f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); | ||
11111 | if (f < 0) | ||
11112 | goto ecreate; | ||
11113 | break; | ||
11114 | case NTO: | ||
11115 | /* Take care of noclobber mode. */ | ||
11116 | if (Cflag) { | ||
11117 | fname = redir->nfile.expfname; | ||
11118 | f = noclobberopen(fname); | ||
11119 | if (f < 0) | ||
11120 | goto ecreate; | ||
11121 | break; | ||
11122 | } | ||
11123 | /* FALLTHROUGH */ | ||
11124 | case NCLOBBER: | ||
11125 | fname = redir->nfile.expfname; | ||
11126 | f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); | ||
11127 | if (f < 0) | ||
11128 | goto ecreate; | ||
11129 | break; | ||
11130 | case NAPPEND: | ||
11131 | fname = redir->nfile.expfname; | ||
11132 | f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); | ||
11133 | if (f < 0) | ||
11134 | goto ecreate; | ||
11135 | break; | ||
11136 | default: | ||
11137 | #if DEBUG | ||
11138 | abort(); | ||
11139 | #endif | ||
11140 | /* Fall through to eliminate warning. */ | ||
11141 | case NTOFD: | ||
11142 | case NFROMFD: | ||
11143 | f = -1; | ||
11144 | break; | ||
11145 | case NHERE: | ||
11146 | case NXHERE: | ||
11147 | f = openhere(redir); | ||
11148 | break; | ||
11149 | } | ||
11150 | |||
11151 | return f; | ||
11152 | ecreate: | ||
11153 | ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "Directory nonexistent")); | ||
11154 | eopen: | ||
11155 | ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "No such file")); | ||
11156 | } | ||
11157 | |||
11158 | static void | ||
11159 | dupredirect(union node *redir, int f) | ||
11160 | { | ||
11161 | int fd = redir->nfile.fd; | ||
11162 | |||
11163 | if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { | ||
11164 | if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ | ||
11165 | copyfd(redir->ndup.dupfd, fd); | ||
11166 | } | ||
11167 | return; | ||
11168 | } | ||
11169 | |||
11170 | if (f != fd) { | ||
11171 | copyfd(f, fd); | ||
11172 | close(f); | ||
11173 | } | ||
11174 | } | ||
11175 | |||
11176 | /* | ||
11177 | * Process a list of redirection commands. If the REDIR_PUSH flag is set, | ||
11178 | * old file descriptors are stashed away so that the redirection can be | ||
11179 | * undone by calling popredir. If the REDIR_BACKQ flag is set, then the | ||
11180 | * standard output, and the standard error if it becomes a duplicate of | ||
11181 | * stdout, is saved in memory. | ||
11182 | */ | ||
11183 | static void | ||
11184 | redirect(union node *redir, int flags) | ||
11185 | { | ||
11186 | union node *n; | ||
11187 | struct redirtab *sv; | ||
11188 | int i; | ||
11189 | int fd; | ||
11190 | int newfd; | ||
11191 | int *p; | ||
11192 | nullredirs++; | ||
11193 | if (!redir) { | ||
11194 | return; | ||
11195 | } | ||
11196 | sv = NULL; | ||
11197 | INT_OFF; | ||
11198 | if (flags & REDIR_PUSH) { | ||
11199 | struct redirtab *q; | ||
11200 | q = ckmalloc(sizeof(struct redirtab)); | ||
11201 | q->next = redirlist; | ||
11202 | redirlist = q; | ||
11203 | q->nullredirs = nullredirs - 1; | ||
11204 | for (i = 0; i < 10; i++) | ||
11205 | q->renamed[i] = EMPTY; | ||
11206 | nullredirs = 0; | ||
11207 | sv = q; | ||
11208 | } | ||
11209 | n = redir; | ||
11210 | do { | ||
11211 | fd = n->nfile.fd; | ||
11212 | if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) | ||
11213 | && n->ndup.dupfd == fd) | ||
11214 | continue; /* redirect from/to same file descriptor */ | ||
11215 | |||
11216 | newfd = openredirect(n); | ||
11217 | if (fd == newfd) | ||
11218 | continue; | ||
11219 | if (sv && *(p = &sv->renamed[fd]) == EMPTY) { | ||
11220 | i = fcntl(fd, F_DUPFD, 10); | ||
11221 | |||
11222 | if (i == -1) { | ||
11223 | i = errno; | ||
11224 | if (i != EBADF) { | ||
11225 | close(newfd); | ||
11226 | errno = i; | ||
11227 | ash_msg_and_raise_error("%d: %m", fd); | ||
11228 | /* NOTREACHED */ | ||
11229 | } | ||
11230 | } else { | ||
11231 | *p = i; | ||
11232 | close(fd); | ||
11233 | } | ||
11234 | } else { | ||
11235 | close(fd); | ||
11236 | } | ||
11237 | dupredirect(n, newfd); | ||
11238 | } while ((n = n->nfile.next)); | ||
11239 | INT_ON; | ||
11240 | if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0) | ||
11241 | preverrout_fd = sv->renamed[2]; | ||
11242 | } | ||
11243 | |||
11244 | /* | ||
11245 | * Undo the effects of the last redirection. | ||
11246 | */ | ||
11247 | static void | ||
11248 | popredir(int drop) | ||
11249 | { | ||
11250 | struct redirtab *rp; | ||
11251 | int i; | ||
11252 | |||
11253 | if (--nullredirs >= 0) | ||
11254 | return; | ||
11255 | INT_OFF; | ||
11256 | rp = redirlist; | ||
11257 | for (i = 0; i < 10; i++) { | ||
11258 | if (rp->renamed[i] != EMPTY) { | ||
11259 | if (!drop) { | ||
11260 | close(i); | ||
11261 | copyfd(rp->renamed[i], i); | ||
11262 | } | ||
11263 | close(rp->renamed[i]); | ||
11264 | } | ||
11265 | } | ||
11266 | redirlist = rp->next; | ||
11267 | nullredirs = rp->nullredirs; | ||
11268 | free(rp); | ||
11269 | INT_ON; | ||
11270 | } | ||
11271 | |||
11272 | /* | ||
11273 | * Undo all redirections. Called on error or interrupt. | ||
11274 | */ | ||
11275 | |||
11276 | /* | ||
11277 | * Discard all saved file descriptors. | ||
11278 | */ | ||
11279 | static void | ||
11280 | clearredir(int drop) | ||
11281 | { | ||
11282 | for (;;) { | ||
11283 | nullredirs = 0; | ||
11284 | if (!redirlist) | ||
11285 | break; | ||
11286 | popredir(drop); | ||
11287 | } | ||
11288 | } | ||
11289 | |||
11290 | /* | ||
11291 | * Copy a file descriptor to be >= to. Returns -1 | ||
11292 | * if the source file descriptor is closed, EMPTY if there are no unused | ||
11293 | * file descriptors left. | ||
11294 | */ | ||
11295 | static int | ||
11296 | copyfd(int from, int to) | ||
11297 | { | ||
11298 | int newfd; | ||
11299 | |||
11300 | newfd = fcntl(from, F_DUPFD, to); | ||
11301 | if (newfd < 0) { | ||
11302 | if (errno == EMFILE) | ||
11303 | return EMPTY; | ||
11304 | ash_msg_and_raise_error("%d: %m", from); | ||
11305 | } | ||
11306 | return newfd; | ||
11307 | } | ||
11308 | |||
11309 | static int | ||
11310 | redirectsafe(union node *redir, int flags) | ||
11311 | { | ||
11312 | int err; | ||
11313 | volatile int saveint; | ||
11314 | struct jmploc *volatile savehandler = exception_handler; | ||
11315 | struct jmploc jmploc; | ||
11316 | |||
11317 | SAVE_INT(saveint); | ||
11318 | err = setjmp(jmploc.loc) * 2; | ||
11319 | if (!err) { | ||
11320 | exception_handler = &jmploc; | ||
11321 | redirect(redir, flags); | ||
11322 | } | ||
11323 | exception_handler = savehandler; | ||
11324 | if (err && exception != EXERROR) | ||
11325 | longjmp(exception_handler->loc, 1); | ||
11326 | RESTORE_INT(saveint); | ||
11327 | return err; | ||
11328 | } | ||
11329 | |||
11330 | |||
11331 | /* ============ trap.c */ | 11311 | /* ============ trap.c */ |
11332 | 11312 | ||
11333 | /* | 11313 | /* |