1 /* $Id: cmd-pipe-pane.c,v 1.10 2009-12-04 22:14:47 tcunha Exp $ */
4 * Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
20 #include <sys/socket.h>
30 * Open pipe to redirect pane output. If already open, close first.
33 int cmd_pipe_pane_exec(struct cmd
*, struct cmd_ctx
*);
35 void cmd_pipe_pane_error_callback(struct bufferevent
*, short, void *);
37 const struct cmd_entry cmd_pipe_pane_entry
= {
39 CMD_TARGET_PANE_USAGE
"[-o] [command]",
49 cmd_pipe_pane_exec(struct cmd
*self
, struct cmd_ctx
*ctx
)
51 struct cmd_target_data
*data
= self
->data
;
52 struct window_pane
*wp
;
53 int old_fd
, pipe_fd
[2], null_fd
, mode
;
55 if (cmd_find_pane(ctx
, data
->target
, NULL
, &wp
) == NULL
)
58 /* Destroy the old pipe. */
60 if (wp
->pipe_fd
!= -1) {
61 bufferevent_free(wp
->pipe_event
);
66 /* If no pipe command, that is enough. */
67 if (data
->arg
== NULL
|| *data
->arg
== '\0')
71 * With -o, only open the new pipe if there was no previous one. This
72 * allows a pipe to be toggled with a single key, for example:
74 * bind ^p pipep -o 'cat >>~/output'
76 if (cmd_check_flag(data
->chflags
, 'o') && old_fd
!= -1)
79 /* Open the new pipe. */
80 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, pipe_fd
) != 0) {
81 ctx
->error(ctx
, "socketpair error: %s", strerror(errno
));
88 ctx
->error(ctx
, "fork error: %s", strerror(errno
));
93 server_signal_clear();
95 if (dup2(pipe_fd
[1], STDIN_FILENO
) == -1)
97 if (pipe_fd
[1] != STDIN_FILENO
)
100 null_fd
= open(_PATH_DEVNULL
, O_WRONLY
, 0);
101 if (dup2(null_fd
, STDOUT_FILENO
) == -1)
103 if (dup2(null_fd
, STDERR_FILENO
) == -1)
105 if (null_fd
!= STDOUT_FILENO
&& null_fd
!= STDERR_FILENO
)
108 execl(_PATH_BSHELL
, "sh", "-c", data
->arg
, (char *) NULL
);
111 /* Parent process. */
114 wp
->pipe_fd
= pipe_fd
[0];
115 wp
->pipe_off
= EVBUFFER_LENGTH(wp
->event
->input
);
117 wp
->pipe_event
= bufferevent_new(wp
->pipe_fd
,
118 NULL
, NULL
, cmd_pipe_pane_error_callback
, wp
);
119 bufferevent_enable(wp
->pipe_event
, EV_WRITE
);
121 if ((mode
= fcntl(wp
->pipe_fd
, F_GETFL
)) == -1)
122 fatal("fcntl failed");
123 if (fcntl(wp
->pipe_fd
, F_SETFL
, mode
|O_NONBLOCK
) == -1)
124 fatal("fcntl failed");
125 if (fcntl(wp
->pipe_fd
, F_SETFD
, FD_CLOEXEC
) == -1)
126 fatal("fcntl failed");
133 cmd_pipe_pane_error_callback(
134 unused
struct bufferevent
*bufev
, unused
short what
, void *data
)
136 struct window_pane
*wp
= data
;
138 bufferevent_free(wp
->pipe_event
);