=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/server-client.c,v retrieving revision 1.35 retrieving revision 1.36 diff -c -r1.35 -r1.36 *** src/usr.bin/tmux/server-client.c 2010/07/19 18:27:38 1.35 --- src/usr.bin/tmux/server-client.c 2010/07/24 20:11:59 1.36 *************** *** 1,4 **** ! /* $OpenBSD: server-client.c,v 1.35 2010/07/19 18:27:38 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott --- 1,4 ---- ! /* $OpenBSD: server-client.c,v 1.36 2010/07/24 20:11:59 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott *************** *** 29,37 **** --- 29,41 ---- void server_client_handle_key(int, struct mouse_event *, void *); void server_client_repeat_timer(int, short, void *); + void server_client_check_exit(struct client *); void server_client_check_redraw(struct client *); void server_client_set_title(struct client *); void server_client_reset_state(struct client *); + void server_client_in_callback(struct bufferevent *, short, void *); + void server_client_out_callback(struct bufferevent *, short, void *); + void server_client_err_callback(struct bufferevent *, short, void *); int server_client_msg_dispatch(struct client *); void server_client_msg_command(struct client *, struct msg_command_data *); *************** *** 69,77 **** ARRAY_INIT(&c->prompt_hdata); ! c->stdin_file = NULL; ! c->stdout_file = NULL; ! c->stderr_file = NULL; c->tty.fd = -1; c->title = NULL; --- 73,81 ---- ARRAY_INIT(&c->prompt_hdata); ! c->stdin_event = NULL; ! c->stdout_event = NULL; ! c->stderr_event = NULL; c->tty.fd = -1; c->title = NULL; *************** *** 122,133 **** if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); ! if (c->stdin_file != NULL) ! fclose(c->stdin_file); ! if (c->stdout_file != NULL) ! fclose(c->stdout_file); ! if (c->stderr_file != NULL) ! fclose(c->stderr_file); screen_free(&c->status); job_tree_free(&c->status_jobs); --- 126,143 ---- if (c->flags & CLIENT_TERMINAL) tty_free(&c->tty); ! if (c->stdin_fd != -1) ! close(c->stdin_fd); ! if (c->stdin_event != NULL) ! bufferevent_free(c->stdin_event); ! if (c->stdout_fd != -1) ! close(c->stdout_fd); ! if (c->stdout_event != NULL) ! bufferevent_free(c->stdout_event); ! if (c->stderr_fd != -1) ! close(c->stderr_fd); ! if (c->stderr_event != NULL) ! bufferevent_free(c->stderr_event); screen_free(&c->status); job_tree_free(&c->status_jobs); *************** *** 390,400 **** for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); ! if (c == NULL || c->session == NULL) continue; ! server_client_check_redraw(c); ! server_client_reset_state(c); } /* --- 400,413 ---- for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); ! if (c == NULL) continue; ! server_client_check_exit(c); ! if (c->session != NULL) { ! server_client_check_redraw(c); ! server_client_reset_state(c); ! } } /* *************** *** 457,462 **** --- 470,497 ---- c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); } + /* Check if client should be exited. */ + void + server_client_check_exit(struct client *c) + { + struct msg_exit_data exitdata; + + if (!(c->flags & CLIENT_EXIT)) + return; + + if (c->stdout_fd != -1 && c->stdout_event != NULL && + EVBUFFER_LENGTH(c->stdout_event->output) != 0) + return; + if (c->stderr_fd != -1 && c->stderr_event != NULL && + EVBUFFER_LENGTH(c->stderr_event->output) != 0) + return; + + exitdata.retcode = c->retcode; + server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); + + c->flags &= ~CLIENT_EXIT; + } + /* Check for client redraws. */ void server_client_check_redraw(struct client *c) *************** *** 523,528 **** --- 558,609 ---- xfree(title); } + /* + * Error callback for client stdin. Caller must increase reference count when + * enabling event! + */ + void + server_client_in_callback( + unused struct bufferevent *bufev, unused short what, void *data) + { + struct client *c = data; + + c->references--; + if (c->flags & CLIENT_DEAD) + return; + + bufferevent_disable(c->stdin_event, EV_READ|EV_WRITE); + close(c->stdin_fd); + c->stdin_fd = -1; + + if (c->stdin_callback != NULL) + c->stdin_callback(c, c->stdin_data); + } + + /* Error callback for client stdout. */ + void + server_client_out_callback( + unused struct bufferevent *bufev, unused short what, unused void *data) + { + struct client *c = data; + + bufferevent_disable(c->stdout_event, EV_READ|EV_WRITE); + close(c->stdout_fd); + c->stdout_fd = -1; + } + + /* Error callback for client stderr. */ + void + server_client_err_callback( + unused struct bufferevent *bufev, unused short what, unused void *data) + { + struct client *c = data; + + bufferevent_disable(c->stderr_event, EV_READ|EV_WRITE); + close(c->stderr_fd); + c->stderr_fd = -1; + } + /* Dispatch message from client. */ int server_client_msg_dispatch(struct client *c) *************** *** 532,537 **** --- 613,619 ---- struct msg_identify_data identifydata; struct msg_environ_data environdata; ssize_t n, datalen; + int mode; if ((n = imsg_read(&c->ibuf)) == -1 || n == 0) return (-1); *************** *** 566,574 **** fatalx("MSG_IDENTIFY missing fd"); memcpy(&identifydata, imsg.data, sizeof identifydata); ! c->stdin_file = fdopen(imsg.fd, "r"); ! if (c->stdin_file == NULL) ! fatal("fdopen(stdin) failed"); server_client_msg_identify(c, &identifydata, imsg.fd); break; case MSG_STDOUT: --- 648,664 ---- fatalx("MSG_IDENTIFY missing fd"); memcpy(&identifydata, imsg.data, sizeof identifydata); ! c->stdin_fd = imsg.fd; ! c->stdin_event = bufferevent_new(imsg.fd, NULL, NULL, ! server_client_in_callback, c); ! if (c->stdin_event == NULL) ! fatalx("failed to create stdin event"); ! ! if ((mode = fcntl(imsg.fd, F_GETFL)) != -1) ! fcntl(imsg.fd, F_SETFL, mode|O_NONBLOCK); ! if (fcntl(imsg.fd, F_SETFD, FD_CLOEXEC) == -1) ! fatal("fcntl failed"); ! server_client_msg_identify(c, &identifydata, imsg.fd); break; case MSG_STDOUT: *************** *** 577,585 **** if (imsg.fd == -1) fatalx("MSG_STDOUT missing fd"); ! c->stdout_file = fdopen(imsg.fd, "w"); ! if (c->stdout_file == NULL) ! fatal("fdopen(stdout) failed"); break; case MSG_STDERR: if (datalen != 0) --- 667,682 ---- if (imsg.fd == -1) fatalx("MSG_STDOUT missing fd"); ! c->stdout_fd = imsg.fd; ! c->stdout_event = bufferevent_new(imsg.fd, NULL, NULL, ! server_client_out_callback, c); ! if (c->stdout_event == NULL) ! fatalx("failed to create stdout event"); ! ! if ((mode = fcntl(imsg.fd, F_GETFL)) != -1) ! fcntl(imsg.fd, F_SETFL, mode|O_NONBLOCK); ! if (fcntl(imsg.fd, F_SETFD, FD_CLOEXEC) == -1) ! fatal("fcntl failed"); break; case MSG_STDERR: if (datalen != 0) *************** *** 587,595 **** if (imsg.fd == -1) fatalx("MSG_STDERR missing fd"); ! c->stderr_file = fdopen(imsg.fd, "w"); ! if (c->stderr_file == NULL) ! fatal("fdopen(stderr) failed"); break; case MSG_RESIZE: if (datalen != 0) --- 684,699 ---- if (imsg.fd == -1) fatalx("MSG_STDERR missing fd"); ! c->stderr_fd = imsg.fd; ! c->stderr_event = bufferevent_new(imsg.fd, NULL, NULL, ! server_client_err_callback, c); ! if (c->stderr_event == NULL) ! fatalx("failed to create stderr event"); ! ! if ((mode = fcntl(imsg.fd, F_GETFL)) != -1) ! fcntl(imsg.fd, F_SETFL, mode|O_NONBLOCK); ! if (fcntl(imsg.fd, F_SETFD, FD_CLOEXEC) == -1) ! fatal("fcntl failed"); break; case MSG_RESIZE: if (datalen != 0) *************** *** 659,670 **** va_list ap; va_start(ap, fmt); ! vfprintf(ctx->cmdclient->stderr_file, fmt, ap); va_end(ap); ! fputc('\n', ctx->cmdclient->stderr_file); ! fflush(ctx->cmdclient->stderr_file); ! ctx->cmdclient->retcode = 1; } --- 763,772 ---- va_list ap; va_start(ap, fmt); ! evbuffer_add_vprintf(ctx->cmdclient->stderr_event->output, fmt, ap); va_end(ap); ! bufferevent_write(ctx->cmdclient->stderr_event, "\n", 1); ctx->cmdclient->retcode = 1; } *************** *** 675,685 **** va_list ap; va_start(ap, fmt); ! vfprintf(ctx->cmdclient->stdout_file, fmt, ap); va_end(ap); ! fputc('\n', ctx->cmdclient->stdout_file); ! fflush(ctx->cmdclient->stdout_file); } /* Callback to send print message to client, if not quiet. */ --- 777,786 ---- va_list ap; va_start(ap, fmt); ! evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap); va_end(ap); ! bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1); } /* Callback to send print message to client, if not quiet. */ *************** *** 692,713 **** return; va_start(ap, fmt); ! vfprintf(ctx->cmdclient->stdout_file, fmt, ap); va_end(ap); ! fputc('\n', ctx->cmdclient->stdout_file); ! fflush(ctx->cmdclient->stdout_file); } /* Handle command message. */ void server_client_msg_command(struct client *c, struct msg_command_data *data) { ! struct cmd_ctx ctx; ! struct cmd_list *cmdlist = NULL; ! struct msg_exit_data exitdata; ! int argc; ! char **argv, *cause; ctx.error = server_client_msg_error; ctx.print = server_client_msg_print; --- 793,812 ---- return; va_start(ap, fmt); ! evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap); va_end(ap); ! bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1); } /* Handle command message. */ void server_client_msg_command(struct client *c, struct msg_command_data *data) { ! struct cmd_ctx ctx; ! struct cmd_list *cmdlist = NULL; ! int argc; ! char **argv, *cause; ctx.error = server_client_msg_error; ctx.print = server_client_msg_print; *************** *** 738,755 **** } cmd_free_argv(argc, argv); ! if (cmd_list_exec(cmdlist, &ctx) != 1) { ! exitdata.retcode = c->retcode; ! server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); ! } cmd_list_free(cmdlist); return; error: if (cmdlist != NULL) cmd_list_free(cmdlist); ! exitdata.retcode = c->retcode; ! server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata); } /* Handle identify message. */ --- 837,851 ---- } cmd_free_argv(argc, argv); ! if (cmd_list_exec(cmdlist, &ctx) != 1) ! c->flags |= CLIENT_EXIT; cmd_list_free(cmdlist); return; error: if (cmdlist != NULL) cmd_list_free(cmdlist); ! c->flags |= CLIENT_EXIT; } /* Handle identify message. */