tmux  3.2a
About: tmux is a terminal multiplexer that lets you switch easily between several programs in one terminal.
  Fossies Dox: tmux-3.2a.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

job.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
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 #include <sys/ioctl.h>
21 #include <sys/socket.h>
22 #include <sys/wait.h>
23 
24 #include <fcntl.h>
25 #include <signal.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include "tmux.h"
31 
32 /*
33  * Job scheduling. Run queued commands in the background and record their
34  * output.
35  */
36 
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 *);
40 
41 /* A single job. */
42 struct job {
43  enum {
47  } state;
48 
49  int flags;
50 
51  char *cmd;
52  pid_t pid;
53  int status;
54 
55  int fd;
56  struct bufferevent *event;
57 
61  void *data;
62 
63  LIST_ENTRY(job) entry;
64 };
65 
66 /* All jobs list. */
67 static LIST_HEAD(joblist, job) all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
68 
69 /* Start a job running. */
70 struct job *
71 job_run(const char *cmd, int argc, char **argv, struct session *s,
73  job_free_cb freecb, void *data, int flags, int sx, int sy)
74 {
75  struct job *job;
76  struct environ *env;
77  pid_t pid;
78  int nullfd, out[2], master;
79  const char *home;
80  sigset_t set, oldset;
81  struct winsize ws;
82  char **argvp;
83 
84  /*
85  * Do not set TERM during .tmux.conf, it is nice to be able to use
86  * if-shell to decide on default-terminal based on outside TERM.
87  */
89 
90  sigfillset(&set);
91  sigprocmask(SIG_BLOCK, &set, &oldset);
92 
93  if (flags & JOB_PTY) {
94  memset(&ws, 0, sizeof ws);
95  ws.ws_col = sx;
96  ws.ws_row = sy;
97  pid = fdforkpty(ptm_fd, &master, NULL, NULL, &ws);
98  } else {
99  if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0)
100  goto fail;
101  pid = fork();
102  }
103  if (cmd == NULL) {
104  cmd_log_argv(argc, argv, "%s:", __func__);
105  log_debug("%s: cwd=%s", __func__, cwd == NULL ? "" : cwd);
106  } else {
107  log_debug("%s: cmd=%s, cwd=%s", __func__, cmd,
108  cwd == NULL ? "" : cwd);
109  }
110 
111  switch (pid) {
112  case -1:
113  if (~flags & JOB_PTY) {
114  close(out[0]);
115  close(out[1]);
116  }
117  goto fail;
118  case 0:
120  sigprocmask(SIG_SETMASK, &oldset, NULL);
121 
122  if ((cwd == NULL || chdir(cwd) != 0) &&
123  ((home = find_home()) == NULL || chdir(home) != 0) &&
124  chdir("/") != 0)
125  fatal("chdir failed");
126 
127  environ_push(env);
128  environ_free(env);
129 
130  if (~flags & JOB_PTY) {
131  if (dup2(out[1], STDIN_FILENO) == -1)
132  fatal("dup2 failed");
133  if (dup2(out[1], STDOUT_FILENO) == -1)
134  fatal("dup2 failed");
135  if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO)
136  close(out[1]);
137  close(out[0]);
138 
139  nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
140  if (nullfd == -1)
141  fatal("open failed");
142  if (dup2(nullfd, STDERR_FILENO) == -1)
143  fatal("dup2 failed");
144  if (nullfd != STDERR_FILENO)
145  close(nullfd);
146  }
147  closefrom(STDERR_FILENO + 1);
148 
149  if (cmd != NULL) {
150  execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
151  fatal("execl failed");
152  } else {
153  argvp = cmd_copy_argv(argc, argv);
154  execvp(argvp[0], argvp);
155  fatal("execvp failed");
156  }
157  }
158 
159  sigprocmask(SIG_SETMASK, &oldset, NULL);
160  environ_free(env);
161 
162  job = xmalloc(sizeof *job);
163  job->state = JOB_RUNNING;
164  job->flags = flags;
165 
166  if (cmd != NULL)
167  job->cmd = xstrdup(cmd);
168  else
169  job->cmd = cmd_stringify_argv(argc, argv);
170  job->pid = pid;
171  job->status = 0;
172 
173  LIST_INSERT_HEAD(&all_jobs, job, entry);
174 
175  job->updatecb = updatecb;
176  job->completecb = completecb;
177  job->freecb = freecb;
178  job->data = data;
179 
180  if (~flags & JOB_PTY) {
181  close(out[1]);
182  job->fd = out[0];
183  } else
184  job->fd = master;
185  setblocking(job->fd, 0);
186 
187  job->event = bufferevent_new(job->fd, job_read_callback,
189  if (job->event == NULL)
190  fatalx("out of memory");
191  bufferevent_enable(job->event, EV_READ|EV_WRITE);
192 
193  log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
194  return (job);
195 
196 fail:
197  sigprocmask(SIG_SETMASK, &oldset, NULL);
198  environ_free(env);
199  return (NULL);
200 }
201 
202 /* Kill and free an individual job. */
203 void
204 job_free(struct job *job)
205 {
206  log_debug("free job %p: %s", job, job->cmd);
207 
208  LIST_REMOVE(job, entry);
209  free(job->cmd);
210 
211  if (job->freecb != NULL && job->data != NULL)
212  job->freecb(job->data);
213 
214  if (job->pid != -1)
215  kill(job->pid, SIGTERM);
216  if (job->event != NULL)
217  bufferevent_free(job->event);
218  if (job->fd != -1)
219  close(job->fd);
220 
221  free(job);
222 }
223 
224 /* Resize job. */
225 void
226 job_resize(struct job *job, u_int sx, u_int sy)
227 {
228  struct winsize ws;
229 
230  if (job->fd == -1 || (~job->flags & JOB_PTY))
231  return;
232 
233  log_debug("resize job %p: %ux%u", job, sx, sy);
234 
235  memset(&ws, 0, sizeof ws);
236  ws.ws_col = sx;
237  ws.ws_row = sy;
238  if (ioctl(job->fd, TIOCSWINSZ, &ws) == -1)
239  fatal("ioctl failed");
240 }
241 
242 /* Job buffer read callback. */
243 static void
244 job_read_callback(__unused struct bufferevent *bufev, void *data)
245 {
246  struct job *job = data;
247 
248  if (job->updatecb != NULL)
249  job->updatecb(job);
250 }
251 
252 /*
253  * Job buffer write callback. Fired when the buffer falls below watermark
254  * (default is empty). If all the data has been written, disable the write
255  * event.
256  */
257 static void
258 job_write_callback(__unused struct bufferevent *bufev, void *data)
259 {
260  struct job *job = data;
261  size_t len = EVBUFFER_LENGTH(EVBUFFER_OUTPUT(job->event));
262 
263  log_debug("job write %p: %s, pid %ld, output left %zu", job, job->cmd,
264  (long) job->pid, len);
265 
266  if (len == 0 && (~job->flags & JOB_KEEPWRITE)) {
267  shutdown(job->fd, SHUT_WR);
268  bufferevent_disable(job->event, EV_WRITE);
269  }
270 }
271 
272 /* Job buffer error callback. */
273 static void
274 job_error_callback(__unused struct bufferevent *bufev, __unused short events,
275  void *data)
276 {
277  struct job *job = data;
278 
279  log_debug("job error %p: %s, pid %ld", job, job->cmd, (long) job->pid);
280 
281  if (job->state == JOB_DEAD) {
282  if (job->completecb != NULL)
283  job->completecb(job);
284  job_free(job);
285  } else {
286  bufferevent_disable(job->event, EV_READ);
287  job->state = JOB_CLOSED;
288  }
289 }
290 
291 /* Job died (waitpid() returned its pid). */
292 void
294 {
295  struct job *job;
296 
297  LIST_FOREACH(job, &all_jobs, entry) {
298  if (pid == job->pid)
299  break;
300  }
301  if (job == NULL)
302  return;
303  if (WIFSTOPPED(status)) {
304  if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU)
305  return;
306  killpg(job->pid, SIGCONT);
307  return;
308  }
309  log_debug("job died %p: %s, pid %ld", job, job->cmd, (long) job->pid);
310 
311  job->status = status;
312 
313  if (job->state == JOB_CLOSED) {
314  if (job->completecb != NULL)
315  job->completecb(job);
316  job_free(job);
317  } else {
318  job->pid = -1;
319  job->state = JOB_DEAD;
320  }
321 }
322 
323 /* Get job status. */
324 int
326 {
327  return (job->status);
328 }
329 
330 /* Get job data. */
331 void *
333 {
334  return (job->data);
335 }
336 
337 /* Get job event. */
338 struct bufferevent *
340 {
341  return (job->event);
342 }
343 
344 /* Kill all jobs. */
345 void
347 {
348  struct job *job;
349 
350  LIST_FOREACH(job, &all_jobs, entry) {
351  if (job->pid != -1)
352  kill(job->pid, SIGTERM);
353  }
354 }
355 
356 /* Are any jobs still running? */
357 int
359 {
360  struct job *job;
361 
362  LIST_FOREACH(job, &all_jobs, entry) {
363  if ((~job->flags & JOB_NOWAIT) && job->state == JOB_RUNNING)
364  return (1);
365  }
366  return (0);
367 }
368 
369 /* Print job summary. */
370 void
371 job_print_summary(struct cmdq_item *item, int blank)
372 {
373  struct job *job;
374  u_int n = 0;
375 
376  LIST_FOREACH(job, &all_jobs, entry) {
377  if (blank) {
378  cmdq_print(item, "%s", "");
379  blank = 0;
380  }
381  cmdq_print(item, "Job %u: %s [fd=%d, pid=%ld, status=%d]",
382  n, job->cmd, job->fd, (long)job->pid, job->status);
383  n++;
384  }
385 }
int cfg_finished
Definition: cfg.c:30
void cmdq_print(struct cmdq_item *item, const char *fmt,...)
Definition: cmd-queue.c:792
char ** cmd_copy_argv(int argc, char **argv)
Definition: cmd.c:327
char * cmd_stringify_argv(int argc, char **argv)
Definition: cmd.c:357
void cmd_log_argv(int argc, char **argv, const char *fmt,...)
Definition: cmd.c:233
#define _PATH_DEVNULL
Definition: compat.h:106
#define __unused
Definition: compat.h:60
void closefrom(int)
pid_t fdforkpty(int, int *, char *, struct termios *, struct winsize *)
#define _PATH_BSHELL
Definition: compat.h:98
void environ_push(struct environ *env)
Definition: environ.c:209
struct environ * environ_for_session(struct session *s, int no_TERM)
Definition: environ.c:246
void environ_free(struct environ *env)
Definition: environ.c:56
void job_check_died(pid_t pid, int status)
Definition: job.c:293
static void job_read_callback(struct bufferevent *, void *)
Definition: job.c:244
void * job_get_data(struct job *job)
Definition: job.c:332
void job_kill_all(void)
Definition: job.c:346
void job_print_summary(struct cmdq_item *item, int blank)
Definition: job.c:371
void job_resize(struct job *job, u_int sx, u_int sy)
Definition: job.c:226
int job_still_running(void)
Definition: job.c:358
static LIST_HEAD(joblist, job)
Definition: job.c:67
static void job_error_callback(struct bufferevent *, short, void *)
Definition: job.c:274
void job_free(struct job *job)
Definition: job.c:204
static void job_write_callback(struct bufferevent *, void *)
Definition: job.c:258
int job_get_status(struct job *job)
Definition: job.c:325
struct bufferevent * job_get_event(struct job *job)
Definition: job.c:339
void fatal(const char *msg,...)
Definition: log.c:144
void fatalx(const char *msg,...)
Definition: log.c:159
void log_debug(const char *msg,...)
Definition: log.c:130
void proc_clear_signals(struct tmuxproc *tp, int defaults)
Definition: proc.c:272
struct tmuxproc * server_proc
Definition: server.c:44
Definition: cmd.c:212
Definition: job.c:42
@ JOB_CLOSED
Definition: job.c:46
@ JOB_DEAD
Definition: job.c:45
@ JOB_RUNNING
Definition: job.c:44
int fd
Definition: job.c:55
void * data
Definition: job.c:61
struct bufferevent * event
Definition: job.c:56
job_complete_cb completecb
Definition: job.c:59
job_update_cb updatecb
Definition: job.c:58
int status
Definition: job.c:53
char * cmd
Definition: job.c:51
pid_t pid
Definition: job.c:52
job_free_cb freecb
Definition: job.c:60
int flags
Definition: job.c:49
enum job::@7 state
Definition: tmux.h:1179
int ptm_fd
Definition: tmux.c:43
const char * find_home(void)
Definition: tmux.c:299
void setblocking(int fd, int state)
Definition: tmux.c:233
struct job * job_run(const char *, int, char **, struct session *, const char *, job_update_cb, job_complete_cb, job_free_cb, void *, int, int, int)
void(* job_update_cb)(struct job *)
Definition: tmux.h:2096
#define JOB_KEEPWRITE
Definition: tmux.h:2100
void(* job_complete_cb)(struct job *)
Definition: tmux.h:2097
char ** environ
#define JOB_PTY
Definition: tmux.h:2101
#define JOB_NOWAIT
Definition: tmux.h:2099
void(* job_free_cb)(void *)
Definition: tmux.h:2098
void * xmalloc(size_t size)
Definition: xmalloc.c:27
char * xstrdup(const char *str)
Definition: xmalloc.c:89