4 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
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/ioctl.h>
21 #include <sys/socket.h>
35 * Job scheduling. Run queued commands in the background and record their
39 static void job_read_callback(struct bufferevent
*, void *);
40 static void job_write_callback(struct bufferevent
*, void *);
41 static void job_error_callback(struct bufferevent
*, short, void *);
55 char tty
[TTY_NAME_MAX
];
59 struct bufferevent
*event
;
61 job_update_cb updatecb
;
62 job_complete_cb completecb
;
66 LIST_ENTRY(job
) entry
;
70 static LIST_HEAD(joblist
, job
) all_jobs
= LIST_HEAD_INITIALIZER(all_jobs
);
72 /* Start a job running. */
74 job_run(const char *cmd
, int argc
, char **argv
, struct environ
*e
, struct session
*s
,
75 const char *cwd
, job_update_cb updatecb
, job_complete_cb completecb
,
76 job_free_cb freecb
, void *data
, int flags
, int sx
, int sy
)
81 int nullfd
, out
[2], master
;
82 const char *home
, *shell
;
85 char **argvp
, tty
[TTY_NAME_MAX
], *argv0
;
88 * Do not set TERM during .tmux.conf (second argument here), it is nice
89 * to be able to use if-shell to decide on default-terminal based on
92 env
= environ_for_session(s
, !cfg_finished
);
97 shell
= options_get_string(s
->options
, "default-shell");
99 shell
= options_get_string(global_s_options
, "default-shell");
100 if (!checkshell(shell
))
101 shell
= _PATH_BSHELL
;
102 argv0
= shell_argv0(shell
, 0);
105 sigprocmask(SIG_BLOCK
, &set
, &oldset
);
107 if (flags
& JOB_PTY
) {
108 memset(&ws
, 0, sizeof ws
);
111 pid
= fdforkpty(ptm_fd
, &master
, tty
, NULL
, &ws
);
113 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, out
) != 0)
118 cmd_log_argv(argc
, argv
, "%s:", __func__
);
119 log_debug("%s: cwd=%s, shell=%s", __func__
,
120 cwd
== NULL
? "" : cwd
, shell
);
122 log_debug("%s: cmd=%s, cwd=%s, shell=%s", __func__
, cmd
,
123 cwd
== NULL
? "" : cwd
, shell
);
128 if (~flags
& JOB_PTY
) {
134 proc_clear_signals(server_proc
, 1);
135 sigprocmask(SIG_SETMASK
, &oldset
, NULL
);
137 if ((cwd
== NULL
|| chdir(cwd
) != 0) &&
138 ((home
= find_home()) == NULL
|| chdir(home
) != 0) &&
140 fatal("chdir failed");
145 if (~flags
& JOB_PTY
) {
146 if (dup2(out
[1], STDIN_FILENO
) == -1)
147 fatal("dup2 failed");
148 if (dup2(out
[1], STDOUT_FILENO
) == -1)
149 fatal("dup2 failed");
150 if (out
[1] != STDIN_FILENO
&& out
[1] != STDOUT_FILENO
)
154 nullfd
= open(_PATH_DEVNULL
, O_RDWR
);
156 fatal("open failed");
157 if (dup2(nullfd
, STDERR_FILENO
) == -1)
158 fatal("dup2 failed");
159 if (nullfd
!= STDERR_FILENO
)
162 closefrom(STDERR_FILENO
+ 1);
165 setenv("SHELL", shell
, 1);
166 execl(shell
, argv0
, "-c", cmd
, (char *)NULL
);
167 fatal("execl failed");
169 argvp
= cmd_copy_argv(argc
, argv
);
170 execvp(argvp
[0], argvp
);
171 fatal("execvp failed");
175 sigprocmask(SIG_SETMASK
, &oldset
, NULL
);
179 job
= xmalloc(sizeof *job
);
180 job
->state
= JOB_RUNNING
;
184 job
->cmd
= xstrdup(cmd
);
186 job
->cmd
= cmd_stringify_argv(argc
, argv
);
188 strlcpy(job
->tty
, tty
, sizeof job
->tty
);
191 LIST_INSERT_HEAD(&all_jobs
, job
, entry
);
193 job
->updatecb
= updatecb
;
194 job
->completecb
= completecb
;
195 job
->freecb
= freecb
;
198 if (~flags
& JOB_PTY
) {
203 setblocking(job
->fd
, 0);
205 job
->event
= bufferevent_new(job
->fd
, job_read_callback
,
206 job_write_callback
, job_error_callback
, job
);
207 if (job
->event
== NULL
)
208 fatalx("out of memory");
209 bufferevent_enable(job
->event
, EV_READ
|EV_WRITE
);
211 log_debug("run job %p: %s, pid %ld", job
, job
->cmd
, (long)job
->pid
);
215 sigprocmask(SIG_SETMASK
, &oldset
, NULL
);
221 /* Take job's file descriptor and free the job. */
223 job_transfer(struct job
*job
, pid_t
*pid
, char *tty
, size_t ttylen
)
227 log_debug("transfer job %p: %s", job
, job
->cmd
);
232 strlcpy(tty
, job
->tty
, ttylen
);
234 LIST_REMOVE(job
, entry
);
237 if (job
->freecb
!= NULL
&& job
->data
!= NULL
)
238 job
->freecb(job
->data
);
240 if (job
->event
!= NULL
)
241 bufferevent_free(job
->event
);
247 /* Kill and free an individual job. */
249 job_free(struct job
*job
)
251 log_debug("free job %p: %s", job
, job
->cmd
);
253 LIST_REMOVE(job
, entry
);
256 if (job
->freecb
!= NULL
&& job
->data
!= NULL
)
257 job
->freecb(job
->data
);
260 kill(job
->pid
, SIGTERM
);
261 if (job
->event
!= NULL
)
262 bufferevent_free(job
->event
);
271 job_resize(struct job
*job
, u_int sx
, u_int sy
)
275 if (job
->fd
== -1 || (~job
->flags
& JOB_PTY
))
278 log_debug("resize job %p: %ux%u", job
, sx
, sy
);
280 memset(&ws
, 0, sizeof ws
);
283 if (ioctl(job
->fd
, TIOCSWINSZ
, &ws
) == -1)
284 fatal("ioctl failed");
287 /* Job buffer read callback. */
289 job_read_callback(__unused
struct bufferevent
*bufev
, void *data
)
291 struct job
*job
= data
;
293 if (job
->updatecb
!= NULL
)
298 * Job buffer write callback. Fired when the buffer falls below watermark
299 * (default is empty). If all the data has been written, disable the write
303 job_write_callback(__unused
struct bufferevent
*bufev
, void *data
)
305 struct job
*job
= data
;
306 size_t len
= EVBUFFER_LENGTH(EVBUFFER_OUTPUT(job
->event
));
308 log_debug("job write %p: %s, pid %ld, output left %zu", job
, job
->cmd
,
309 (long) job
->pid
, len
);
311 if (len
== 0 && (~job
->flags
& JOB_KEEPWRITE
)) {
312 shutdown(job
->fd
, SHUT_WR
);
313 bufferevent_disable(job
->event
, EV_WRITE
);
317 /* Job buffer error callback. */
319 job_error_callback(__unused
struct bufferevent
*bufev
, __unused
short events
,
322 struct job
*job
= data
;
324 log_debug("job error %p: %s, pid %ld", job
, job
->cmd
, (long) job
->pid
);
326 if (job
->state
== JOB_DEAD
) {
327 if (job
->completecb
!= NULL
)
328 job
->completecb(job
);
331 bufferevent_disable(job
->event
, EV_READ
);
332 job
->state
= JOB_CLOSED
;
336 /* Job died (waitpid() returned its pid). */
338 job_check_died(pid_t pid
, int status
)
342 LIST_FOREACH(job
, &all_jobs
, entry
) {
348 if (WIFSTOPPED(status
)) {
349 if (WSTOPSIG(status
) == SIGTTIN
|| WSTOPSIG(status
) == SIGTTOU
)
351 killpg(job
->pid
, SIGCONT
);
354 log_debug("job died %p: %s, pid %ld", job
, job
->cmd
, (long) job
->pid
);
356 job
->status
= status
;
358 if (job
->state
== JOB_CLOSED
) {
359 if (job
->completecb
!= NULL
)
360 job
->completecb(job
);
364 job
->state
= JOB_DEAD
;
368 /* Get job status. */
370 job_get_status(struct job
*job
)
372 return (job
->status
);
377 job_get_data(struct job
*job
)
384 job_get_event(struct job
*job
)
395 LIST_FOREACH(job
, &all_jobs
, entry
) {
397 kill(job
->pid
, SIGTERM
);
401 /* Are any jobs still running? */
403 job_still_running(void)
407 LIST_FOREACH(job
, &all_jobs
, entry
) {
408 if ((~job
->flags
& JOB_NOWAIT
) && job
->state
== JOB_RUNNING
)
414 /* Print job summary. */
416 job_print_summary(struct cmdq_item
*item
, int blank
)
421 LIST_FOREACH(job
, &all_jobs
, entry
) {
423 cmdq_print(item
, "%s", "");
426 cmdq_print(item
, "Job %u: %s [fd=%d, pid=%ld, status=%d]",
427 n
, job
->cmd
, job
->fd
, (long)job
->pid
, job
->status
);