aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-07-30 23:34:04 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-07-31 04:08:09 +0200
commit657e9005a9e31e1da094b260abaa8f335e92301f (patch)
tree6ee40b817a62ef8989532de792bb3a6d13cd19da
parentd07a15bd1ba99caa9386234cda1e8c83897c7553 (diff)
downloadbusybox-w32-657e9005a9e31e1da094b260abaa8f335e92301f.tar.gz
busybox-w32-657e9005a9e31e1da094b260abaa8f335e92301f.tar.bz2
busybox-w32-657e9005a9e31e1da094b260abaa8f335e92301f.zip
hush: massage redirect code to be slightly more like ash
function old new delta save_fd_on_redirect - 203 +203 xdup_CLOEXEC_and_close - 75 +75 setup_redirects 245 250 +5 xdup_and_close 72 - -72 save_fds_on_redirect 221 - -221 ------------------------------------------------------------------------------ (add/remove: 2/2 grow/shrink: 1/0 up/down: 283/-293) Total: -10 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/hush.c109
1 files changed, 72 insertions, 37 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 0fae809b3..d4101d66f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1454,11 +1454,11 @@ static int fcntl_F_DUPFD(int fd, int avoid_fd)
1454 return newfd; 1454 return newfd;
1455} 1455}
1456 1456
1457static int xdup_and_close(int fd, int F_DUPFD_maybe_CLOEXEC, int avoid_fd) 1457static int xdup_CLOEXEC_and_close(int fd, int avoid_fd)
1458{ 1458{
1459 int newfd; 1459 int newfd;
1460 repeat: 1460 repeat:
1461 newfd = fcntl(fd, F_DUPFD_maybe_CLOEXEC, avoid_fd + 1); 1461 newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1);
1462 if (newfd < 0) { 1462 if (newfd < 0) {
1463 if (errno == EBUSY) 1463 if (errno == EBUSY)
1464 goto repeat; 1464 goto repeat;
@@ -1469,6 +1469,8 @@ static int xdup_and_close(int fd, int F_DUPFD_maybe_CLOEXEC, int avoid_fd)
1469 return fd; 1469 return fd;
1470 xfunc_die(); 1470 xfunc_die();
1471 } 1471 }
1472 if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
1473 fcntl(newfd, F_SETFD, FD_CLOEXEC);
1472 close(fd); 1474 close(fd);
1473 return newfd; 1475 return newfd;
1474} 1476}
@@ -1507,7 +1509,7 @@ static int save_FILEs_on_redirect(int fd, int avoid_fd)
1507 while (fl) { 1509 while (fl) {
1508 if (fd == fl->fd) { 1510 if (fd == fl->fd) {
1509 /* We use it only on script files, they are all CLOEXEC */ 1511 /* We use it only on script files, they are all CLOEXEC */
1510 fl->fd = xdup_and_close(fd, F_DUPFD_CLOEXEC, avoid_fd); 1512 fl->fd = xdup_CLOEXEC_and_close(fd, avoid_fd);
1511 debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd); 1513 debug_printf_redir("redirect_fd %d: matches a script fd, moving it to %d\n", fd, fl->fd);
1512 return 1; 1514 return 1;
1513 } 1515 }
@@ -6711,18 +6713,42 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd)
6711 return append_squirrel(sq, i, fd, moved_to); 6713 return append_squirrel(sq, i, fd, moved_to);
6712} 6714}
6713 6715
6716static struct squirrel *add_squirrel_closed(struct squirrel *sq, int fd)
6717{
6718 int i;
6719
6720 i = 0;
6721 if (sq) while (sq[i].orig_fd >= 0) {
6722 /* If we collide with an already moved fd... */
6723 if (fd == sq[i].orig_fd) {
6724 /* Examples:
6725 * "echo 3>FILE 3>&- 3>FILE"
6726 * "echo 3>&- 3>FILE"
6727 * No need for last redirect to insert
6728 * another "need to close 3" indicator.
6729 */
6730 debug_printf_redir("redirect_fd %d: already moved or closed\n", fd);
6731 return sq;
6732 }
6733 i++;
6734 }
6735
6736 debug_printf_redir("redirect_fd %d: previous fd was closed\n", fd);
6737 return append_squirrel(sq, i, fd, -1);
6738}
6739
6714/* fd: redirect wants this fd to be used (e.g. 3>file). 6740/* fd: redirect wants this fd to be used (e.g. 3>file).
6715 * Move all conflicting internally used fds, 6741 * Move all conflicting internally used fds,
6716 * and remember them so that we can restore them later. 6742 * and remember them so that we can restore them later.
6717 */ 6743 */
6718static int save_fds_on_redirect(int fd, int avoid_fd, struct squirrel **sqp) 6744static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
6719{ 6745{
6720 if (avoid_fd < 9) /* the important case here is that it can be -1 */ 6746 if (avoid_fd < 9) /* the important case here is that it can be -1 */
6721 avoid_fd = 9; 6747 avoid_fd = 9;
6722 6748
6723#if ENABLE_HUSH_INTERACTIVE 6749#if ENABLE_HUSH_INTERACTIVE
6724 if (fd != 0 && fd == G.interactive_fd) { 6750 if (fd != 0 && fd == G.interactive_fd) {
6725 G.interactive_fd = xdup_and_close(G.interactive_fd, F_DUPFD_CLOEXEC, avoid_fd); 6751 G.interactive_fd = xdup_CLOEXEC_and_close(G.interactive_fd, avoid_fd);
6726 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd); 6752 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd);
6727 return 1; /* "we closed fd" */ 6753 return 1; /* "we closed fd" */
6728 } 6754 }
@@ -6748,7 +6774,6 @@ static int save_fds_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
6748 6774
6749static void restore_redirects(struct squirrel *sq) 6775static void restore_redirects(struct squirrel *sq)
6750{ 6776{
6751
6752 if (sq) { 6777 if (sq) {
6753 int i = 0; 6778 int i = 0;
6754 while (sq[i].orig_fd >= 0) { 6779 while (sq[i].orig_fd >= 0) {
@@ -6775,13 +6800,15 @@ static void restore_redirects(struct squirrel *sq)
6775 * and stderr if they are redirected. */ 6800 * and stderr if they are redirected. */
6776static int setup_redirects(struct command *prog, struct squirrel **sqp) 6801static int setup_redirects(struct command *prog, struct squirrel **sqp)
6777{ 6802{
6778 int openfd, mode;
6779 struct redir_struct *redir; 6803 struct redir_struct *redir;
6780 6804
6781 for (redir = prog->redirects; redir; redir = redir->next) { 6805 for (redir = prog->redirects; redir; redir = redir->next) {
6806 int newfd;
6807 int closed;
6808
6782 if (redir->rd_type == REDIRECT_HEREDOC2) { 6809 if (redir->rd_type == REDIRECT_HEREDOC2) {
6783 /* "rd_fd<<HERE" case */ 6810 /* "rd_fd<<HERE" case */
6784 save_fds_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp); 6811 save_fd_on_redirect(redir->rd_fd, /*avoid:*/ 0, sqp);
6785 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ 6812 /* for REDIRECT_HEREDOC2, rd_filename holds _contents_
6786 * of the heredoc */ 6813 * of the heredoc */
6787 debug_printf_parse("set heredoc '%s'\n", 6814 debug_printf_parse("set heredoc '%s'\n",
@@ -6793,6 +6820,8 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
6793 if (redir->rd_dup == REDIRFD_TO_FILE) { 6820 if (redir->rd_dup == REDIRFD_TO_FILE) {
6794 /* "rd_fd<*>file" case (<*> is <,>,>>,<>) */ 6821 /* "rd_fd<*>file" case (<*> is <,>,>>,<>) */
6795 char *p; 6822 char *p;
6823 int mode;
6824
6796 if (redir->rd_filename == NULL) { 6825 if (redir->rd_filename == NULL) {
6797 /* 6826 /*
6798 * Examples: 6827 * Examples:
@@ -6804,9 +6833,9 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
6804 } 6833 }
6805 mode = redir_table[redir->rd_type].mode; 6834 mode = redir_table[redir->rd_type].mode;
6806 p = expand_string_to_string(redir->rd_filename, /*unbackslash:*/ 1); 6835 p = expand_string_to_string(redir->rd_filename, /*unbackslash:*/ 1);
6807 openfd = open_or_warn(p, mode); 6836 newfd = open_or_warn(p, mode);
6808 free(p); 6837 free(p);
6809 if (openfd < 0) { 6838 if (newfd < 0) {
6810 /* Error message from open_or_warn can be lost 6839 /* Error message from open_or_warn can be lost
6811 * if stderr has been redirected, but bash 6840 * if stderr has been redirected, but bash
6812 * and ash both lose it as well 6841 * and ash both lose it as well
@@ -6814,40 +6843,46 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
6814 */ 6843 */
6815 return 1; 6844 return 1;
6816 } 6845 }
6817 if (openfd == redir->rd_fd && sqp) { 6846 if (newfd == redir->rd_fd && sqp) {
6818 /* open() gave us precisely the fd we wanted. 6847 /* open() gave us precisely the fd we wanted.
6819 * This means that this fd was not busy 6848 * This means that this fd was not busy
6820 * (not opened to anywhere). 6849 * (not opened to anywhere).
6821 * Remember to close it on restore: 6850 * Remember to close it on restore:
6822 */ 6851 */
6823 struct squirrel *sq = *sqp; 6852 *sqp = add_squirrel_closed(*sqp, newfd);
6824 int i = 0; 6853 debug_printf_redir("redir to previously closed fd %d\n", newfd);
6825 if (sq) while (sq[i].orig_fd >= 0)
6826 i++;
6827 *sqp = append_squirrel(sq, i, openfd, -1); /* -1 = "it was closed" */
6828 debug_printf_redir("redir to previously closed fd %d\n", openfd);
6829 } 6854 }
6830 } else { 6855 } else {
6831 /* "rd_fd<*>rd_dup" or "rd_fd<*>-" cases */ 6856 /* "rd_fd>&rd_dup" or "rd_fd>&-" case */
6832 openfd = redir->rd_dup; 6857 newfd = redir->rd_dup;
6833 } 6858 }
6834 6859
6835 if (openfd != redir->rd_fd) { 6860 if (newfd == redir->rd_fd)
6836 int closed = save_fds_on_redirect(redir->rd_fd, /*avoid:*/ openfd, sqp); 6861 continue;
6837 if (openfd == REDIRFD_CLOSE) { 6862
6838 /* "rd_fd >&-" means "close me" */ 6863 /* if "N>FILE": move newfd to redir->rd_fd */
6839 if (!closed) { 6864 /* if "N>&M": dup newfd to redir->rd_fd */
6840 /* ^^^ optimization: saving may already 6865 /* if "N>&-": close redir->rd_fd (newfd is REDIRFD_CLOSE) */
6841 * have closed it. If not... */ 6866
6842 close(redir->rd_fd); 6867 closed = save_fd_on_redirect(redir->rd_fd, /*avoid:*/ newfd, sqp);
6843 } 6868 if (newfd == REDIRFD_CLOSE) {
6844 } else { 6869 /* "N>&-" means "close me" */
6845 xdup2(openfd, redir->rd_fd); 6870 if (!closed) {
6846 if (redir->rd_dup == REDIRFD_TO_FILE) 6871 /* ^^^ optimization: saving may already
6847 /* "rd_fd > FILE" */ 6872 * have closed it. If not... */
6848 close(openfd); 6873 close(redir->rd_fd);
6849 /* else: "rd_fd > rd_dup" */ 6874 }
6850 } 6875 /* Sometimes we do another close on restore, getting EBADF.
6876 * Consider "echo 3>FILE 3>&-"
6877 * first redirect remembers "need to close 3",
6878 * and second redirect closes 3! Restore code then closes 3 again.
6879 */
6880 } else {
6881 xdup2(newfd, redir->rd_fd);
6882 if (redir->rd_dup == REDIRFD_TO_FILE)
6883 /* "rd_fd > FILE" */
6884 close(newfd);
6885 /* else: "rd_fd > rd_dup" */
6851 } 6886 }
6852 } 6887 }
6853 return 0; 6888 return 0;