4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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/socket.h>
36 struct imsgbuf client_ibuf
;
37 struct event client_event
;
38 const char *client_exitmsg
;
41 void client_send_identify(int);
42 void client_send_environ(void);
43 void client_write_server(enum msgtype
, void *, size_t);
44 void client_update_event(void);
45 void client_signal(int, short, void *);
46 void client_callback(int, short, void *);
47 int client_dispatch(void);
50 client_init(char *path
, int cmdflags
, int flags
)
52 struct sockaddr_un sa
;
55 char rpathbuf
[MAXPATHLEN
];
57 if (realpath(path
, rpathbuf
) == NULL
)
58 strlcpy(rpathbuf
, path
, sizeof rpathbuf
);
59 setproctitle("client (%s)", rpathbuf
);
61 memset(&sa
, 0, sizeof sa
);
62 sa
.sun_family
= AF_UNIX
;
63 size
= strlcpy(sa
.sun_path
, path
, sizeof sa
.sun_path
);
64 if (size
>= sizeof sa
.sun_path
) {
69 if ((fd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) == -1)
70 fatal("socket failed");
72 if (connect(fd
, (struct sockaddr
*) &sa
, SUN_LEN(&sa
)) == -1) {
73 if (!(cmdflags
& CMD_STARTSERVER
))
77 if (unlink(path
) != 0)
81 if ((fd
= server_start(path
)) == -1)
89 if ((mode
= fcntl(fd
, F_GETFL
)) == -1)
90 fatal("fcntl failed");
91 if (fcntl(fd
, F_SETFL
, mode
|O_NONBLOCK
) == -1)
92 fatal("fcntl failed");
93 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) == -1)
94 fatal("fcntl failed");
95 imsg_init(&client_ibuf
, fd
);
97 if (cmdflags
& CMD_SENDENVIRON
)
98 client_send_environ();
99 if (isatty(STDIN_FILENO
))
100 client_send_identify(flags
);
102 return (&client_ibuf
);
105 log_warnx("server failed to start");
109 log_warn("server not found");
114 client_send_identify(int flags
)
116 struct msg_identify_data data
;
122 if (getcwd(data
.cwd
, sizeof data
.cwd
) == NULL
)
125 term
= getenv("TERM");
127 strlcpy(data
.term
, term
, sizeof data
.term
) >= sizeof data
.term
)
130 if ((fd
= dup(STDIN_FILENO
)) == -1)
132 imsg_compose(&client_ibuf
,
133 MSG_IDENTIFY
, PROTOCOL_VERSION
, -1, fd
, &data
, sizeof data
);
137 client_send_environ(void)
139 struct msg_environ_data data
;
142 for (var
= environ
; *var
!= NULL
; var
++) {
143 if (strlcpy(data
.var
, *var
, sizeof data
.var
) >= sizeof data
.var
)
145 client_write_server(MSG_ENVIRON
, &data
, sizeof data
);
150 client_write_server(enum msgtype type
, void *buf
, size_t len
)
152 imsg_compose(&client_ibuf
, type
, PROTOCOL_VERSION
, -1, -1, buf
, len
);
156 client_update_event(void)
160 event_del(&client_event
);
162 if (client_ibuf
.w
.queued
> 0)
164 event_set(&client_event
, client_ibuf
.fd
, events
, client_callback
, NULL
);
165 event_add(&client_event
, NULL
);
173 /* Note: event_init() has already been called. */
175 /* Set up signals. */
176 set_signals(client_signal
);
179 * Send a resize message immediately in case the terminal size has
180 * changed between the identify message to the server and the MSG_READY
181 * telling us to move into the client code.
183 client_write_server(MSG_RESIZE
, NULL
, 0);
186 * imsg_read in the first client poll loop (before the terminal has
187 * been initialised) may have read messages into the buffer after the
188 * MSG_READY switched to here. Process anything outstanding now to
189 * avoid hanging waiting for messages that have already arrived.
191 if (client_dispatch() != 0)
194 /* Set the event and dispatch. */
195 client_update_event();
199 /* Print the exit message, if any, and exit. */
200 if (client_exitmsg
!= NULL
&& !login_shell
)
201 printf("[%s]\n", client_exitmsg
);
202 exit(client_exitval
);
207 client_signal(int sig
, unused
short events
, unused
void *data
)
209 struct sigaction sigact
;
213 client_exitmsg
= "lost tty";
215 client_write_server(MSG_EXITING
, NULL
, 0);
218 client_exitmsg
= "terminated";
220 client_write_server(MSG_EXITING
, NULL
, 0);
223 client_write_server(MSG_RESIZE
, NULL
, 0);
226 memset(&sigact
, 0, sizeof sigact
);
227 sigemptyset(&sigact
.sa_mask
);
228 sigact
.sa_flags
= SA_RESTART
;
229 sigact
.sa_handler
= SIG_IGN
;
230 if (sigaction(SIGTSTP
, &sigact
, NULL
) != 0)
231 fatal("sigaction failed");
232 client_write_server(MSG_WAKEUP
, NULL
, 0);
236 client_update_event();
241 client_callback(unused
int fd
, short events
, unused
void *data
)
245 if (events
& EV_READ
) {
246 if ((n
= imsg_read(&client_ibuf
)) == -1 || n
== 0)
248 if (client_dispatch() != 0) {
249 event_loopexit(NULL
);
254 if (events
& EV_WRITE
) {
255 if (msgbuf_write(&client_ibuf
.w
) < 0)
259 client_update_event();
263 client_exitmsg
= "lost server";
265 event_loopexit(NULL
);
269 client_dispatch(void)
272 struct msg_lock_data lockdata
;
273 struct sigaction sigact
;
277 if ((n
= imsg_get(&client_ibuf
, &imsg
)) == -1)
278 fatalx("imsg_get failed");
281 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
283 log_debug("client got %d", imsg
.hdr
.type
);
284 switch (imsg
.hdr
.type
) {
287 fatalx("bad MSG_DETACH size");
289 client_write_server(MSG_EXITING
, NULL
, 0);
290 client_exitmsg
= "detached";
294 fatalx("bad MSG_EXIT size");
296 client_write_server(MSG_EXITING
, NULL
, 0);
297 client_exitmsg
= "exited";
301 fatalx("bad MSG_EXITED size");
307 fatalx("bad MSG_SHUTDOWN size");
309 client_write_server(MSG_EXITING
, NULL
, 0);
310 client_exitmsg
= "server exited";
315 fatalx("bad MSG_SUSPEND size");
317 memset(&sigact
, 0, sizeof sigact
);
318 sigemptyset(&sigact
.sa_mask
);
319 sigact
.sa_flags
= SA_RESTART
;
320 sigact
.sa_handler
= SIG_DFL
;
321 if (sigaction(SIGTSTP
, &sigact
, NULL
) != 0)
322 fatal("sigaction failed");
323 kill(getpid(), SIGTSTP
);
326 if (datalen
!= sizeof lockdata
)
327 fatalx("bad MSG_LOCK size");
328 memcpy(&lockdata
, imsg
.data
, sizeof lockdata
);
330 lockdata
.cmd
[(sizeof lockdata
.cmd
) - 1] = '\0';
331 system(lockdata
.cmd
);
332 client_write_server(MSG_UNLOCK
, NULL
, 0);
335 fatalx("unexpected message");