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