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/ioctl.h>
21 #include <sys/socket.h>
37 struct imsgbuf client_ibuf
;
38 struct event client_event
;
39 const char *client_exitmsg
;
42 void client_send_identify(int);
43 void client_send_environ(void);
44 void client_write_server(enum msgtype
, void *, size_t);
45 void client_update_event(void);
46 void client_signal(int, short, void *);
47 void client_callback(int, short, void *);
48 int client_dispatch(void);
51 client_init(char *path
, int cmdflags
, int flags
)
53 struct sockaddr_un sa
;
56 char rpathbuf
[MAXPATHLEN
];
58 if (realpath(path
, rpathbuf
) == NULL
)
59 strlcpy(rpathbuf
, path
, sizeof rpathbuf
);
60 setproctitle("client (%s)", rpathbuf
);
62 memset(&sa
, 0, sizeof sa
);
63 sa
.sun_family
= AF_UNIX
;
64 size
= strlcpy(sa
.sun_path
, path
, sizeof sa
.sun_path
);
65 if (size
>= sizeof sa
.sun_path
) {
70 if ((fd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) == -1)
71 fatal("socket failed");
73 if (connect(fd
, (struct sockaddr
*) &sa
, SUN_LEN(&sa
)) == -1) {
74 if (!(cmdflags
& CMD_STARTSERVER
))
78 if (unlink(path
) != 0)
82 if ((fd
= server_start(path
)) == -1)
90 if ((mode
= fcntl(fd
, F_GETFL
)) == -1)
91 fatal("fcntl failed");
92 if (fcntl(fd
, F_SETFL
, mode
|O_NONBLOCK
) == -1)
93 fatal("fcntl failed");
94 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) == -1)
95 fatal("fcntl failed");
96 imsg_init(&client_ibuf
, fd
);
98 if (cmdflags
& CMD_SENDENVIRON
)
99 client_send_environ();
100 if (isatty(STDIN_FILENO
))
101 client_send_identify(flags
);
103 return (&client_ibuf
);
106 log_warnx("server failed to start");
110 log_warn("server not found");
115 client_send_identify(int flags
)
117 struct msg_identify_data data
;
122 if (ioctl(STDIN_FILENO
, TIOCGWINSZ
, &ws
) == -1)
123 fatal("ioctl(TIOCGWINSZ)");
126 if (getcwd(data
.cwd
, sizeof data
.cwd
) == NULL
)
129 term
= getenv("TERM");
131 strlcpy(data
.term
, term
, sizeof data
.term
) >= sizeof data
.term
)
134 if ((fd
= dup(STDIN_FILENO
)) == -1)
136 imsg_compose(&client_ibuf
,
137 MSG_IDENTIFY
, PROTOCOL_VERSION
, -1, fd
, &data
, sizeof data
);
141 client_send_environ(void)
143 struct msg_environ_data data
;
146 for (var
= environ
; *var
!= NULL
; var
++) {
147 if (strlcpy(data
.var
, *var
, sizeof data
.var
) >= sizeof data
.var
)
149 client_write_server(MSG_ENVIRON
, &data
, sizeof data
);
154 client_write_server(enum msgtype type
, void *buf
, size_t len
)
156 imsg_compose(&client_ibuf
, type
, PROTOCOL_VERSION
, -1, -1, buf
, len
);
160 client_update_event(void)
164 event_del(&client_event
);
166 if (client_ibuf
.w
.queued
> 0)
168 event_set(&client_event
, client_ibuf
.fd
, events
, client_callback
, NULL
);
169 event_add(&client_event
, NULL
);
177 /* Note: event_init() has already been called. */
179 /* Set up signals. */
180 set_signals(client_signal
);
183 * imsg_read in the first client poll loop (before the terminal has
184 * been initialised) may have read messages into the buffer after the
185 * MSG_READY switched to here. Process anything outstanding now to
186 * avoid hanging waiting for messages that have already arrived.
188 if (client_dispatch() != 0)
191 /* Set the event and dispatch. */
192 client_update_event();
196 /* Print the exit message, if any, and exit. */
197 if (client_exitmsg
!= NULL
&& !login_shell
)
198 printf("[%s]\n", client_exitmsg
);
199 exit(client_exitval
);
204 client_signal(int sig
, unused
short events
, unused
void *data
)
206 struct sigaction sigact
;
210 client_exitmsg
= "lost tty";
212 client_write_server(MSG_EXITING
, NULL
, 0);
215 client_exitmsg
= "terminated";
217 client_write_server(MSG_EXITING
, NULL
, 0);
220 client_write_server(MSG_RESIZE
, NULL
, 0);
223 memset(&sigact
, 0, sizeof sigact
);
224 sigemptyset(&sigact
.sa_mask
);
225 sigact
.sa_flags
= SA_RESTART
;
226 sigact
.sa_handler
= SIG_IGN
;
227 if (sigaction(SIGTSTP
, &sigact
, NULL
) != 0)
228 fatal("sigaction failed");
229 client_write_server(MSG_WAKEUP
, NULL
, 0);
233 client_update_event();
238 client_callback(unused
int fd
, short events
, unused
void *data
)
242 if (events
& EV_READ
) {
243 if ((n
= imsg_read(&client_ibuf
)) == -1 || n
== 0)
245 if (client_dispatch() != 0) {
246 event_loopexit(NULL
);
251 if (events
& EV_WRITE
) {
252 if (msgbuf_write(&client_ibuf
.w
) < 0)
256 client_update_event();
260 client_exitmsg
= "lost server";
262 event_loopexit(NULL
);
266 client_dispatch(void)
269 struct msg_lock_data lockdata
;
270 struct sigaction sigact
;
274 if ((n
= imsg_get(&client_ibuf
, &imsg
)) == -1)
275 fatalx("imsg_get failed");
278 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
280 log_debug("client got %d", imsg
.hdr
.type
);
281 switch (imsg
.hdr
.type
) {
284 fatalx("bad MSG_DETACH size");
286 client_write_server(MSG_EXITING
, NULL
, 0);
287 client_exitmsg
= "detached";
291 fatalx("bad MSG_EXIT size");
293 client_write_server(MSG_EXITING
, NULL
, 0);
294 client_exitmsg
= "exited";
298 fatalx("bad MSG_EXITED size");
304 fatalx("bad MSG_SHUTDOWN size");
306 client_write_server(MSG_EXITING
, NULL
, 0);
307 client_exitmsg
= "server exited";
312 fatalx("bad MSG_SUSPEND size");
314 memset(&sigact
, 0, sizeof sigact
);
315 sigemptyset(&sigact
.sa_mask
);
316 sigact
.sa_flags
= SA_RESTART
;
317 sigact
.sa_handler
= SIG_DFL
;
318 if (sigaction(SIGTSTP
, &sigact
, NULL
) != 0)
319 fatal("sigaction failed");
320 kill(getpid(), SIGTSTP
);
323 if (datalen
!= sizeof lockdata
)
324 fatalx("bad MSG_LOCK size");
325 memcpy(&lockdata
, imsg
.data
, sizeof lockdata
);
327 lockdata
.cmd
[(sizeof lockdata
.cmd
) - 1] = '\0';
328 system(lockdata
.cmd
);
329 client_write_server(MSG_UNLOCK
, NULL
, 0);
332 fatalx("unexpected message");