Annotation of src/usr.bin/tmux/client.c, Revision 1.1
1.1 ! nicm 1: /* $OpenBSD$ */
! 2:
! 3: /*
! 4: * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
! 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/stat.h>
! 23: #include <sys/un.h>
! 24: #include <sys/wait.h>
! 25:
! 26: #include <errno.h>
! 27: #include <fcntl.h>
! 28: #include <pwd.h>
! 29: #include <stdlib.h>
! 30: #include <string.h>
! 31: #include <syslog.h>
! 32: #include <unistd.h>
! 33:
! 34: #include "tmux.h"
! 35:
! 36: void client_handle_winch(struct client_ctx *);
! 37:
! 38: int
! 39: client_init(char *path, struct client_ctx *cctx, int start_server, int flags)
! 40: {
! 41: struct sockaddr_un sa;
! 42: struct stat sb;
! 43: struct msg_identify_data data;
! 44: struct winsize ws;
! 45: size_t size;
! 46: int mode;
! 47: struct buffer *b;
! 48: char *name;
! 49:
! 50: if (lstat(path, &sb) != 0) {
! 51: if (start_server && errno == ENOENT) {
! 52: if ((cctx->srv_fd = server_start(path)) == -1)
! 53: goto start_failed;
! 54: goto server_started;
! 55: }
! 56: goto not_found;
! 57: }
! 58: if (!S_ISSOCK(sb.st_mode)) {
! 59: errno = ENOTSOCK;
! 60: goto not_found;
! 61: }
! 62:
! 63: memset(&sa, 0, sizeof sa);
! 64: sa.sun_family = AF_UNIX;
! 65: size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
! 66: if (size >= sizeof sa.sun_path) {
! 67: errno = ENAMETOOLONG;
! 68: goto not_found;
! 69: }
! 70:
! 71: if ((cctx->srv_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
! 72: fatal("socket");
! 73:
! 74: if (connect(
! 75: cctx->srv_fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
! 76: if (errno == ECONNREFUSED) {
! 77: if (unlink(path) != 0 || !start_server)
! 78: goto not_found;
! 79: if ((cctx->srv_fd = server_start(path)) == -1)
! 80: goto start_failed;
! 81: goto server_started;
! 82: }
! 83: goto not_found;
! 84: }
! 85:
! 86: server_started:
! 87: if ((mode = fcntl(cctx->srv_fd, F_GETFL)) == -1)
! 88: fatal("fcntl failed");
! 89: if (fcntl(cctx->srv_fd, F_SETFL, mode|O_NONBLOCK) == -1)
! 90: fatal("fcntl failed");
! 91: cctx->srv_in = buffer_create(BUFSIZ);
! 92: cctx->srv_out = buffer_create(BUFSIZ);
! 93:
! 94: if (isatty(STDIN_FILENO)) {
! 95: if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
! 96: fatal("ioctl(TIOCGWINSZ)");
! 97: data.version = PROTOCOL_VERSION;
! 98: data.flags = flags;
! 99: data.sx = ws.ws_col;
! 100: data.sy = ws.ws_row;
! 101: *data.tty = '\0';
! 102: if (getcwd(data.cwd, sizeof data.cwd) == NULL)
! 103: *data.cwd = '\0';
! 104:
! 105: if ((name = ttyname(STDIN_FILENO)) == NULL)
! 106: fatal("ttyname failed");
! 107: if (strlcpy(data.tty, name, sizeof data.tty) >= sizeof data.tty)
! 108: fatalx("ttyname failed");
! 109:
! 110: b = buffer_create(BUFSIZ);
! 111: cmd_send_string(b, getenv("TERM"));
! 112: client_write_server2(cctx, MSG_IDENTIFY,
! 113: &data, sizeof data, BUFFER_OUT(b), BUFFER_USED(b));
! 114: buffer_destroy(b);
! 115: }
! 116:
! 117: return (0);
! 118:
! 119: start_failed:
! 120: log_warnx("server failed to start");
! 121: return (1);
! 122:
! 123: not_found:
! 124: log_warn("server not found");
! 125: return (1);
! 126: }
! 127:
! 128: int
! 129: client_main(struct client_ctx *cctx)
! 130: {
! 131: struct pollfd pfd;
! 132: char *error;
! 133: int xtimeout; /* Yay for ncurses namespace! */
! 134:
! 135: siginit();
! 136:
! 137: logfile("client");
! 138: setproctitle("client");
! 139:
! 140: error = NULL;
! 141: xtimeout = INFTIM;
! 142: while (!sigterm) {
! 143: if (sigchld) {
! 144: waitpid(WAIT_ANY, NULL, WNOHANG);
! 145: sigchld = 0;
! 146: }
! 147: if (sigwinch)
! 148: client_handle_winch(cctx);
! 149: if (sigcont) {
! 150: siginit();
! 151: client_write_server(cctx, MSG_WAKEUP, NULL, 0);
! 152: sigcont = 0;
! 153: }
! 154:
! 155: switch (client_msg_dispatch(cctx, &error)) {
! 156: case -1:
! 157: goto out;
! 158: case 0:
! 159: /* May be more in buffer, don't let poll block. */
! 160: xtimeout = 0;
! 161: break;
! 162: default:
! 163: /* Out of data, poll may block. */
! 164: xtimeout = INFTIM;
! 165: break;
! 166: }
! 167:
! 168: pfd.fd = cctx->srv_fd;
! 169: pfd.events = POLLIN;
! 170: if (BUFFER_USED(cctx->srv_out) > 0)
! 171: pfd.events |= POLLOUT;
! 172:
! 173: if (poll(&pfd, 1, xtimeout) == -1) {
! 174: if (errno == EAGAIN || errno == EINTR)
! 175: continue;
! 176: fatal("poll failed");
! 177: }
! 178:
! 179: if (buffer_poll(&pfd, cctx->srv_in, cctx->srv_out) != 0)
! 180: goto server_dead;
! 181: }
! 182:
! 183: out:
! 184: if (sigterm) {
! 185: printf("[terminated]\n");
! 186: return (1);
! 187: }
! 188:
! 189: if (cctx->flags & CCTX_SHUTDOWN) {
! 190: printf("[server exited]\n");
! 191: return (0);
! 192: }
! 193:
! 194: if (cctx->flags & CCTX_EXIT) {
! 195: printf("[exited]\n");
! 196: return (0);
! 197: }
! 198:
! 199: if (cctx->flags & CCTX_DETACH) {
! 200: printf("[detached]\n");
! 201: return (0);
! 202: }
! 203:
! 204: printf("[error: %s]\n", error);
! 205: return (1);
! 206:
! 207: server_dead:
! 208: printf("[lost server]\n");
! 209: return (0);
! 210: }
! 211:
! 212: void
! 213: client_handle_winch(struct client_ctx *cctx)
! 214: {
! 215: struct msg_resize_data data;
! 216: struct winsize ws;
! 217:
! 218: if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
! 219: fatal("ioctl failed");
! 220:
! 221: data.sx = ws.ws_col;
! 222: data.sy = ws.ws_row;
! 223: client_write_server(cctx, MSG_RESIZE, &data, sizeof data);
! 224:
! 225: sigwinch = 0;
! 226: }