Merge branch 'obsd-master'
[tmux.git] / job.c
blobd2d9adbfdd4d3206cf083fd29cf5a59cd983a1c3
1 /* $OpenBSD$ */
3 /*
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>
22 #include <sys/wait.h>
24 #include <fcntl.h>
25 #include <signal.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
30 #include "tmux.h"
33 * Job scheduling. Run queued commands in the background and record their
34 * output.
37 static void job_read_callback(struct bufferevent *, void *);
38 static void job_write_callback(struct bufferevent *, void *);
39 static void job_error_callback(struct bufferevent *, short, void *);
41 /* A single job. */
42 struct job {
43 enum {
44 JOB_RUNNING,
45 JOB_DEAD,
46 JOB_CLOSED
47 } state;
49 int flags;
51 char *cmd;
52 pid_t pid;
53 char tty[TTY_NAME_MAX];
54 int status;
56 int fd;
57 struct bufferevent *event;
59 job_update_cb updatecb;
60 job_complete_cb completecb;
61 job_free_cb freecb;
62 void *data;
64 LIST_ENTRY(job) entry;
67 /* All jobs list. */
68 static LIST_HEAD(joblist, job) all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
70 /* Start a job running. */
71 struct job *
72 job_run(const char *cmd, int argc, char **argv, struct environ *e, struct session *s,
73 const char *cwd, job_update_cb updatecb, job_complete_cb completecb,
74 job_free_cb freecb, void *data, int flags, int sx, int sy)
76 struct job *job;
77 struct environ *env;
78 pid_t pid;
79 int nullfd, out[2], master;
80 const char *home;
81 sigset_t set, oldset;
82 struct winsize ws;
83 char **argvp, tty[TTY_NAME_MAX];
86 * Do not set TERM during .tmux.conf, it is nice to be able to use
87 * if-shell to decide on default-terminal based on outside TERM.
89 env = environ_for_session(s, !cfg_finished);
90 if (e != NULL)
91 environ_copy(e, env);
93 sigfillset(&set);
94 sigprocmask(SIG_BLOCK, &set, &oldset);
96 if (flags & JOB_PTY) {
97 memset(&ws, 0, sizeof ws);
98 ws.ws_col = sx;
99 ws.ws_row = sy;
100 pid = fdforkpty(ptm_fd, &master, tty, NULL, &ws);
101 } else {
102 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0)
103 goto fail;
104 pid = fork();
106 if (cmd == NULL) {
107 cmd_log_argv(argc, argv, "%s:", __func__);
108 log_debug("%s: cwd=%s", __func__, cwd == NULL ? "" : cwd);
109 } else {
110 log_debug("%s: cmd=%s, cwd=%s", __func__, cmd,
111 cwd == NULL ? "" : cwd);
114 switch (pid) {
115 case -1:
116 if (~flags & JOB_PTY) {
117 close(out[0]);
118 close(out[1]);
120 goto fail;
121 case 0:
122 proc_clear_signals(server_proc, 1);
123 sigprocmask(SIG_SETMASK, &oldset, NULL);
125 if ((cwd == NULL || chdir(cwd) != 0) &&
126 ((home = find_home()) == NULL || chdir(home) != 0) &&
127 chdir("/") != 0)
128 fatal("chdir failed");
130 environ_push(env);
131 environ_free(env);
133 if (~flags & JOB_PTY) {
134 if (dup2(out[1], STDIN_FILENO) == -1)
135 fatal("dup2 failed");
136 if (dup2(out[1], STDOUT_FILENO) == -1)
137 fatal("dup2 failed");
138 if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO)
139 close(out[1]);
140 close(out[0]);
142 nullfd = open(_PATH_DEVNULL, O_RDWR);
143 if (nullfd == -1)
144 fatal("open failed");
145 if (dup2(nullfd, STDERR_FILENO) == -1)
146 fatal("dup2 failed");
147 if (nullfd != STDERR_FILENO)
148 close(nullfd);
150 closefrom(STDERR_FILENO + 1);
152 if (cmd != NULL) {
153 execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
154 fatal("execl failed");
155 } else {
156 argvp = cmd_copy_argv(argc, argv);
157 execvp(argvp[0], argvp);
158 fatal("execvp failed");
162 sigprocmask(SIG_SETMASK, &oldset, NULL);
163 environ_free(env);
165 job = xmalloc(sizeof *job);
166 job->state = JOB_RUNNING;
167 job->flags = flags;
169 if (cmd != NULL)
170 job->cmd = xstrdup(cmd);
171 else
172 job->cmd = cmd_stringify_argv(argc, argv);
173 job->pid = pid;
174 strlcpy(job->tty, tty, sizeof job->tty);
175 job->status = 0;
177 LIST_INSERT_HEAD(&all_jobs, job, entry);
179 job->updatecb = updatecb;
180 job->completecb = completecb;
181 job->freecb = freecb;
182 job->data = data;
184 if (~flags & JOB_PTY) {
185 close(out[1]);
186 job->fd = out[0];
187 } else
188 job->fd = master;
189 setblocking(job->fd, 0);
191 job->event = bufferevent_new(job->fd, job_read_callback,
192 job_write_callback, job_error_callback, job);
193 if (job->event == NULL)
194 fatalx("out of memory");
195 bufferevent_enable(job->event, EV_READ|EV_WRITE);
197 log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
198 return (job);
200 fail:
201 sigprocmask(SIG_SETMASK, &oldset, NULL);
202 environ_free(env);
203 return (NULL);
206 /* Take job's file descriptor and free the job. */
208 job_transfer(struct job *job, pid_t *pid, char *tty, size_t ttylen)
210 int fd = job->fd;
212 log_debug("transfer job %p: %s", job, job->cmd);
214 if (pid != NULL)
215 *pid = job->pid;
216 if (tty != NULL)
217 strlcpy(tty, job->tty, ttylen);
219 LIST_REMOVE(job, entry);
220 free(job->cmd);
222 if (job->freecb != NULL && job->data != NULL)
223 job->freecb(job->data);
225 if (job->event != NULL)
226 bufferevent_free(job->event);
228 free(job);
229 return (fd);
232 /* Kill and free an individual job. */
233 void
234 job_free(struct job *job)
236 log_debug("free job %p: %s", job, job->cmd);
238 LIST_REMOVE(job, entry);
239 free(job->cmd);
241 if (job->freecb != NULL && job->data != NULL)
242 job->freecb(job->data);
244 if (job->pid != -1)
245 kill(job->pid, SIGTERM);
246 if (job->event != NULL)
247 bufferevent_free(job->event);
248 if (job->fd != -1)
249 close(job->fd);
251 free(job);
254 /* Resize job. */
255 void
256 job_resize(struct job *job, u_int sx, u_int sy)
258 struct winsize ws;
260 if (job->fd == -1 || (~job->flags & JOB_PTY))
261 return;
263 log_debug("resize job %p: %ux%u", job, sx, sy);
265 memset(&ws, 0, sizeof ws);
266 ws.ws_col = sx;
267 ws.ws_row = sy;
268 if (ioctl(job->fd, TIOCSWINSZ, &ws) == -1)
269 fatal("ioctl failed");
272 /* Job buffer read callback. */
273 static void
274 job_read_callback(__unused struct bufferevent *bufev, void *data)
276 struct job *job = data;
278 if (job->updatecb != NULL)
279 job->updatecb(job);
283 * Job buffer write callback. Fired when the buffer falls below watermark
284 * (default is empty). If all the data has been written, disable the write
285 * event.
287 static void
288 job_write_callback(__unused struct bufferevent *bufev, void *data)
290 struct job *job = data;
291 size_t len = EVBUFFER_LENGTH(EVBUFFER_OUTPUT(job->event));
293 log_debug("job write %p: %s, pid %ld, output left %zu", job, job->cmd,
294 (long) job->pid, len);
296 if (len == 0 && (~job->flags & JOB_KEEPWRITE)) {
297 shutdown(job->fd, SHUT_WR);
298 bufferevent_disable(job->event, EV_WRITE);
302 /* Job buffer error callback. */
303 static void
304 job_error_callback(__unused struct bufferevent *bufev, __unused short events,
305 void *data)
307 struct job *job = data;
309 log_debug("job error %p: %s, pid %ld", job, job->cmd, (long) job->pid);
311 if (job->state == JOB_DEAD) {
312 if (job->completecb != NULL)
313 job->completecb(job);
314 job_free(job);
315 } else {
316 bufferevent_disable(job->event, EV_READ);
317 job->state = JOB_CLOSED;
321 /* Job died (waitpid() returned its pid). */
322 void
323 job_check_died(pid_t pid, int status)
325 struct job *job;
327 LIST_FOREACH(job, &all_jobs, entry) {
328 if (pid == job->pid)
329 break;
331 if (job == NULL)
332 return;
333 if (WIFSTOPPED(status)) {
334 if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
335 return;
336 killpg(job->pid, SIGCONT);
337 return;
339 log_debug("job died %p: %s, pid %ld", job, job->cmd, (long) job->pid);
341 job->status = status;
343 if (job->state == JOB_CLOSED) {
344 if (job->completecb != NULL)
345 job->completecb(job);
346 job_free(job);
347 } else {
348 job->pid = -1;
349 job->state = JOB_DEAD;
353 /* Get job status. */
355 job_get_status(struct job *job)
357 return (job->status);
360 /* Get job data. */
361 void *
362 job_get_data(struct job *job)
364 return (job->data);
367 /* Get job event. */
368 struct bufferevent *
369 job_get_event(struct job *job)
371 return (job->event);
374 /* Kill all jobs. */
375 void
376 job_kill_all(void)
378 struct job *job;
380 LIST_FOREACH(job, &all_jobs, entry) {
381 if (job->pid != -1)
382 kill(job->pid, SIGTERM);
386 /* Are any jobs still running? */
388 job_still_running(void)
390 struct job *job;
392 LIST_FOREACH(job, &all_jobs, entry) {
393 if ((~job->flags & JOB_NOWAIT) && job->state == JOB_RUNNING)
394 return (1);
396 return (0);
399 /* Print job summary. */
400 void
401 job_print_summary(struct cmdq_item *item, int blank)
403 struct job *job;
404 u_int n = 0;
406 LIST_FOREACH(job, &all_jobs, entry) {
407 if (blank) {
408 cmdq_print(item, "%s", "");
409 blank = 0;
411 cmdq_print(item, "Job %u: %s [fd=%d, pid=%ld, status=%d]",
412 n, job->cmd, job->fd, (long)job->pid, job->status);
413 n++;