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
);
96 event_set(&client_event
, fd
, EV_READ
, client_callback
, NULL
);
98 if (cmdflags
& CMD_SENDENVIRON
)
99 client_send_environ();
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
);
135 if ((fd
= dup(STDOUT_FILENO
)) == -1)
137 imsg_compose(&client_ibuf
, MSG_STDOUT
, PROTOCOL_VERSION
, -1, fd
, NULL
, 0);
139 if ((fd
= dup(STDERR_FILENO
)) == -1)
141 imsg_compose(&client_ibuf
, MSG_STDERR
, PROTOCOL_VERSION
, -1, fd
, NULL
, 0);
145 client_send_environ(void)
147 struct msg_environ_data data
;
150 for (var
= environ
; *var
!= NULL
; var
++) {
151 if (strlcpy(data
.var
, *var
, sizeof data
.var
) >= sizeof data
.var
)
153 client_write_server(MSG_ENVIRON
, &data
, sizeof data
);
158 client_write_server(enum msgtype type
, void *buf
, size_t len
)
160 imsg_compose(&client_ibuf
, type
, PROTOCOL_VERSION
, -1, -1, buf
, len
);
164 client_update_event(void)
168 event_del(&client_event
);
170 if (client_ibuf
.w
.queued
> 0)
172 event_set(&client_event
, client_ibuf
.fd
, events
, client_callback
, NULL
);
173 event_add(&client_event
, NULL
);
181 /* Note: event_init() has already been called. */
183 /* Set up signals. */
184 set_signals(client_signal
);
187 * Send a resize message immediately in case the terminal size has
188 * changed between the identify message to the server and the MSG_READY
189 * telling us to move into the client code.
191 client_write_server(MSG_RESIZE
, NULL
, 0);
194 * imsg_read in the first client poll loop (before the terminal has
195 * been initialised) may have read messages into the buffer after the
196 * MSG_READY switched to here. Process anything outstanding now to
197 * avoid hanging waiting for messages that have already arrived.
199 if (client_dispatch() != 0)
202 /* Set the event and dispatch. */
203 client_update_event();
207 /* Print the exit message, if any, and exit. */
208 if (client_exitmsg
!= NULL
&& !login_shell
)
209 printf("[%s]\n", client_exitmsg
);
210 exit(client_exitval
);
215 client_signal(int sig
, unused
short events
, unused
void *data
)
217 struct sigaction sigact
;
221 client_exitmsg
= "lost tty";
223 client_write_server(MSG_EXITING
, NULL
, 0);
226 client_exitmsg
= "terminated";
228 client_write_server(MSG_EXITING
, NULL
, 0);
231 client_write_server(MSG_RESIZE
, NULL
, 0);
234 memset(&sigact
, 0, sizeof sigact
);
235 sigemptyset(&sigact
.sa_mask
);
236 sigact
.sa_flags
= SA_RESTART
;
237 sigact
.sa_handler
= SIG_IGN
;
238 if (sigaction(SIGTSTP
, &sigact
, NULL
) != 0)
239 fatal("sigaction failed");
240 client_write_server(MSG_WAKEUP
, NULL
, 0);
244 client_update_event();
249 client_callback(unused
int fd
, short events
, unused
void *data
)
253 if (events
& EV_READ
) {
254 if ((n
= imsg_read(&client_ibuf
)) == -1 || n
== 0)
256 if (client_dispatch() != 0) {
257 event_loopexit(NULL
);
262 if (events
& EV_WRITE
) {
263 if (msgbuf_write(&client_ibuf
.w
) < 0)
267 client_update_event();
271 client_exitmsg
= "lost server";
273 event_loopexit(NULL
);
277 client_dispatch(void)
280 struct msg_lock_data lockdata
;
281 struct sigaction sigact
;
285 if ((n
= imsg_get(&client_ibuf
, &imsg
)) == -1)
286 fatalx("imsg_get failed");
289 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
291 log_debug("client got %d", imsg
.hdr
.type
);
292 switch (imsg
.hdr
.type
) {
295 fatalx("bad MSG_DETACH size");
297 client_write_server(MSG_EXITING
, NULL
, 0);
298 client_exitmsg
= "detached";
302 datalen
!= sizeof (struct msg_exit_data
))
303 fatalx("bad MSG_EXIT size");
305 client_write_server(MSG_EXITING
, NULL
, 0);
306 client_exitmsg
= "exited";
310 fatalx("bad MSG_EXITED size");
316 fatalx("bad MSG_SHUTDOWN size");
318 client_write_server(MSG_EXITING
, NULL
, 0);
319 client_exitmsg
= "server exited";
324 fatalx("bad MSG_SUSPEND size");
326 memset(&sigact
, 0, sizeof sigact
);
327 sigemptyset(&sigact
.sa_mask
);
328 sigact
.sa_flags
= SA_RESTART
;
329 sigact
.sa_handler
= SIG_DFL
;
330 if (sigaction(SIGTSTP
, &sigact
, NULL
) != 0)
331 fatal("sigaction failed");
332 kill(getpid(), SIGTSTP
);
335 if (datalen
!= sizeof lockdata
)
336 fatalx("bad MSG_LOCK size");
337 memcpy(&lockdata
, imsg
.data
, sizeof lockdata
);
339 lockdata
.cmd
[(sizeof lockdata
.cmd
) - 1] = '\0';
340 system(lockdata
.cmd
);
341 client_write_server(MSG_UNLOCK
, NULL
, 0);
344 fatalx("unexpected message");