]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/cmd/lxc_monitord.c
Merge pull request #2534 from tcharding/checkpatch
[mirror_lxc.git] / src / lxc / cmd / 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>
b467714b 27#include <pthread.h>
60e4f6fa
CB
28#include <signal.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33#include <net/if.h>
34#include <netinet/in.h>
d0dacf05 35#include <setjmp.h>
2afd1dc0 36#include <sys/epoll.h>
e51d4895
DE
37#include <sys/param.h>
38#include <sys/socket.h>
60e4f6fa
CB
39#include <sys/stat.h>
40#include <sys/types.h>
e51d4895 41#include <sys/un.h>
e51d4895 42
1194822f
CB
43#include <lxc/lxccontainer.h>
44
f2363e38
ÇO
45#include "af_unix.h"
46#include "log.h"
47#include "mainloop.h"
48#include "monitor.h"
49#include "utils.h"
e51d4895
DE
50
51#define CLIENTFDS_CHUNK 64
52
53lxc_log_define(lxc_monitord, lxc);
54
d0dacf05
CB
55sigjmp_buf mark;
56
e51d4895
DE
57static void lxc_monitord_cleanup(void);
58
59/*
60 * Defines the structure to store the monitor information
61 * @lxcpath : the path being monitored
62 * @fifofd : the file descriptor for publishers (containers) to write state
63 * @listenfd : the file descriptor for subscribers (lxc-monitors) to connect
64 * @clientfds : accepted client file descriptors
65 * @clientfds_size : number of file descriptors clientfds can hold
66 * @clientfds_cnt : the count of valid fds in clientfds
67 * @descr : the lxc_mainloop state
68 */
69struct lxc_monitor {
70 const char *lxcpath;
71 int fifofd;
72 int listenfd;
73 int *clientfds;
74 int clientfds_size;
75 int clientfds_cnt;
76 struct lxc_epoll_descr descr;
77};
78
8f47bc3f 79static struct lxc_monitor mon;
2afd1dc0 80static int quit;
8f47bc3f 81
e51d4895
DE
82static int lxc_monitord_fifo_create(struct lxc_monitor *mon)
83{
8bf1e61e 84 struct flock lk;
e51d4895
DE
85 char fifo_path[PATH_MAX];
86 int ret;
87
9e60f51d
DE
88 ret = lxc_monitor_fifo_name(mon->lxcpath, fifo_path, sizeof(fifo_path), 1);
89 if (ret < 0)
90 return ret;
e51d4895
DE
91
92 ret = mknod(fifo_path, S_IFIFO|S_IRUSR|S_IWUSR, 0);
8bf1e61e 93 if (ret < 0 && errno != EEXIST) {
7874d81a 94 SYSINFO("Failed to mknod monitor fifo %s", fifo_path);
e51d4895
DE
95 return -1;
96 }
97
98 mon->fifofd = open(fifo_path, O_RDWR);
99 if (mon->fifofd < 0) {
9044b79e 100 SYSERROR("Failed to open monitor fifo %s", fifo_path);
e51d4895 101 unlink(fifo_path);
e51d4895
DE
102 return -1;
103 }
8bf1e61e
DE
104
105 lk.l_type = F_WRLCK;
106 lk.l_whence = SEEK_SET;
107 lk.l_start = 0;
108 lk.l_len = 0;
9044b79e 109
8bf1e61e
DE
110 if (fcntl(mon->fifofd, F_SETLK, &lk) != 0) {
111 /* another lxc-monitord is already running, don't start up */
9044b79e 112 SYSDEBUG("lxc-monitord already running on lxcpath %s", mon->lxcpath);
8bf1e61e
DE
113 close(mon->fifofd);
114 return -1;
115 }
9044b79e 116
e51d4895
DE
117 return 0;
118}
119
120static int lxc_monitord_fifo_delete(struct lxc_monitor *mon)
121{
122 char fifo_path[PATH_MAX];
123 int ret;
124
9e60f51d
DE
125 ret = lxc_monitor_fifo_name(mon->lxcpath, fifo_path, sizeof(fifo_path), 0);
126 if (ret < 0)
127 return ret;
128
e51d4895
DE
129 unlink(fifo_path);
130 return 0;
131}
132
2db65c21
TH
133static void lxc_monitord_sockfd_remove(struct lxc_monitor *mon, int fd)
134{
e51d4895
DE
135 int i;
136
137 if (lxc_mainloop_del_handler(&mon->descr, fd))
9044b79e 138 CRIT("File descriptor %d not found in mainloop", fd);
e51d4895
DE
139 close(fd);
140
9044b79e 141 for (i = 0; i < mon->clientfds_cnt; i++)
e51d4895
DE
142 if (mon->clientfds[i] == fd)
143 break;
9044b79e 144
e51d4895 145 if (i >= mon->clientfds_cnt) {
9044b79e 146 CRIT("File descriptor %d not found in clients array", fd);
e51d4895
DE
147 lxc_monitord_cleanup();
148 exit(EXIT_FAILURE);
149 }
150
151 memmove(&mon->clientfds[i], &mon->clientfds[i+1],
152 (mon->clientfds_cnt - i - 1) * sizeof(mon->clientfds[0]));
153 mon->clientfds_cnt--;
154}
155
84c92abd 156static int lxc_monitord_sock_handler(int fd, uint32_t events, void *data,
e51d4895
DE
157 struct lxc_epoll_descr *descr)
158{
159 struct lxc_monitor *mon = data;
160
2afd1dc0
DE
161 if (events & EPOLLIN) {
162 int rc;
163 char buf[4];
164
243fdadf 165 rc = lxc_read_nointr(fd, buf, sizeof(buf));
2afd1dc0 166 if (rc > 0 && !strncmp(buf, "quit", 4))
b2a48508 167 quit = LXC_MAINLOOP_CLOSE;
2afd1dc0
DE
168 }
169
170 if (events & EPOLLHUP)
171 lxc_monitord_sockfd_remove(mon, fd);
9044b79e 172
2afd1dc0 173 return quit;
e51d4895
DE
174}
175
84c92abd 176static int lxc_monitord_sock_accept(int fd, uint32_t events, void *data,
e51d4895
DE
177 struct lxc_epoll_descr *descr)
178{
2db65c21 179 int ret, clientfd;
e51d4895
DE
180 struct lxc_monitor *mon = data;
181 struct ucred cred;
182 socklen_t credsz = sizeof(cred);
183
b2a48508 184 ret = LXC_MAINLOOP_ERROR;
e51d4895
DE
185 clientfd = accept(fd, NULL, 0);
186 if (clientfd < 0) {
9044b79e 187 SYSERROR("Failed to accept connection for client file descriptor %d", fd);
e51d4895
DE
188 goto out;
189 }
190
191 if (fcntl(clientfd, F_SETFD, FD_CLOEXEC)) {
9044b79e 192 SYSERROR("Failed to set FD_CLOEXEC on client socket connection %d", clientfd);
e51d4895
DE
193 goto err1;
194 }
195
9044b79e 196 if (getsockopt(clientfd, SOL_SOCKET, SO_PEERCRED, &cred, &credsz)) {
197 SYSERROR("Failed to get credentials on client socket connection %d", clientfd);
e51d4895
DE
198 goto err1;
199 }
9044b79e 200
e51d4895 201 if (cred.uid && cred.uid != geteuid()) {
9044b79e 202 WARN("Monitor denied for uid %d on client socket connection %d", cred.uid, clientfd);
e51d4895
DE
203 goto err1;
204 }
205
206 if (mon->clientfds_cnt + 1 > mon->clientfds_size) {
207 int *clientfds;
9044b79e 208
e51d4895 209 clientfds = realloc(mon->clientfds,
60e4f6fa 210 (mon->clientfds_size + CLIENTFDS_CHUNK) * sizeof(mon->clientfds[0]));
e51d4895 211 if (clientfds == NULL) {
9044b79e 212 ERROR("Failed to realloc memory for %d client file descriptors",
60e4f6fa 213 mon->clientfds_size + CLIENTFDS_CHUNK);
e51d4895
DE
214 goto err1;
215 }
9044b79e 216
e51d4895
DE
217 mon->clientfds = clientfds;
218 mon->clientfds_size += CLIENTFDS_CHUNK;
219 }
220
221 ret = lxc_mainloop_add_handler(&mon->descr, clientfd,
222 lxc_monitord_sock_handler, mon);
9044b79e 223 if (ret < 0) {
224 ERROR("Failed to add socket handler");
e51d4895
DE
225 goto err1;
226 }
227
228 mon->clientfds[mon->clientfds_cnt++] = clientfd;
9044b79e 229 INFO("Accepted client file descriptor %d. Number of accepted file descriptors is now %d",
230 clientfd, mon->clientfds_cnt);
e51d4895
DE
231 goto out;
232
233err1:
234 close(clientfd);
9044b79e 235
e51d4895
DE
236out:
237 return ret;
238}
239
240static int lxc_monitord_sock_create(struct lxc_monitor *mon)
241{
242 struct sockaddr_un addr;
243 int fd;
244
245 if (lxc_monitor_sock_name(mon->lxcpath, &addr) < 0)
246 return -1;
247
aae93dd3 248 fd = lxc_abstract_unix_open(addr.sun_path, SOCK_STREAM, O_TRUNC);
e51d4895 249 if (fd < 0) {
6d1400b5 250 SYSERROR("Failed to open unix socket");
e51d4895
DE
251 return -1;
252 }
253
254 mon->listenfd = fd;
255 return 0;
256}
257
258static int lxc_monitord_sock_delete(struct lxc_monitor *mon)
259{
260 struct sockaddr_un addr;
261
262 if (lxc_monitor_sock_name(mon->lxcpath, &addr) < 0)
263 return -1;
9044b79e 264
e51d4895
DE
265 if (addr.sun_path[0])
266 unlink(addr.sun_path);
9044b79e 267
e51d4895
DE
268 return 0;
269}
270
271static int lxc_monitord_create(struct lxc_monitor *mon)
272{
273 int ret;
274
275 ret = lxc_monitord_fifo_create(mon);
276 if (ret < 0)
277 return ret;
278
9044b79e 279 return lxc_monitord_sock_create(mon);
e51d4895
DE
280}
281
282static void lxc_monitord_delete(struct lxc_monitor *mon)
283{
284 int i;
285
286 lxc_mainloop_del_handler(&mon->descr, mon->listenfd);
9044b79e 287 lxc_abstract_unix_close(mon->listenfd);
e51d4895
DE
288 lxc_monitord_sock_delete(mon);
289
290 lxc_mainloop_del_handler(&mon->descr, mon->fifofd);
e51d4895 291 lxc_monitord_fifo_delete(mon);
8bf1e61e 292 close(mon->fifofd);
e51d4895
DE
293
294 for (i = 0; i < mon->clientfds_cnt; i++) {
295 lxc_mainloop_del_handler(&mon->descr, mon->clientfds[i]);
296 close(mon->clientfds[i]);
297 }
9044b79e 298
e51d4895
DE
299 mon->clientfds_cnt = 0;
300}
301
84c92abd 302static int lxc_monitord_fifo_handler(int fd, uint32_t events, void *data,
e51d4895
DE
303 struct lxc_epoll_descr *descr)
304{
2db65c21 305 int ret, i;
e51d4895
DE
306 struct lxc_msg msglxc;
307 struct lxc_monitor *mon = data;
308
243fdadf 309 ret = lxc_read_nointr(fd, &msglxc, sizeof(msglxc));
e51d4895 310 if (ret != sizeof(msglxc)) {
b5be6a7c 311 SYSERROR("Reading from fifo failed");
b2a48508 312 return LXC_MAINLOOP_CLOSE;
e51d4895
DE
313 }
314
315 for (i = 0; i < mon->clientfds_cnt; i++) {
ff50dd77 316 ret = lxc_write_nointr(mon->clientfds[i], &msglxc, sizeof(msglxc));
60e4f6fa 317 if (ret < 0)
6d1400b5 318 SYSERROR("Failed to send message to client file descriptor %d",
2db65c21 319 mon->clientfds[i]);
e51d4895
DE
320 }
321
b2a48508 322 return LXC_MAINLOOP_CONTINUE;
e51d4895
DE
323}
324
325static int lxc_monitord_mainloop_add(struct lxc_monitor *mon)
326{
327 int ret;
328
329 ret = lxc_mainloop_add_handler(&mon->descr, mon->fifofd,
330 lxc_monitord_fifo_handler, mon);
331 if (ret < 0) {
9044b79e 332 ERROR("Failed to add to mainloop monitor handler for fifo");
e51d4895
DE
333 return -1;
334 }
335
336 ret = lxc_mainloop_add_handler(&mon->descr, mon->listenfd,
337 lxc_monitord_sock_accept, mon);
338 if (ret < 0) {
9044b79e 339 ERROR("Failed to add to mainloop monitor handler for listen socket");
e51d4895
DE
340 return -1;
341 }
342
343 return 0;
344}
345
346static void lxc_monitord_cleanup(void)
347{
348 lxc_monitord_delete(&mon);
349}
350
351static void lxc_monitord_sig_handler(int sig)
352{
d0dacf05 353 siglongjmp(mark, 1);
e51d4895
DE
354}
355
356int main(int argc, char *argv[])
357{
60e4f6fa 358 int ret, pipefd;
e51d4895
DE
359 char logpath[PATH_MAX];
360 sigset_t mask;
60e4f6fa 361 char *lxcpath = argv[1];
5cc0f22d
CB
362 bool mainloop_opened = false;
363 bool monitord_created = false;
73b910a3 364 struct lxc_log log;
e51d4895
DE
365
366 if (argc != 3) {
367 fprintf(stderr,
368 "Usage: lxc-monitord lxcpath sync-pipe-fd\n\n"
369 "NOTE: lxc-monitord is intended for use by lxc internally\n"
370 " and does not need to be run by hand\n\n");
371 exit(EXIT_FAILURE);
372 }
373
374 ret = snprintf(logpath, sizeof(logpath), "%s/lxc-monitord.log",
2db65c21 375 (strcmp(LXCPATH, lxcpath) ? lxcpath : LOGPATH));
e51d4895 376 if (ret < 0 || ret >= sizeof(logpath))
7e5af997 377 exit(EXIT_FAILURE);
e51d4895 378
73b910a3 379 log.name = NULL;
380 log.file = logpath;
4b73005c 381 log.level = "DEBUG";
73b910a3 382 log.prefix = "lxc-monitord";
383 log.quiet = 0;
384 log.lxcpath = lxcpath;
9044b79e 385
73b910a3 386 ret = lxc_log_init(&log);
e51d4895 387 if (ret)
9044b79e 388 INFO("Failed to open log file %s, log will be lost", lxcpath);
6edbfc86 389 lxc_log_options_no_override();
e51d4895 390
7e5af997
CB
391 if (lxc_safe_int(argv[2], &pipefd) < 0)
392 exit(EXIT_FAILURE);
e51d4895
DE
393
394 if (sigfillset(&mask) ||
395 sigdelset(&mask, SIGILL) ||
396 sigdelset(&mask, SIGSEGV) ||
397 sigdelset(&mask, SIGBUS) ||
398 sigdelset(&mask, SIGTERM) ||
b467714b 399 pthread_sigmask(SIG_BLOCK, &mask, NULL)) {
9044b79e 400 SYSERROR("Failed to set signal mask");
7e5af997 401 exit(EXIT_FAILURE);
e51d4895
DE
402 }
403
404 signal(SIGILL, lxc_monitord_sig_handler);
405 signal(SIGSEGV, lxc_monitord_sig_handler);
406 signal(SIGBUS, lxc_monitord_sig_handler);
407 signal(SIGTERM, lxc_monitord_sig_handler);
408
d0dacf05
CB
409 if (sigsetjmp(mark, 1) != 0)
410 goto on_signal;
411
e51d4895 412 ret = EXIT_FAILURE;
9044b79e 413
e51d4895
DE
414 memset(&mon, 0, sizeof(mon));
415 mon.lxcpath = lxcpath;
416 if (lxc_mainloop_open(&mon.descr)) {
9044b79e 417 ERROR("Failed to create mainloop");
60e4f6fa 418 goto on_error;
e51d4895 419 }
5cc0f22d 420 mainloop_opened = true;
e51d4895 421
5cc0f22d 422 if (lxc_monitord_create(&mon))
60e4f6fa 423 goto on_error;
5cc0f22d 424 monitord_created = true;
e51d4895
DE
425
426 /* sync with parent, we're ignoring the return from write
427 * because regardless if it works or not, the following
428 * close will sync us with the parent process. the
429 * if-empty-statement construct is to quiet the
430 * warn-unused-result warning.
431 */
ff50dd77 432 if (lxc_write_nointr(pipefd, "S", 1))
8f47bc3f 433 ;
e51d4895
DE
434 close(pipefd);
435
436 if (lxc_monitord_mainloop_add(&mon)) {
9044b79e 437 ERROR("Failed to add mainloop handlers");
60e4f6fa 438 goto on_error;
e51d4895
DE
439 }
440
9044b79e 441 NOTICE("lxc-monitord with pid %d is now monitoring lxcpath %s",
0059379f 442 lxc_raw_getpid(), mon.lxcpath);
9044b79e 443
60e4f6fa 444 for (;;) {
e51d4895 445 ret = lxc_mainloop(&mon.descr, 1000 * 30);
267bc7ed 446 if (ret) {
447 ERROR("mainloop returned an error");
448 break;
449 }
9044b79e 450
60e4f6fa 451 if (mon.clientfds_cnt <= 0) {
9044b79e 452 NOTICE("No remaining clients. lxc-monitord is exiting");
e51d4895
DE
453 break;
454 }
9044b79e 455
456 if (quit == LXC_MAINLOOP_CLOSE) {
457 NOTICE("Got quit command. lxc-monitord is exitting");
267bc7ed 458 break;
459 }
e51d4895
DE
460 }
461
5cc0f22d 462on_signal:
e51d4895 463 ret = EXIT_SUCCESS;
9044b79e 464
60e4f6fa 465on_error:
5cc0f22d
CB
466 if (monitord_created)
467 lxc_monitord_cleanup();
9044b79e 468
5cc0f22d
CB
469 if (mainloop_opened)
470 lxc_mainloop_close(&mon.descr);
d0dacf05 471
5cc0f22d 472 exit(ret);
e51d4895 473}