1 /* $Id: client.c,v 1.90 2009-12-04 22:14:47 tcunha Exp $ */
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 #ifdef HAVE_SETPROCTITLE
57 char rpathbuf
[MAXPATHLEN
];
60 #ifdef HAVE_SETPROCTITLE
61 if (realpath(path
, rpathbuf
) == NULL
)
62 strlcpy(rpathbuf
, path
, sizeof rpathbuf
);
63 setproctitle("client (%s)", rpathbuf
);
66 memset(&sa
, 0, sizeof sa
);
67 sa
.sun_family
= AF_UNIX
;
68 size
= strlcpy(sa
.sun_path
, path
, sizeof sa
.sun_path
);
69 if (size
>= sizeof sa
.sun_path
) {
74 if ((fd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) == -1)
75 fatal("socket failed");
77 if (connect(fd
, (struct sockaddr
*) &sa
, SUN_LEN(&sa
)) == -1) {
78 if (!(cmdflags
& CMD_STARTSERVER
))
82 if (unlink(path
) != 0)
86 if ((fd
= server_start(path
)) == -1)
94 if ((mode
= fcntl(fd
, F_GETFL
)) == -1)
95 fatal("fcntl failed");
96 if (fcntl(fd
, F_SETFL
, mode
|O_NONBLOCK
) == -1)
97 fatal("fcntl failed");
98 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) == -1)
99 fatal("fcntl failed");
100 imsg_init(&client_ibuf
, fd
);
102 if (cmdflags
& CMD_SENDENVIRON
)
103 client_send_environ();
104 if (isatty(STDIN_FILENO
))
105 client_send_identify(flags
);
107 return (&client_ibuf
);
110 log_warnx("server failed to start");
114 log_warn("server not found");
119 client_send_identify(int flags
)
121 struct msg_identify_data data
;
126 if (ioctl(STDIN_FILENO
, TIOCGWINSZ
, &ws
) == -1)
127 fatal("ioctl(TIOCGWINSZ)");
130 if (getcwd(data
.cwd
, sizeof data
.cwd
) == NULL
)
133 term
= getenv("TERM");
135 strlcpy(data
.term
, term
, sizeof data
.term
) >= sizeof data
.term
)
138 if ((fd
= dup(STDIN_FILENO
)) == -1)
140 imsg_compose(&client_ibuf
,
141 MSG_IDENTIFY
, PROTOCOL_VERSION
, -1, fd
, &data
, sizeof data
);
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
);
179 struct event ev_sigcont
, ev_sigterm
, ev_sigwinch
;
180 struct sigaction sigact
;
184 /* Note: event_init() has already been called. */
186 /* Set up signals. */
187 memset(&sigact
, 0, sizeof sigact
);
188 sigemptyset(&sigact
.sa_mask
);
189 sigact
.sa_flags
= SA_RESTART
;
190 sigact
.sa_handler
= SIG_IGN
;
191 if (sigaction(SIGINT
, &sigact
, NULL
) != 0)
192 fatal("sigaction failed");
193 if (sigaction(SIGPIPE
, &sigact
, NULL
) != 0)
194 fatal("sigaction failed");
195 if (sigaction(SIGUSR1
, &sigact
, NULL
) != 0)
196 fatal("sigaction failed");
197 if (sigaction(SIGUSR2
, &sigact
, NULL
) != 0)
198 fatal("sigaction failed");
199 if (sigaction(SIGTSTP
, &sigact
, NULL
) != 0)
200 fatal("sigaction failed");
202 signal_set(&ev_sigcont
, SIGCONT
, client_signal
, NULL
);
203 signal_add(&ev_sigcont
, NULL
);
204 signal_set(&ev_sigterm
, SIGTERM
, client_signal
, NULL
);
205 signal_add(&ev_sigterm
, NULL
);
206 signal_set(&ev_sigwinch
, SIGWINCH
, client_signal
, NULL
);
207 signal_add(&ev_sigwinch
, NULL
);
210 * imsg_read in the first client poll loop (before the terminal has
211 * been initialised) may have read messages into the buffer after the
212 * MSG_READY switched to here. Process anything outstanding now to
213 * avoid hanging waiting for messages that have already arrived.
215 if (client_dispatch() != 0)
218 /* Set the event and dispatch. */
219 client_update_event();
223 /* Print the exit message, if any, and exit. */
224 if (client_exitmsg
!= NULL
&& !login_shell
)
225 printf("[%s]\n", client_exitmsg
);
226 exit(client_exitval
);
231 client_signal(int sig
, unused
short events
, unused
void *data
)
233 struct sigaction sigact
;
237 client_exitmsg
= "terminated";
239 client_write_server(MSG_EXITING
, NULL
, 0);
242 client_write_server(MSG_RESIZE
, NULL
, 0);
245 memset(&sigact
, 0, sizeof sigact
);
246 sigemptyset(&sigact
.sa_mask
);
247 sigact
.sa_flags
= SA_RESTART
;
248 sigact
.sa_handler
= SIG_IGN
;
249 if (sigaction(SIGTSTP
, &sigact
, NULL
) != 0)
250 fatal("sigaction failed");
251 client_write_server(MSG_WAKEUP
, NULL
, 0);
255 client_update_event();
260 client_callback(unused
int fd
, short events
, unused
void *data
)
264 if (events
& EV_READ
) {
265 if ((n
= imsg_read(&client_ibuf
)) == -1 || n
== 0)
267 if (client_dispatch() != 0) {
268 event_loopexit(NULL
);
273 if (events
& EV_WRITE
) {
274 if (msgbuf_write(&client_ibuf
.w
) < 0)
278 client_update_event();
282 client_exitmsg
= "lost server";
284 event_loopexit(NULL
);
288 client_dispatch(void)
291 struct msg_lock_data lockdata
;
292 struct sigaction sigact
;
296 if ((n
= imsg_get(&client_ibuf
, &imsg
)) == -1)
297 fatalx("imsg_get failed");
300 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
302 log_debug("client got %d", imsg
.hdr
.type
);
303 switch (imsg
.hdr
.type
) {
306 fatalx("bad MSG_DETACH size");
308 client_write_server(MSG_EXITING
, NULL
, 0);
309 client_exitmsg
= "detached";
313 fatalx("bad MSG_EXIT size");
315 client_write_server(MSG_EXITING
, NULL
, 0);
316 client_exitmsg
= "exited";
320 fatalx("bad MSG_EXITED size");
326 fatalx("bad MSG_SHUTDOWN size");
328 client_write_server(MSG_EXITING
, NULL
, 0);
329 client_exitmsg
= "server exited";
334 fatalx("bad MSG_SUSPEND size");
336 memset(&sigact
, 0, sizeof sigact
);
337 sigemptyset(&sigact
.sa_mask
);
338 sigact
.sa_flags
= SA_RESTART
;
339 sigact
.sa_handler
= SIG_DFL
;
340 if (sigaction(SIGTSTP
, &sigact
, NULL
) != 0)
341 fatal("sigaction failed");
342 kill(getpid(), SIGTSTP
);
345 if (datalen
!= sizeof lockdata
)
346 fatalx("bad MSG_LOCK size");
347 memcpy(&lockdata
, imsg
.data
, sizeof lockdata
);
349 lockdata
.cmd
[(sizeof lockdata
.cmd
) - 1] = '\0';
350 system(lockdata
.cmd
);
351 client_write_server(MSG_UNLOCK
, NULL
, 0);
354 fatalx("unexpected message");