Annotation of src/usr.bin/tmux/cmd-pipe-pane.c, Revision 1.1
1.1 ! nicm 1: /* $OpenBSD: cmd-select-pane.c,v 1.7 2009/07/30 13:45:56 nicm Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
! 15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
! 16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: #include <sys/types.h>
! 20:
! 21: #include <errno.h>
! 22: #include <fcntl.h>
! 23: #include <paths.h>
! 24: #include <string.h>
! 25: #include <unistd.h>
! 26:
! 27: #include "tmux.h"
! 28:
! 29: /*
! 30: * Open pipe to redirect pane output. If already open, close first.
! 31: */
! 32:
! 33: int cmd_pipe_pane_exec(struct cmd *, struct cmd_ctx *);
! 34:
! 35: const struct cmd_entry cmd_pipe_pane_entry = {
! 36: "pipe-pane", "pipep",
! 37: CMD_TARGET_PANE_USAGE "[-o] [command]",
! 38: CMD_ARG01, CMD_CHFLAG('o'),
! 39: cmd_target_init,
! 40: cmd_target_parse,
! 41: cmd_pipe_pane_exec,
! 42: cmd_target_free,
! 43: cmd_target_print
! 44: };
! 45:
! 46: int
! 47: cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
! 48: {
! 49: struct cmd_target_data *data = self->data;
! 50: struct winlink *wl;
! 51: struct window_pane *wp;
! 52: int old_fd, pipe_fd[2], null_fd, mode;
! 53:
! 54: if ((wl = cmd_find_pane(ctx, data->target, NULL, &wp)) == NULL)
! 55: return (-1);
! 56:
! 57: /* Destroy the old pipe. */
! 58: old_fd = wp->pipe_fd;
! 59: if (wp->pipe_fd != -1) {
! 60: buffer_destroy(wp->pipe_buf);
! 61: close(wp->pipe_fd);
! 62: wp->pipe_fd = -1;
! 63: }
! 64:
! 65: /* If no pipe command, that is enough. */
! 66: if (data->arg == NULL || *data->arg == '\0')
! 67: return (0);
! 68:
! 69: /*
! 70: * With -o, only open the new pipe if there was no previous one. This
! 71: * allows a pipe to be toggled with a single key, for example:
! 72: *
! 73: * bind ^p pipep -o 'cat >>~/output'
! 74: */
! 75: if (data->chflags & CMD_CHFLAG('o') && old_fd != -1)
! 76: return (0);
! 77:
! 78: /* Open the new pipe. */
! 79: if (pipe(pipe_fd) != 0) {
! 80: ctx->error(ctx, "pipe error: %s", strerror(errno));
! 81: return (-1);
! 82: }
! 83:
! 84: /* Fork the child. */
! 85: switch (fork()) {
! 86: case -1:
! 87: ctx->error(ctx, "fork error: %s", strerror(errno));
! 88: return (-1);
! 89: case 0:
! 90: /* Child process. */
! 91: close(pipe_fd[0]);
! 92: sigreset();
! 93:
! 94: if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
! 95: _exit(1);
! 96: if (pipe_fd[1] != STDIN_FILENO)
! 97: close(pipe_fd[1]);
! 98:
! 99: null_fd = open(_PATH_DEVNULL, O_WRONLY, 0);
! 100: if (dup2(null_fd, STDOUT_FILENO) == -1)
! 101: _exit(1);
! 102: if (dup2(null_fd, STDERR_FILENO) == -1)
! 103: _exit(1);
! 104: if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO)
! 105: close(null_fd);
! 106:
! 107: execl(_PATH_BSHELL, "sh", "-c", data->arg, (char *) NULL);
! 108: _exit(1);
! 109: default:
! 110: /* Parent process. */
! 111: close(pipe_fd[1]);
! 112:
! 113: wp->pipe_fd = pipe_fd[0];
! 114: wp->pipe_buf = buffer_create(BUFSIZ);
! 115: wp->pipe_off = BUFFER_USED(wp->in);
! 116:
! 117: if ((mode = fcntl(wp->pipe_fd, F_GETFL)) == -1)
! 118: fatal("fcntl failed");
! 119: if (fcntl(wp->pipe_fd, F_SETFL, mode|O_NONBLOCK) == -1)
! 120: fatal("fcntl failed");
! 121: if (fcntl(wp->pipe_fd, F_SETFD, FD_CLOEXEC) == -1)
! 122: fatal("fcntl failed");
! 123: return (0);
! 124: }
! 125:
! 126: return (0);
! 127: }