]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_monitord.c
Merge pull request #1539 from brauner/2017-05-06/fix_abstract_unix_sockets
[mirror_lxc.git] / src / lxc / lxc_monitord.c
1 /*
2 * lxc: linux Container library
3 *
4 * Copyright © 2012 Oracle.
5 *
6 * Authors:
7 * Dwight Engen <dwight.engen@oracle.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #define _GNU_SOURCE
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <net/if.h>
33 #include <netinet/in.h>
34 #include <setjmp.h>
35 #include <sys/epoll.h>
36 #include <sys/param.h>
37 #include <sys/socket.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <sys/un.h>
41
42 #include "af_unix.h"
43 #include "log.h"
44 #include "mainloop.h"
45 #include "monitor.h"
46 #include "utils.h"
47
48 #define CLIENTFDS_CHUNK 64
49
50 lxc_log_define(lxc_monitord, lxc);
51
52 sigjmp_buf mark;
53
54 static void lxc_monitord_cleanup(void);
55
56 /*
57 * Defines the structure to store the monitor information
58 * @lxcpath : the path being monitored
59 * @fifofd : the file descriptor for publishers (containers) to write state
60 * @listenfd : the file descriptor for subscribers (lxc-monitors) to connect
61 * @clientfds : accepted client file descriptors
62 * @clientfds_size : number of file descriptors clientfds can hold
63 * @clientfds_cnt : the count of valid fds in clientfds
64 * @descr : the lxc_mainloop state
65 */
66 struct lxc_monitor {
67 const char *lxcpath;
68 int fifofd;
69 int listenfd;
70 int *clientfds;
71 int clientfds_size;
72 int clientfds_cnt;
73 struct lxc_epoll_descr descr;
74 };
75
76 static struct lxc_monitor mon;
77 static int quit;
78
79 static int lxc_monitord_fifo_create(struct lxc_monitor *mon)
80 {
81 struct flock lk;
82 char fifo_path[PATH_MAX];
83 int ret;
84
85 ret = lxc_monitor_fifo_name(mon->lxcpath, fifo_path, sizeof(fifo_path), 1);
86 if (ret < 0)
87 return ret;
88
89 ret = mknod(fifo_path, S_IFIFO|S_IRUSR|S_IWUSR, 0);
90 if (ret < 0 && errno != EEXIST) {
91 INFO("Failed to mknod monitor fifo %s: %s.", fifo_path, strerror(errno));
92 return -1;
93 }
94
95 mon->fifofd = open(fifo_path, O_RDWR);
96 if (mon->fifofd < 0) {
97 unlink(fifo_path);
98 ERROR("Failed to open monitor fifo.");
99 return -1;
100 }
101
102 lk.l_type = F_WRLCK;
103 lk.l_whence = SEEK_SET;
104 lk.l_start = 0;
105 lk.l_len = 0;
106 if (fcntl(mon->fifofd, F_SETLK, &lk) != 0) {
107 /* another lxc-monitord is already running, don't start up */
108 DEBUG("lxc-monitord already running on lxcpath %s.", mon->lxcpath);
109 close(mon->fifofd);
110 return -1;
111 }
112 return 0;
113 }
114
115 static int lxc_monitord_fifo_delete(struct lxc_monitor *mon)
116 {
117 char fifo_path[PATH_MAX];
118 int ret;
119
120 ret = lxc_monitor_fifo_name(mon->lxcpath, fifo_path, sizeof(fifo_path), 0);
121 if (ret < 0)
122 return ret;
123
124 unlink(fifo_path);
125 return 0;
126 }
127
128 static void lxc_monitord_sockfd_remove(struct lxc_monitor *mon, int fd) {
129 int i;
130
131 if (lxc_mainloop_del_handler(&mon->descr, fd))
132 CRIT("File descriptor %d not found in mainloop.", fd);
133 close(fd);
134
135 for (i = 0; i < mon->clientfds_cnt; i++) {
136 if (mon->clientfds[i] == fd)
137 break;
138 }
139 if (i >= mon->clientfds_cnt) {
140 CRIT("File descriptor %d not found in clients array.", fd);
141 lxc_monitord_cleanup();
142 exit(EXIT_FAILURE);
143 }
144
145 memmove(&mon->clientfds[i], &mon->clientfds[i+1],
146 (mon->clientfds_cnt - i - 1) * sizeof(mon->clientfds[0]));
147 mon->clientfds_cnt--;
148 }
149
150 static int lxc_monitord_sock_handler(int fd, uint32_t events, void *data,
151 struct lxc_epoll_descr *descr)
152 {
153 struct lxc_monitor *mon = data;
154
155 if (events & EPOLLIN) {
156 int rc;
157 char buf[4];
158
159 rc = read(fd, buf, sizeof(buf));
160 if (rc > 0 && !strncmp(buf, "quit", 4))
161 quit = 1;
162 }
163
164 if (events & EPOLLHUP)
165 lxc_monitord_sockfd_remove(mon, fd);
166 return quit;
167 }
168
169 static int lxc_monitord_sock_accept(int fd, uint32_t events, void *data,
170 struct lxc_epoll_descr *descr)
171 {
172 int ret,clientfd;
173 struct lxc_monitor *mon = data;
174 struct ucred cred;
175 socklen_t credsz = sizeof(cred);
176
177 ret = -1;
178 clientfd = accept(fd, NULL, 0);
179 if (clientfd < 0) {
180 SYSERROR("Failed to accept connection for client file descriptor %d.", fd);
181 goto out;
182 }
183
184 if (fcntl(clientfd, F_SETFD, FD_CLOEXEC)) {
185 SYSERROR("Failed to set FD_CLOEXEC on client socket connection %d.", clientfd);
186 goto err1;
187 }
188
189 if (getsockopt(clientfd, SOL_SOCKET, SO_PEERCRED, &cred, &credsz))
190 {
191 ERROR("Failed to get credentials on client socket connection %d.", clientfd);
192 goto err1;
193 }
194 if (cred.uid && cred.uid != geteuid()) {
195 WARN("Monitor denied for uid %d on client socket connection %d.", cred.uid, clientfd);
196 ret = -EACCES;
197 goto err1;
198 }
199
200 if (mon->clientfds_cnt + 1 > mon->clientfds_size) {
201 int *clientfds;
202 clientfds = realloc(mon->clientfds,
203 (mon->clientfds_size + CLIENTFDS_CHUNK) * sizeof(mon->clientfds[0]));
204 if (clientfds == NULL) {
205 ERROR("Failed to realloc memory for %d client file "
206 "descriptors.",
207 mon->clientfds_size + CLIENTFDS_CHUNK);
208 goto err1;
209 }
210 mon->clientfds = clientfds;
211 mon->clientfds_size += CLIENTFDS_CHUNK;
212 }
213
214 ret = lxc_mainloop_add_handler(&mon->descr, clientfd,
215 lxc_monitord_sock_handler, mon);
216 if (ret) {
217 ERROR("Failed to add socket handler.");
218 goto err1;
219 }
220
221 mon->clientfds[mon->clientfds_cnt++] = clientfd;
222 INFO("Accepted client file descriptor %d. Number of accepted file descriptors is now %d.", clientfd, mon->clientfds_cnt);
223 goto out;
224
225 err1:
226 close(clientfd);
227 out:
228 return ret;
229 }
230
231 static int lxc_monitord_sock_create(struct lxc_monitor *mon)
232 {
233 struct sockaddr_un addr;
234 int fd;
235
236 if (lxc_monitor_sock_name(mon->lxcpath, &addr) < 0)
237 return -1;
238
239 fd = lxc_abstract_unix_open(addr.sun_path, SOCK_STREAM, O_TRUNC);
240 if (fd < 0) {
241 ERROR("Failed to open unix socket: %s.", strerror(errno));
242 return -1;
243 }
244
245 mon->listenfd = fd;
246 return 0;
247 }
248
249 static int lxc_monitord_sock_delete(struct lxc_monitor *mon)
250 {
251 struct sockaddr_un addr;
252
253 if (lxc_monitor_sock_name(mon->lxcpath, &addr) < 0)
254 return -1;
255 if (addr.sun_path[0])
256 unlink(addr.sun_path);
257 return 0;
258 }
259
260 static int lxc_monitord_create(struct lxc_monitor *mon)
261 {
262 int ret;
263
264 ret = lxc_monitord_fifo_create(mon);
265 if (ret < 0)
266 return ret;
267
268 ret = lxc_monitord_sock_create(mon);
269 return ret;
270 }
271
272 static void lxc_monitord_delete(struct lxc_monitor *mon)
273 {
274 int i;
275
276 lxc_mainloop_del_handler(&mon->descr, mon->listenfd);
277 close(mon->listenfd);
278 lxc_monitord_sock_delete(mon);
279
280 lxc_mainloop_del_handler(&mon->descr, mon->fifofd);
281 lxc_monitord_fifo_delete(mon);
282 close(mon->fifofd);
283
284 for (i = 0; i < mon->clientfds_cnt; i++) {
285 lxc_mainloop_del_handler(&mon->descr, mon->clientfds[i]);
286 close(mon->clientfds[i]);
287 }
288 mon->clientfds_cnt = 0;
289 }
290
291 static int lxc_monitord_fifo_handler(int fd, uint32_t events, void *data,
292 struct lxc_epoll_descr *descr)
293 {
294 int ret,i;
295 struct lxc_msg msglxc;
296 struct lxc_monitor *mon = data;
297
298 ret = read(fd, &msglxc, sizeof(msglxc));
299 if (ret != sizeof(msglxc)) {
300 SYSERROR("Reading from fifo failed: %s.", strerror(errno));
301 return 1;
302 }
303
304 for (i = 0; i < mon->clientfds_cnt; i++) {
305 ret = write(mon->clientfds[i], &msglxc, sizeof(msglxc));
306 if (ret < 0)
307 ERROR("Failed to send message to client file descriptor %d: %s.",
308 mon->clientfds[i], strerror(errno));
309 }
310
311 return 0;
312 }
313
314 static int lxc_monitord_mainloop_add(struct lxc_monitor *mon)
315 {
316 int ret;
317
318 ret = lxc_mainloop_add_handler(&mon->descr, mon->fifofd,
319 lxc_monitord_fifo_handler, mon);
320 if (ret < 0) {
321 ERROR("Failed to add to mainloop monitor handler for fifo.");
322 return -1;
323 }
324
325 ret = lxc_mainloop_add_handler(&mon->descr, mon->listenfd,
326 lxc_monitord_sock_accept, mon);
327 if (ret < 0) {
328 ERROR("Failed to add to mainloop monitor handler for listen socket.");
329 return -1;
330 }
331
332 return 0;
333 }
334
335 static void lxc_monitord_cleanup(void)
336 {
337 lxc_monitord_delete(&mon);
338 }
339
340 static void lxc_monitord_sig_handler(int sig)
341 {
342 siglongjmp(mark, 1);
343 }
344
345 int main(int argc, char *argv[])
346 {
347 int ret, pipefd;
348 char logpath[PATH_MAX];
349 sigset_t mask;
350 char *lxcpath = argv[1];
351 bool mainloop_opened = false;
352 bool monitord_created = false;
353
354 if (argc != 3) {
355 fprintf(stderr,
356 "Usage: lxc-monitord lxcpath sync-pipe-fd\n\n"
357 "NOTE: lxc-monitord is intended for use by lxc internally\n"
358 " and does not need to be run by hand\n\n");
359 exit(EXIT_FAILURE);
360 }
361
362 ret = snprintf(logpath, sizeof(logpath), "%s/lxc-monitord.log",
363 (strcmp(LXCPATH, lxcpath) ? lxcpath : LOGPATH ));
364 if (ret < 0 || ret >= sizeof(logpath))
365 exit(EXIT_FAILURE);
366
367 ret = lxc_log_init(NULL, logpath, "DEBUG", "lxc-monitord", 0, lxcpath);
368 if (ret)
369 INFO("Failed to open log file %s, log will be lost.", lxcpath);
370 lxc_log_options_no_override();
371
372 if (lxc_safe_int(argv[2], &pipefd) < 0)
373 exit(EXIT_FAILURE);
374
375 if (sigfillset(&mask) ||
376 sigdelset(&mask, SIGILL) ||
377 sigdelset(&mask, SIGSEGV) ||
378 sigdelset(&mask, SIGBUS) ||
379 sigdelset(&mask, SIGTERM) ||
380 sigprocmask(SIG_BLOCK, &mask, NULL)) {
381 SYSERROR("Failed to set signal mask.");
382 exit(EXIT_FAILURE);
383 }
384
385 signal(SIGILL, lxc_monitord_sig_handler);
386 signal(SIGSEGV, lxc_monitord_sig_handler);
387 signal(SIGBUS, lxc_monitord_sig_handler);
388 signal(SIGTERM, lxc_monitord_sig_handler);
389
390 if (sigsetjmp(mark, 1) != 0)
391 goto on_signal;
392
393 ret = EXIT_FAILURE;
394 memset(&mon, 0, sizeof(mon));
395 mon.lxcpath = lxcpath;
396 if (lxc_mainloop_open(&mon.descr)) {
397 ERROR("Failed to create mainloop.");
398 goto on_error;
399 }
400 mainloop_opened = true;
401
402 if (lxc_monitord_create(&mon))
403 goto on_error;
404 monitord_created = true;
405
406 /* sync with parent, we're ignoring the return from write
407 * because regardless if it works or not, the following
408 * close will sync us with the parent process. the
409 * if-empty-statement construct is to quiet the
410 * warn-unused-result warning.
411 */
412 if (write(pipefd, "S", 1))
413 ;
414 close(pipefd);
415
416 if (lxc_monitord_mainloop_add(&mon)) {
417 ERROR("Failed to add mainloop handlers.");
418 goto on_error;
419 }
420
421 NOTICE("lxc-monitord with pid %d is now monitoring lxcpath %s.",
422 getpid(), mon.lxcpath);
423 for (;;) {
424 ret = lxc_mainloop(&mon.descr, 1000 * 30);
425 if (mon.clientfds_cnt <= 0) {
426 NOTICE("No remaining clients. lxc-monitord is exiting.");
427 break;
428 }
429 }
430
431 on_signal:
432 ret = EXIT_SUCCESS;
433 on_error:
434 if (monitord_created)
435 lxc_monitord_cleanup();
436 if (mainloop_opened)
437 lxc_mainloop_close(&mon.descr);
438
439 exit(ret);
440 }