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