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