1 /* $OpenBSD$ */ 2 3 /* 4 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott (at) 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 { 44 JOB_RUNNING, 45 JOB_DEAD, 46 JOB_CLOSED 47 } state; 48 49 int flags; 50 51 char *cmd; 52 pid_t pid; 53 char tty[TTY_NAME_MAX]; 54 int status; 55 56 int fd; 57 struct bufferevent *event; 58 59 job_update_cb updatecb; 60 job_complete_cb completecb; 61 job_free_cb freecb; 62 void *data; 63 64 LIST_ENTRY(job) entry; 65 }; 66 67 /* All jobs list. */ 68 static LIST_HEAD(joblist, job) all_jobs = LIST_HEAD_INITIALIZER(all_jobs); 69 70 /* Start a job running. */ 71 struct job * 72 job_run(const char *cmd, int argc, char **argv, struct environ *e, 73 struct session *s, const char *cwd, job_update_cb updatecb, 74 job_complete_cb completecb, job_free_cb freecb, void *data, int flags, 75 int sx, int sy) 76 { 77 struct job *job; 78 struct environ *env; 79 pid_t pid; 80 int nullfd, out[2], master, do_close = 1; 81 const char *home, *shell; 82 sigset_t set, oldset; 83 struct winsize ws; 84 char **argvp, tty[TTY_NAME_MAX], *argv0; 85 struct options *oo; 86 87 /* 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 90 * outside TERM. 91 */ 92 env = environ_for_session(s, !cfg_finished); 93 if (e != NULL) 94 environ_copy(e, env); 95 96 if (~flags & JOB_DEFAULTSHELL) 97 shell = _PATH_BSHELL; 98 else { 99 if (s != NULL) 100 oo = s->options; 101 else 102 oo = global_s_options; 103 shell = options_get_string(oo, "default-shell"); 104 if (!checkshell(shell)) 105 shell = _PATH_BSHELL; 106 } 107 argv0 = shell_argv0(shell, 0); 108 109 sigfillset(&set); 110 sigprocmask(SIG_BLOCK, &set, &oldset); 111 112 if (flags & JOB_PTY) { 113 memset(&ws, 0, sizeof ws); 114 ws.ws_col = sx; 115 ws.ws_row = sy; 116 pid = fdforkpty(ptm_fd, &master, tty, NULL, &ws); 117 } else { 118 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) 119 goto fail; 120 pid = fork(); 121 } 122 if (cmd == NULL) { 123 cmd_log_argv(argc, argv, "%s:", __func__); 124 log_debug("%s: cwd=%s, shell=%s", __func__, 125 cwd == NULL ? "" : cwd, shell); 126 } else { 127 log_debug("%s: cmd=%s, cwd=%s, shell=%s", __func__, cmd, 128 cwd == NULL ? "" : cwd, shell); 129 } 130 131 switch (pid) { 132 case -1: 133 if (~flags & JOB_PTY) { 134 close(out[0]); 135 close(out[1]); 136 } 137 goto fail; 138 case 0: 139 proc_clear_signals(server_proc, 1); 140 sigprocmask(SIG_SETMASK, &oldset, NULL); 141 142 if (cwd != NULL) { 143 if (chdir(cwd) == 0) 144 environ_set(env, "PWD", 0, "%s", cwd); 145 else if ((home = find_home()) != NULL && chdir(home) == 0) 146 environ_set(env, "PWD", 0, "%s", home); 147 else if (chdir("/") == 0) 148 environ_set(env, "PWD", 0, "/"); 149 else 150 fatal("chdir failed"); 151 } 152 153 environ_push(env); 154 environ_free(env); 155 156 if (~flags & JOB_PTY) { 157 if (dup2(out[1], STDIN_FILENO) == -1) 158 fatal("dup2 failed"); 159 do_close = do_close && out[1] != STDIN_FILENO; 160 if (dup2(out[1], STDOUT_FILENO) == -1) 161 fatal("dup2 failed"); 162 do_close = do_close && out[1] != STDOUT_FILENO; 163 if (flags & JOB_SHOWSTDERR) { 164 if (dup2(out[1], STDERR_FILENO) == -1) 165 fatal("dup2 failed"); 166 do_close = do_close && out[1] != STDERR_FILENO; 167 } else { 168 nullfd = open(_PATH_DEVNULL, O_RDWR); 169 if (nullfd == -1) 170 fatal("open failed"); 171 if (dup2(nullfd, STDERR_FILENO) == -1) 172 fatal("dup2 failed"); 173 if (nullfd != STDERR_FILENO) 174 close(nullfd); 175 } 176 if (do_close) 177 close(out[1]); 178 close(out[0]); 179 } 180 closefrom(STDERR_FILENO + 1); 181 182 if (cmd != NULL) { 183 if (flags & JOB_DEFAULTSHELL) 184 setenv("SHELL", shell, 1); 185 execl(shell, argv0, "-c", cmd, (char *)NULL); 186 fatal("execl failed"); 187 } else { 188 argvp = cmd_copy_argv(argc, argv); 189 execvp(argvp[0], argvp); 190 fatal("execvp failed"); 191 } 192 } 193 194 sigprocmask(SIG_SETMASK, &oldset, NULL); 195 environ_free(env); 196 free(argv0); 197 198 job = xcalloc(1, sizeof *job); 199 job->state = JOB_RUNNING; 200 job->flags = flags; 201 202 if (cmd != NULL) 203 job->cmd = xstrdup(cmd); 204 else 205 job->cmd = cmd_stringify_argv(argc, argv); 206 job->pid = pid; 207 if (flags & JOB_PTY) 208 strlcpy(job->tty, tty, sizeof job->tty); 209 job->status = 0; 210 211 LIST_INSERT_HEAD(&all_jobs, job, entry); 212 213 job->updatecb = updatecb; 214 job->completecb = completecb; 215 job->freecb = freecb; 216 job->data = data; 217 218 if (~flags & JOB_PTY) { 219 close(out[1]); 220 job->fd = out[0]; 221 } else 222 job->fd = master; 223 setblocking(job->fd, 0); 224 225 job->event = bufferevent_new(job->fd, job_read_callback, 226 job_write_callback, job_error_callback, job); 227 if (job->event == NULL) 228 fatalx("out of memory"); 229 bufferevent_enable(job->event, EV_READ|EV_WRITE); 230 231 log_debug("run job %p: %s, pid %ld", job, job->cmd, (long)job->pid); 232 return (job); 233 234 fail: 235 sigprocmask(SIG_SETMASK, &oldset, NULL); 236 environ_free(env); 237 free(argv0); 238 return (NULL); 239 } 240 241 /* Take job's file descriptor and free the job. */ 242 int 243 job_transfer(struct job *job, pid_t *pid, char *tty, size_t ttylen) 244 { 245 int fd = job->fd; 246 247 log_debug("transfer job %p: %s", job, job->cmd); 248 249 if (pid != NULL) 250 *pid = job->pid; 251 if (tty != NULL) 252 strlcpy(tty, job->tty, ttylen); 253 254 LIST_REMOVE(job, entry); 255 free(job->cmd); 256 257 if (job->freecb != NULL && job->data != NULL) 258 job->freecb(job->data); 259 260 if (job->event != NULL) 261 bufferevent_free(job->event); 262 263 free(job); 264 return (fd); 265 } 266 267 /* Kill and free an individual job. */ 268 void 269 job_free(struct job *job) 270 { 271 log_debug("free job %p: %s", job, job->cmd); 272 273 LIST_REMOVE(job, entry); 274 free(job->cmd); 275 276 if (job->freecb != NULL && job->data != NULL) 277 job->freecb(job->data); 278 279 if (job->pid != -1) 280 kill(job->pid, SIGTERM); 281 if (job->event != NULL) 282 bufferevent_free(job->event); 283 if (job->fd != -1) 284 close(job->fd); 285 286 free(job); 287 } 288 289 /* Resize job. */ 290 void 291 job_resize(struct job *job, u_int sx, u_int sy) 292 { 293 struct winsize ws; 294 295 if (job->fd == -1 || (~job->flags & JOB_PTY)) 296 return; 297 298 log_debug("resize job %p: %ux%u", job, sx, sy); 299 300 memset(&ws, 0, sizeof ws); 301 ws.ws_col = sx; 302 ws.ws_row = sy; 303 if (ioctl(job->fd, TIOCSWINSZ, &ws) == -1) 304 fatal("ioctl failed"); 305 } 306 307 /* Job buffer read callback. */ 308 static void 309 job_read_callback(__unused struct bufferevent *bufev, void *data) 310 { 311 struct job *job = data; 312 313 if (job->updatecb != NULL) 314 job->updatecb(job); 315 } 316 317 /* 318 * Job buffer write callback. Fired when the buffer falls below watermark 319 * (default is empty). If all the data has been written, disable the write 320 * event. 321 */ 322 static void 323 job_write_callback(__unused struct bufferevent *bufev, void *data) 324 { 325 struct job *job = data; 326 size_t len = EVBUFFER_LENGTH(EVBUFFER_OUTPUT(job->event)); 327 328 log_debug("job write %p: %s, pid %ld, output left %zu", job, job->cmd, 329 (long) job->pid, len); 330 331 if (len == 0 && (~job->flags & JOB_KEEPWRITE)) { 332 shutdown(job->fd, SHUT_WR); 333 bufferevent_disable(job->event, EV_WRITE); 334 } 335 } 336 337 /* Job buffer error callback. */ 338 static void 339 job_error_callback(__unused struct bufferevent *bufev, __unused short events, 340 void *data) 341 { 342 struct job *job = data; 343 344 log_debug("job error %p: %s, pid %ld", job, job->cmd, (long) job->pid); 345 346 if (job->state == JOB_DEAD) { 347 if (job->completecb != NULL) 348 job->completecb(job); 349 job_free(job); 350 } else { 351 bufferevent_disable(job->event, EV_READ); 352 job->state = JOB_CLOSED; 353 } 354 } 355 356 /* Job died (waitpid() returned its pid). */ 357 void 358 job_check_died(pid_t pid, int status) 359 { 360 struct job *job; 361 362 LIST_FOREACH(job, &all_jobs, entry) { 363 if (pid == job->pid) 364 break; 365 } 366 if (job == NULL) 367 return; 368 if (WIFSTOPPED(status)) { 369 if (WSTOPSIG(status) == SIGTTIN || WSTOPSIG(status) == SIGTTOU) 370 return; 371 killpg(job->pid, SIGCONT); 372 return; 373 } 374 log_debug("job died %p: %s, pid %ld", job, job->cmd, (long) job->pid); 375 376 job->status = status; 377 378 if (job->state == JOB_CLOSED) { 379 if (job->completecb != NULL) 380 job->completecb(job); 381 job_free(job); 382 } else { 383 job->pid = -1; 384 job->state = JOB_DEAD; 385 } 386 } 387 388 /* Get job status. */ 389 int 390 job_get_status(struct job *job) 391 { 392 return (job->status); 393 } 394 395 /* Get job data. */ 396 void * 397 job_get_data(struct job *job) 398 { 399 return (job->data); 400 } 401 402 /* Get job event. */ 403 struct bufferevent * 404 job_get_event(struct job *job) 405 { 406 return (job->event); 407 } 408 409 /* Kill all jobs. */ 410 void 411 job_kill_all(void) 412 { 413 struct job *job; 414 415 LIST_FOREACH(job, &all_jobs, entry) { 416 if (job->pid != -1) 417 kill(job->pid, SIGTERM); 418 } 419 } 420 421 /* Are any jobs still running? */ 422 int 423 job_still_running(void) 424 { 425 struct job *job; 426 427 LIST_FOREACH(job, &all_jobs, entry) { 428 if ((~job->flags & JOB_NOWAIT) && job->state == JOB_RUNNING) 429 return (1); 430 } 431 return (0); 432 } 433 434 /* Print job summary. */ 435 void 436 job_print_summary(struct cmdq_item *item, int blank) 437 { 438 struct job *job; 439 u_int n = 0; 440 441 LIST_FOREACH(job, &all_jobs, entry) { 442 if (blank) { 443 cmdq_print(item, "%s", ""); 444 blank = 0; 445 } 446 cmdq_print(item, "Job %u: %s [fd=%d, pid=%ld, status=%d]", 447 n, job->cmd, job->fd, (long)job->pid, job->status); 448 n++; 449 } 450 } 451