2 * lxc: linux Container library
4 * Copyright © 2012 Oracle.
7 * Dwight Engen <dwight.engen@oracle.com>
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.
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.
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
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
34 #include <netinet/in.h>
36 #include <sys/epoll.h>
37 #include <sys/param.h>
38 #include <sys/socket.h>
40 #include <sys/types.h>
43 #include <lxc/lxccontainer.h>
51 #define CLIENTFDS_CHUNK 64
53 lxc_log_define(lxc_monitord
, lxc
);
57 static void lxc_monitord_cleanup(void);
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
76 struct lxc_epoll_descr descr
;
79 static struct lxc_monitor mon
;
82 static int lxc_monitord_fifo_create(struct lxc_monitor
*mon
)
85 char fifo_path
[PATH_MAX
];
88 ret
= lxc_monitor_fifo_name(mon
->lxcpath
, fifo_path
, sizeof(fifo_path
), 1);
92 ret
= mknod(fifo_path
, S_IFIFO
|S_IRUSR
|S_IWUSR
, 0);
93 if (ret
< 0 && errno
!= EEXIST
) {
94 SYSINFO("Failed to mknod monitor fifo %s", fifo_path
);
98 mon
->fifofd
= open(fifo_path
, O_RDWR
);
99 if (mon
->fifofd
< 0) {
100 SYSERROR("Failed to open monitor fifo %s", fifo_path
);
106 lk
.l_whence
= SEEK_SET
;
110 if (fcntl(mon
->fifofd
, F_SETLK
, &lk
) != 0) {
111 /* another lxc-monitord is already running, don't start up */
112 SYSDEBUG("lxc-monitord already running on lxcpath %s", mon
->lxcpath
);
120 static int lxc_monitord_fifo_delete(struct lxc_monitor
*mon
)
122 char fifo_path
[PATH_MAX
];
125 ret
= lxc_monitor_fifo_name(mon
->lxcpath
, fifo_path
, sizeof(fifo_path
), 0);
133 static void lxc_monitord_sockfd_remove(struct lxc_monitor
*mon
, int fd
) {
136 if (lxc_mainloop_del_handler(&mon
->descr
, fd
))
137 CRIT("File descriptor %d not found in mainloop", fd
);
140 for (i
= 0; i
< mon
->clientfds_cnt
; i
++)
141 if (mon
->clientfds
[i
] == fd
)
144 if (i
>= mon
->clientfds_cnt
) {
145 CRIT("File descriptor %d not found in clients array", fd
);
146 lxc_monitord_cleanup();
150 memmove(&mon
->clientfds
[i
], &mon
->clientfds
[i
+1],
151 (mon
->clientfds_cnt
- i
- 1) * sizeof(mon
->clientfds
[0]));
152 mon
->clientfds_cnt
--;
155 static int lxc_monitord_sock_handler(int fd
, uint32_t events
, void *data
,
156 struct lxc_epoll_descr
*descr
)
158 struct lxc_monitor
*mon
= data
;
160 if (events
& EPOLLIN
) {
164 rc
= read(fd
, buf
, sizeof(buf
));
165 if (rc
> 0 && !strncmp(buf
, "quit", 4))
166 quit
= LXC_MAINLOOP_CLOSE
;
169 if (events
& EPOLLHUP
)
170 lxc_monitord_sockfd_remove(mon
, fd
);
175 static int lxc_monitord_sock_accept(int fd
, uint32_t events
, void *data
,
176 struct lxc_epoll_descr
*descr
)
179 struct lxc_monitor
*mon
= data
;
181 socklen_t credsz
= sizeof(cred
);
183 ret
= LXC_MAINLOOP_ERROR
;
184 clientfd
= accept(fd
, NULL
, 0);
186 SYSERROR("Failed to accept connection for client file descriptor %d", fd
);
190 if (fcntl(clientfd
, F_SETFD
, FD_CLOEXEC
)) {
191 SYSERROR("Failed to set FD_CLOEXEC on client socket connection %d", clientfd
);
195 if (getsockopt(clientfd
, SOL_SOCKET
, SO_PEERCRED
, &cred
, &credsz
)) {
196 SYSERROR("Failed to get credentials on client socket connection %d", clientfd
);
200 if (cred
.uid
&& cred
.uid
!= geteuid()) {
201 WARN("Monitor denied for uid %d on client socket connection %d", cred
.uid
, clientfd
);
205 if (mon
->clientfds_cnt
+ 1 > mon
->clientfds_size
) {
208 clientfds
= realloc(mon
->clientfds
,
209 (mon
->clientfds_size
+ CLIENTFDS_CHUNK
) * sizeof(mon
->clientfds
[0]));
210 if (clientfds
== NULL
) {
211 ERROR("Failed to realloc memory for %d client file descriptors",
212 mon
->clientfds_size
+ CLIENTFDS_CHUNK
);
216 mon
->clientfds
= clientfds
;
217 mon
->clientfds_size
+= CLIENTFDS_CHUNK
;
220 ret
= lxc_mainloop_add_handler(&mon
->descr
, clientfd
,
221 lxc_monitord_sock_handler
, mon
);
223 ERROR("Failed to add socket handler");
227 mon
->clientfds
[mon
->clientfds_cnt
++] = clientfd
;
228 INFO("Accepted client file descriptor %d. Number of accepted file descriptors is now %d",
229 clientfd
, mon
->clientfds_cnt
);
239 static int lxc_monitord_sock_create(struct lxc_monitor
*mon
)
241 struct sockaddr_un addr
;
244 if (lxc_monitor_sock_name(mon
->lxcpath
, &addr
) < 0)
247 fd
= lxc_abstract_unix_open(addr
.sun_path
, SOCK_STREAM
, O_TRUNC
);
249 SYSERROR("Failed to open unix socket");
257 static int lxc_monitord_sock_delete(struct lxc_monitor
*mon
)
259 struct sockaddr_un addr
;
261 if (lxc_monitor_sock_name(mon
->lxcpath
, &addr
) < 0)
264 if (addr
.sun_path
[0])
265 unlink(addr
.sun_path
);
270 static int lxc_monitord_create(struct lxc_monitor
*mon
)
274 ret
= lxc_monitord_fifo_create(mon
);
278 return lxc_monitord_sock_create(mon
);
281 static void lxc_monitord_delete(struct lxc_monitor
*mon
)
285 lxc_mainloop_del_handler(&mon
->descr
, mon
->listenfd
);
286 lxc_abstract_unix_close(mon
->listenfd
);
287 lxc_monitord_sock_delete(mon
);
289 lxc_mainloop_del_handler(&mon
->descr
, mon
->fifofd
);
290 lxc_monitord_fifo_delete(mon
);
293 for (i
= 0; i
< mon
->clientfds_cnt
; i
++) {
294 lxc_mainloop_del_handler(&mon
->descr
, mon
->clientfds
[i
]);
295 close(mon
->clientfds
[i
]);
298 mon
->clientfds_cnt
= 0;
301 static int lxc_monitord_fifo_handler(int fd
, uint32_t events
, void *data
,
302 struct lxc_epoll_descr
*descr
)
305 struct lxc_msg msglxc
;
306 struct lxc_monitor
*mon
= data
;
308 ret
= read(fd
, &msglxc
, sizeof(msglxc
));
309 if (ret
!= sizeof(msglxc
)) {
310 SYSERROR("Reading from fifo failed");
311 return LXC_MAINLOOP_CLOSE
;
314 for (i
= 0; i
< mon
->clientfds_cnt
; i
++) {
315 ret
= write(mon
->clientfds
[i
], &msglxc
, sizeof(msglxc
));
317 SYSERROR("Failed to send message to client file descriptor %d",
321 return LXC_MAINLOOP_CONTINUE
;
324 static int lxc_monitord_mainloop_add(struct lxc_monitor
*mon
)
328 ret
= lxc_mainloop_add_handler(&mon
->descr
, mon
->fifofd
,
329 lxc_monitord_fifo_handler
, mon
);
331 ERROR("Failed to add to mainloop monitor handler for fifo");
335 ret
= lxc_mainloop_add_handler(&mon
->descr
, mon
->listenfd
,
336 lxc_monitord_sock_accept
, mon
);
338 ERROR("Failed to add to mainloop monitor handler for listen socket");
345 static void lxc_monitord_cleanup(void)
347 lxc_monitord_delete(&mon
);
350 static void lxc_monitord_sig_handler(int sig
)
355 int main(int argc
, char *argv
[])
358 char logpath
[PATH_MAX
];
360 char *lxcpath
= argv
[1];
361 bool mainloop_opened
= false;
362 bool monitord_created
= false;
367 "Usage: lxc-monitord lxcpath sync-pipe-fd\n\n"
368 "NOTE: lxc-monitord is intended for use by lxc internally\n"
369 " and does not need to be run by hand\n\n");
373 ret
= snprintf(logpath
, sizeof(logpath
), "%s/lxc-monitord.log",
374 (strcmp(LXCPATH
, lxcpath
) ? lxcpath
: LOGPATH
));
375 if (ret
< 0 || ret
>= sizeof(logpath
))
381 log
.prefix
= "lxc-monitord";
383 log
.lxcpath
= lxcpath
;
385 ret
= lxc_log_init(&log
);
387 INFO("Failed to open log file %s, log will be lost", lxcpath
);
388 lxc_log_options_no_override();
390 if (lxc_safe_int(argv
[2], &pipefd
) < 0)
393 if (sigfillset(&mask
) ||
394 sigdelset(&mask
, SIGILL
) ||
395 sigdelset(&mask
, SIGSEGV
) ||
396 sigdelset(&mask
, SIGBUS
) ||
397 sigdelset(&mask
, SIGTERM
) ||
398 pthread_sigmask(SIG_BLOCK
, &mask
, NULL
)) {
399 SYSERROR("Failed to set signal mask");
403 signal(SIGILL
, lxc_monitord_sig_handler
);
404 signal(SIGSEGV
, lxc_monitord_sig_handler
);
405 signal(SIGBUS
, lxc_monitord_sig_handler
);
406 signal(SIGTERM
, lxc_monitord_sig_handler
);
408 if (sigsetjmp(mark
, 1) != 0)
413 memset(&mon
, 0, sizeof(mon
));
414 mon
.lxcpath
= lxcpath
;
415 if (lxc_mainloop_open(&mon
.descr
)) {
416 ERROR("Failed to create mainloop");
419 mainloop_opened
= true;
421 if (lxc_monitord_create(&mon
))
423 monitord_created
= true;
425 /* sync with parent, we're ignoring the return from write
426 * because regardless if it works or not, the following
427 * close will sync us with the parent process. the
428 * if-empty-statement construct is to quiet the
429 * warn-unused-result warning.
431 if (write(pipefd
, "S", 1))
435 if (lxc_monitord_mainloop_add(&mon
)) {
436 ERROR("Failed to add mainloop handlers");
440 NOTICE("lxc-monitord with pid %d is now monitoring lxcpath %s",
441 lxc_raw_getpid(), mon
.lxcpath
);
444 ret
= lxc_mainloop(&mon
.descr
, 1000 * 30);
446 ERROR("mainloop returned an error");
450 if (mon
.clientfds_cnt
<= 0) {
451 NOTICE("No remaining clients. lxc-monitord is exiting");
455 if (quit
== LXC_MAINLOOP_CLOSE
) {
456 NOTICE("Got quit command. lxc-monitord is exitting");
465 if (monitord_created
)
466 lxc_monitord_cleanup();
469 lxc_mainloop_close(&mon
.descr
);