]> git.proxmox.com Git - mirror_lxc.git/blame - 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
CommitLineData
e51d4895
DE
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
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
e51d4895
DE
22 */
23
24#define _GNU_SOURCE
e51d4895 25#include <errno.h>
e51d4895 26#include <fcntl.h>
60e4f6fa
CB
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>
d0dacf05 34#include <setjmp.h>
2afd1dc0 35#include <sys/epoll.h>
e51d4895
DE
36#include <sys/param.h>
37#include <sys/socket.h>
60e4f6fa
CB
38#include <sys/stat.h>
39#include <sys/types.h>
e51d4895 40#include <sys/un.h>
e51d4895 41
f2363e38
ÇO
42#include "af_unix.h"
43#include "log.h"
44#include "mainloop.h"
45#include "monitor.h"
46#include "utils.h"
e51d4895
DE
47
48#define CLIENTFDS_CHUNK 64
49
50lxc_log_define(lxc_monitord, lxc);
51
d0dacf05
CB
52sigjmp_buf mark;
53
e51d4895
DE
54static 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 */
66struct 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
8f47bc3f 76static struct lxc_monitor mon;
2afd1dc0 77static int quit;
8f47bc3f 78
e51d4895
DE
79static int lxc_monitord_fifo_create(struct lxc_monitor *mon)
80{
8bf1e61e 81 struct flock lk;
e51d4895
DE
82 char fifo_path[PATH_MAX];
83 int ret;
84
9e60f51d
DE
85 ret = lxc_monitor_fifo_name(mon->lxcpath, fifo_path, sizeof(fifo_path), 1);
86 if (ret < 0)
87 return ret;
e51d4895
DE
88
89 ret = mknod(fifo_path, S_IFIFO|S_IRUSR|S_IWUSR, 0);
8bf1e61e 90 if (ret < 0 && errno != EEXIST) {
60e4f6fa 91 INFO("Failed to mknod monitor fifo %s: %s.", fifo_path, strerror(errno));
e51d4895
DE
92 return -1;
93 }
94
95 mon->fifofd = open(fifo_path, O_RDWR);
96 if (mon->fifofd < 0) {
97 unlink(fifo_path);
60e4f6fa 98 ERROR("Failed to open monitor fifo.");
e51d4895
DE
99 return -1;
100 }
8bf1e61e
DE
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 */
60e4f6fa 108 DEBUG("lxc-monitord already running on lxcpath %s.", mon->lxcpath);
8bf1e61e
DE
109 close(mon->fifofd);
110 return -1;
111 }
e51d4895
DE
112 return 0;
113}
114
115static int lxc_monitord_fifo_delete(struct lxc_monitor *mon)
116{
117 char fifo_path[PATH_MAX];
118 int ret;
119
9e60f51d
DE
120 ret = lxc_monitor_fifo_name(mon->lxcpath, fifo_path, sizeof(fifo_path), 0);
121 if (ret < 0)
122 return ret;
123
e51d4895
DE
124 unlink(fifo_path);
125 return 0;
126}
127
128static void lxc_monitord_sockfd_remove(struct lxc_monitor *mon, int fd) {
129 int i;
130
131 if (lxc_mainloop_del_handler(&mon->descr, fd))
60e4f6fa 132 CRIT("File descriptor %d not found in mainloop.", fd);
e51d4895
DE
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) {
60e4f6fa 140 CRIT("File descriptor %d not found in clients array.", fd);
e51d4895
DE
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
84c92abd 150static int lxc_monitord_sock_handler(int fd, uint32_t events, void *data,
e51d4895
DE
151 struct lxc_epoll_descr *descr)
152{
153 struct lxc_monitor *mon = data;
154
2afd1dc0
DE
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;
e51d4895
DE
167}
168
84c92abd 169static int lxc_monitord_sock_accept(int fd, uint32_t events, void *data,
e51d4895
DE
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) {
60e4f6fa 180 SYSERROR("Failed to accept connection for client file descriptor %d.", fd);
e51d4895
DE
181 goto out;
182 }
183
184 if (fcntl(clientfd, F_SETFD, FD_CLOEXEC)) {
60e4f6fa 185 SYSERROR("Failed to set FD_CLOEXEC on client socket connection %d.", clientfd);
e51d4895
DE
186 goto err1;
187 }
188
189 if (getsockopt(clientfd, SOL_SOCKET, SO_PEERCRED, &cred, &credsz))
190 {
60e4f6fa 191 ERROR("Failed to get credentials on client socket connection %d.", clientfd);
e51d4895
DE
192 goto err1;
193 }
194 if (cred.uid && cred.uid != geteuid()) {
60e4f6fa 195 WARN("Monitor denied for uid %d on client socket connection %d.", cred.uid, clientfd);
e51d4895
DE
196 ret = -EACCES;
197 goto err1;
198 }
199
200 if (mon->clientfds_cnt + 1 > mon->clientfds_size) {
201 int *clientfds;
e51d4895 202 clientfds = realloc(mon->clientfds,
60e4f6fa 203 (mon->clientfds_size + CLIENTFDS_CHUNK) * sizeof(mon->clientfds[0]));
e51d4895 204 if (clientfds == NULL) {
60e4f6fa
CB
205 ERROR("Failed to realloc memory for %d client file "
206 "descriptors.",
207 mon->clientfds_size + CLIENTFDS_CHUNK);
e51d4895
DE
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) {
60e4f6fa 217 ERROR("Failed to add socket handler.");
e51d4895
DE
218 goto err1;
219 }
220
221 mon->clientfds[mon->clientfds_cnt++] = clientfd;
60e4f6fa 222 INFO("Accepted client file descriptor %d. Number of accepted file descriptors is now %d.", clientfd, mon->clientfds_cnt);
e51d4895
DE
223 goto out;
224
225err1:
226 close(clientfd);
227out:
228 return ret;
229}
230
231static 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
aae93dd3 239 fd = lxc_abstract_unix_open(addr.sun_path, SOCK_STREAM, O_TRUNC);
e51d4895 240 if (fd < 0) {
60e4f6fa 241 ERROR("Failed to open unix socket: %s.", strerror(errno));
e51d4895
DE
242 return -1;
243 }
244
245 mon->listenfd = fd;
246 return 0;
247}
248
249static 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
260static 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
272static 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);
e51d4895 281 lxc_monitord_fifo_delete(mon);
8bf1e61e 282 close(mon->fifofd);
e51d4895
DE
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
84c92abd 291static int lxc_monitord_fifo_handler(int fd, uint32_t events, void *data,
e51d4895
DE
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)) {
60e4f6fa 300 SYSERROR("Reading from fifo failed: %s.", strerror(errno));
e51d4895
DE
301 return 1;
302 }
303
304 for (i = 0; i < mon->clientfds_cnt; i++) {
e51d4895 305 ret = write(mon->clientfds[i], &msglxc, sizeof(msglxc));
60e4f6fa
CB
306 if (ret < 0)
307 ERROR("Failed to send message to client file descriptor %d: %s.",
308 mon->clientfds[i], strerror(errno));
e51d4895
DE
309 }
310
311 return 0;
312}
313
314static 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) {
60e4f6fa 321 ERROR("Failed to add to mainloop monitor handler for fifo.");
e51d4895
DE
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) {
60e4f6fa 328 ERROR("Failed to add to mainloop monitor handler for listen socket.");
e51d4895
DE
329 return -1;
330 }
331
332 return 0;
333}
334
335static void lxc_monitord_cleanup(void)
336{
337 lxc_monitord_delete(&mon);
338}
339
340static void lxc_monitord_sig_handler(int sig)
341{
d0dacf05 342 siglongjmp(mark, 1);
e51d4895
DE
343}
344
345int main(int argc, char *argv[])
346{
60e4f6fa 347 int ret, pipefd;
e51d4895
DE
348 char logpath[PATH_MAX];
349 sigset_t mask;
60e4f6fa 350 char *lxcpath = argv[1];
5cc0f22d
CB
351 bool mainloop_opened = false;
352 bool monitord_created = false;
e51d4895
DE
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",
60e4f6fa 363 (strcmp(LXCPATH, lxcpath) ? lxcpath : LOGPATH ));
e51d4895 364 if (ret < 0 || ret >= sizeof(logpath))
7e5af997 365 exit(EXIT_FAILURE);
e51d4895 366
60e4f6fa 367 ret = lxc_log_init(NULL, logpath, "DEBUG", "lxc-monitord", 0, lxcpath);
e51d4895 368 if (ret)
60e4f6fa 369 INFO("Failed to open log file %s, log will be lost.", lxcpath);
6edbfc86 370 lxc_log_options_no_override();
e51d4895 371
7e5af997
CB
372 if (lxc_safe_int(argv[2], &pipefd) < 0)
373 exit(EXIT_FAILURE);
e51d4895
DE
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)) {
60e4f6fa 381 SYSERROR("Failed to set signal mask.");
7e5af997 382 exit(EXIT_FAILURE);
e51d4895
DE
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
d0dacf05
CB
390 if (sigsetjmp(mark, 1) != 0)
391 goto on_signal;
392
e51d4895
DE
393 ret = EXIT_FAILURE;
394 memset(&mon, 0, sizeof(mon));
395 mon.lxcpath = lxcpath;
396 if (lxc_mainloop_open(&mon.descr)) {
60e4f6fa
CB
397 ERROR("Failed to create mainloop.");
398 goto on_error;
e51d4895 399 }
5cc0f22d 400 mainloop_opened = true;
e51d4895 401
5cc0f22d 402 if (lxc_monitord_create(&mon))
60e4f6fa 403 goto on_error;
5cc0f22d 404 monitord_created = true;
e51d4895
DE
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 */
8f47bc3f
SG
412 if (write(pipefd, "S", 1))
413 ;
e51d4895
DE
414 close(pipefd);
415
416 if (lxc_monitord_mainloop_add(&mon)) {
60e4f6fa
CB
417 ERROR("Failed to add mainloop handlers.");
418 goto on_error;
e51d4895
DE
419 }
420
60e4f6fa
CB
421 NOTICE("lxc-monitord with pid %d is now monitoring lxcpath %s.",
422 getpid(), mon.lxcpath);
423 for (;;) {
e51d4895 424 ret = lxc_mainloop(&mon.descr, 1000 * 30);
60e4f6fa
CB
425 if (mon.clientfds_cnt <= 0) {
426 NOTICE("No remaining clients. lxc-monitord is exiting.");
e51d4895
DE
427 break;
428 }
429 }
430
5cc0f22d 431on_signal:
e51d4895 432 ret = EXIT_SUCCESS;
60e4f6fa 433on_error:
5cc0f22d
CB
434 if (monitord_created)
435 lxc_monitord_cleanup();
436 if (mainloop_opened)
437 lxc_mainloop_close(&mon.descr);
d0dacf05 438
5cc0f22d 439 exit(ret);
e51d4895 440}