aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-02-23 21:10:47 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-02-23 21:10:47 +0000
commit0dec6de38b721b4faae5567f8b4643df1055a175 (patch)
tree80dca3727327907efc3e9d6d6261eecc248fa72e
parentcc5715184bf91fa5a6bb7d4423e6c7aed71a98ef (diff)
downloadbusybox-w32-0dec6de38b721b4faae5567f8b4643df1055a175.tar.gz
busybox-w32-0dec6de38b721b4faae5567f8b4643df1055a175.tar.bz2
busybox-w32-0dec6de38b721b4faae5567f8b4643df1055a175.zip
ash: cleanup part 2.7
-rw-r--r--shell/ash.c962
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
1594static struct shparam shellparam; /* $@ current positional parameters */ 1594static struct shparam shellparam; /* $@ current positional parameters */
1595 1595
1596/*
1597 * Free the list of positional parameters.
1598 */
1599static void
1600freeparam(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
1597static void 1612static void
1598getoptsreset(const char *value) 1613getoptsreset(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
2876static void optschanged(void);
2877static void setparam(char **);
2878static void freeparam(volatile struct shparam *);
2879static int shiftcmd(int, char **);
2880static int setcmd(int, char **);
2881static 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
2890static void redirect(union node *, int);
2891static void popredir(int);
2892static void clearredir(int);
2893static int copyfd(int, int);
2894static 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 */
4633static int
4634noclobberopen(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 */
4693static void expandhere(union node *arg, int fd);
4694static int
4695openhere(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
4729static int
4730openredirect(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 */
4797static int
4798copyfd(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
4811static void
4812dupredirect(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 */
4839static void
4840redirect(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 */
4903static void
4904popredir(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 */
4935static void
4936clearredir(int drop)
4937{
4938 for (;;) {
4939 nullredirs = 0;
4940 if (!redirlist)
4941 break;
4942 popredir(drop);
4943 }
4944}
4945
4946static int
4947redirectsafe(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 */
7824static void
7825setinteractive(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
7862static void
7863optschanged(void)
7864{
7865#if DEBUG
7866 opentrace();
7867#endif
7868 setinteractive(iflag);
7869 setjobctl(mflag);
7870 setvimode(viflag);
7871}
7872
7478static struct localvar *localvars; 7873static 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 */
8684static char *
8685find_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 */
8714static void 9078static void
8715setinteractive(int on) 9079setparam(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
8752static void
8753optschanged(void)
8754{
8755#if DEBUG
8756 opentrace();
8757#endif
8758 setinteractive(iflag);
8759 setjobctl(mflag);
8760 setvimode(viflag);
8761}
8762
8763static void 9105static void
8764minus_o(char *name, int val) 9106minus_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
8783static void 9124static void
8784setoption(int flag, int val) 9125setoption(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 */
8802static void 9138static void
8803options(int cmdline) 9139options(int cmdline)
8804{ 9140{
@@ -8849,47 +9185,6 @@ options(int cmdline)
8849} 9185}
8850 9186
8851/* 9187/*
8852 * Set the shell parameters.
8853 */
8854static void
8855setparam(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 */
8880static void
8881freeparam(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 */
8895static int 9190static 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 */
11022static char *
11023find_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
10723static int 11049static int
10724dotcmd(int argc, char **argv) 11050dotcmd(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 */
11001static int
11002noclobberopen(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 */
11060static int
11061openhere(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
11095static int
11096openredirect(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
11158static void
11159dupredirect(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 */
11183static void
11184redirect(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 */
11247static void
11248popredir(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 */
11279static void
11280clearredir(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 */
11295static int
11296copyfd(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
11309static int
11310redirectsafe(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/*