2 * Copyright (C) 2009 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include <sys/types.h>
32 #include <sys/socket.h>
35 #define UNIX_PATH_MAX 108
37 #include <apr_general.h>
38 #include <apr_network_io.h>
39 #include <apr_getopt.h>
40 #include <apr_strings.h>
41 #include <apr_thread_proc.h>
44 #include <apr_portable.h>
46 #include "hostinfod.h"
48 static void main_loop (void);
49 static void set_reread_socket_dir (const apr_pollfd_t *, void *);
50 static void do_reread_socket_dir (void);
51 static struct guest_description *guest_added (const char *sock_path, const char *name);
52 static void guest_removed (struct guest_description *);
53 static void guest_event (const apr_pollfd_t *, void *);
54 static void modify_pollfd_reqevents (struct guest_description *, apr_int16_t);
56 const char *conf_file = DEFAULT_CONF_FILE;
57 char *socket_dir = NULL;
58 char *guests_file = NULL;
60 char *libvirt_uri = NULL;
61 int libvirt_uri_set_on_cmdline = 0;
64 int verbose_set_on_cmdline = 0;
66 int foreground_set_on_cmdline = 0;
68 int messages_to_stderr = 1;
70 static int reread_socket_dir = 1;
73 apr_pool_t *pool = NULL;
74 static apr_pollset_t *set = NULL;
76 static apr_hash_t *guests = NULL; /* Hash "driver-name" -> guest_description */
78 typedef void (*poll_callback) (const apr_pollfd_t *, void *data);
79 struct callback_data {
80 poll_callback callback;
87 printf ("hostinfod (virt-hostinfo daemon)\n"
88 "Copyright (C) 2009 Red Hat Inc.\n"
91 " hostinfod [--options]\n"
94 " --help Display full usage\n"
95 " -c file | --config file\n"
96 " Configuration file (default: %s)\n"
97 " -C uri | --connect uri\n"
98 " Set libvirt connection URI (default: NULL)\n"
99 " -f | --foreground\n"
100 " Run in the foreground (don't fork)\n"
101 " -v Enable verbose messages (sent to syslog)\n",
109 apr_pool_create (&pool, NULL);
114 main (int argc, char *argv[])
116 static const apr_getopt_option_t options[] = {
117 { "config", 'c', TRUE, "configuration file" },
118 { "connect", 'C', TRUE, "libvirt connection URI" },
119 { "foreground", 'f', FALSE, "run in foreground (don't fork)" },
120 { "verbose", 'v', FALSE, "enable verbose messages" },
121 { "help", '?', FALSE, "display help" },
122 { NULL, 0, 0, NULL },
129 /* REGISTER_COMMAND macro should have caused this to be
130 * initialized. If it's not, then something is badly wrong ...
133 error ("internal error: daemon not initialized - no commands registered");
137 apr_getopt_init (&opt, pool, argc, argv);
139 socket_dir = apr_pstrdup (pool, DEFAULT_SOCKET_DIR);
140 guests_file = apr_pstrdup (pool, DEFAULT_GUESTS_FILE);
143 while ((r = apr_getopt_long (opt, options, &c, &optarg)) == APR_SUCCESS) {
147 /* If the user is specifying this on the command line, then
148 * it should exist. They may have typo'd the name.
150 if (access (conf_file, R_OK) == -1) {
151 perrorf ("%s", conf_file);
156 libvirt_uri = optarg;
157 libvirt_uri_set_on_cmdline = 1;
161 foreground_set_on_cmdline = 1;
165 verbose_set_on_cmdline = 1;
175 fprintf (stderr, "%s: unknown command line option\n", argv[0]);
179 /* Read the config file. */
180 read_main_conf_file ();
182 /* Connect to libvirt. */
185 /* Monitor the socket directory. */
186 monitor_socket_dir ();
188 /* Create the guests hash. */
189 guests = apr_hash_make (pool);
191 /* Create the initial pollset, just containing inotify socket. */
192 r = apr_pollset_create (&set, 1024 /* ? */, pool, 0);
193 if (r != APR_SUCCESS) {
194 paprerror (r, "apr_pollset_create");
197 apr_socket_t *tsock = NULL;
198 r = apr_os_sock_put (&tsock, &sockets_inotify_fd, pool);
199 if (r != APR_SUCCESS) {
200 paprerror (r, "apr_os_sock_put");
203 apr_pollfd_t *tpollfd = apr_palloc (pool, sizeof *tpollfd);
205 tpollfd->desc_type = APR_POLL_SOCKET;
206 tpollfd->reqevents = APR_POLLIN;
207 tpollfd->rtnevents = 0;
208 tpollfd->desc.s = tsock;
210 struct callback_data *callback_data =
211 apr_palloc (pool, sizeof *callback_data);
212 callback_data->callback = set_reread_socket_dir;
213 callback_data->data = NULL;
214 tpollfd->client_data = callback_data;
216 r = apr_pollset_add (set, tpollfd);
217 if (r != APR_SUCCESS) {
218 paprerror (r, "apr_pollset_add");
227 /* After we detach from the terminal, all further messages
228 * should just go to syslog.
230 messages_to_stderr = 0;
233 message ("%s started", PACKAGE_STRING);
235 message ("%s exiting", PACKAGE_STRING);
245 apr_int32_t numdescs;
246 const apr_pollfd_t *descs;
250 /* A socket has appeared or disappeared from the socket directory. */
251 if (reread_socket_dir) {
252 do_reread_socket_dir ();
253 reread_socket_dir = 0;
259 r = apr_pollset_poll (set, -1, &numdescs, &descs);
260 if (r != APR_SUCCESS) {
261 paprerror (r, "apr_pollset_poll");
265 /* Perform the callbacks. */
266 for (i = 0; i < numdescs; ++i) {
267 struct callback_data *callback_data;
269 callback_data = descs[i].client_data;
270 callback_data->callback (&descs[i], callback_data->data);
276 set_reread_socket_dir (const apr_pollfd_t *ignored1, void *ignored2)
278 reread_socket_dir = 1;
282 do_reread_socket_dir (void)
284 static int count = 0;
285 int added = 0, removed = 0;
291 struct guest_description *hval;
292 apr_hash_index_t *hi;
295 debug ("reading socket directory (counter = %d)", count);
297 /* Discard anything which appears on the inotify socket. We will
298 * reread the whole directory each time.
301 r = read (sockets_inotify_fd, buf, sizeof buf);
303 if (errno != EAGAIN && errno != EWOULDBLOCK) {
304 perrorf ("inotify socket: read");
310 dir = opendir (socket_dir);
312 perrorf ("%s: failed to open socket directory", socket_dir);
316 while (errno = 0, (d = readdir (dir)) != NULL) {
317 /* We expect the name to be "<driver>-<name>" (where <driver>
318 * is the libvirt driver name, and <name> is the name of the
319 * domain). Skip any dot-entries and anything that doesn't have
322 if (d->d_name[0] == '.')
324 if (strlen (d->d_name) < 3 || strchr (&d->d_name[1], '-') == NULL)
327 /* It must be a Unix domain socket - skip anything else. */
328 snprintf (buf, sizeof buf, "%s/%s", socket_dir, d->d_name);
329 if (stat (buf, &statbuf) == -1) {
330 perrorf ("stat: %s", buf);
333 if (!S_ISSOCK (statbuf.st_mode))
336 /* See if we have an entry matching this already. */
337 hval = (struct guest_description *)
338 apr_hash_get (guests, d->d_name, APR_HASH_KEY_STRING);
340 hval = guest_added (buf, d->d_name);
344 /* NB. It's not well documented, but the hash table
345 * implementation DOES NOT copy the key internally. Therefore
346 * we have to use hval->name (ie. our copy) as the key, NOT
347 * d->d_name, even though they are the same string.
349 apr_hash_set (guests, hval->name, APR_HASH_KEY_STRING, hval);
353 hval->counter = count;
356 perrorf ("%s: error reading socket directory", socket_dir);
360 if (closedir (dir) == -1) {
361 perrorf ("%s: error closing socket directory", socket_dir);
365 /* Iterate over the hash and look for any guests which have
366 * gone away. The guest_description.counter field won't have
369 for (hi = apr_hash_first (pool, guests); hi; hi = apr_hash_next (hi)) {
370 /* On RHEL 5 this gives:
371 * dereferencing type-punned pointer will break strict-aliasing rules
374 apr_hash_this (hi, NULL, NULL, (void **) &hval);
376 if (hval->counter != count) {
377 /* This hash table implementation allows you to delete the
378 * current entry safely.
380 apr_hash_set (guests, hval->name, APR_HASH_KEY_STRING, NULL);
382 /* guest_removed frees hval but does not unregister it from the
385 guest_removed (hval);
390 debug ("finished reading socket directory, added %d, removed %d, guests %d",
391 added, removed, apr_hash_count (guests));
394 /* This is called whenever we detect that a guest socket has been
395 * created in the socket directory.
397 static struct guest_description *
398 guest_added (const char *sock_path, const char *name)
400 struct guest_description *hval = NULL;
403 unsigned retries = 0, tns;
404 enum guest_state state;
405 apr_pool_t *guest_pool = NULL;
406 struct sockaddr_un addr;
409 sock = socket (AF_UNIX, SOCK_STREAM, 0);
415 if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1) {
416 perrorf ("fcntl: O_NONBLOCK");
420 if (fcntl (sock, F_SETFD, FD_CLOEXEC) == -1) {
421 perrorf ("fcntl: FD_CLOEXEC");
426 addr.sun_family = AF_UNIX;
427 strncpy (addr.sun_path, sock_path, UNIX_PATH_MAX);
428 addr.sun_path[UNIX_PATH_MAX-1] = '\0';
431 r = connect (sock, (struct sockaddr *) &addr, sizeof addr);
433 /* Nasty race condition: The moment the listener binds the socket,
434 * we see it in the directory and can try to connect to it.
435 * However the listener might not have called listen(2) yet, which
436 * means if we are faster than the other end, we will get
437 * ECONNREFUSED. If this happens, sleep a bit and try again a few
440 if (errno == ECONNREFUSED) {
443 ts.tv_sec = tns / 1000000000;
444 ts.tv_nsec = tns % 1000000000;
445 nanosleep (&ts, NULL);
451 if (errno != EINPROGRESS) {
452 /* Dead socket - cull these dead sockets from the directory. */
453 perrorf ("connect: %s", sock_path);
458 state = guest_state_connecting;
461 state = guest_state_request;
463 /* Create a pool which can be used for allocations
464 * during the lifetime of this guest connection.
466 apr_pool_create (&guest_pool, pool);
468 hval = apr_pcalloc (guest_pool, sizeof *hval);
469 hval->pool = guest_pool;
471 /* Create the remaining hash fields. */
473 hval->name = apr_pstrdup (hval->pool, name);
474 hval->sock_path = apr_pstrdup (hval->pool, sock_path);
476 hval->request_max = 4096;
477 hval->request = apr_palloc (hval->pool, hval->request_max);
478 hval->lasttime = apr_hash_make (hval->pool);
480 /* Convert Unix fd into APR socket type. */
481 r = apr_os_sock_put (&hval->aprsock, &sock, hval->pool);
482 if (r != APR_SUCCESS) {
483 paprerror (r, "apr_os_sock_put: %s", sock_path);
487 /* Register the socket in the pollset. */
488 hval->pollfd.p = hval->pool;
489 hval->pollfd.desc_type = APR_POLL_SOCKET;
490 if (hval->state == guest_state_connecting)
491 hval->pollfd.reqevents = APR_POLLOUT;
493 hval->pollfd.reqevents = APR_POLLIN;
494 hval->pollfd.rtnevents = 0;
495 hval->pollfd.desc.s = hval->aprsock;
497 struct callback_data *callback_data =
498 apr_palloc (hval->pool, sizeof *callback_data);
499 callback_data->callback = guest_event;
500 callback_data->data = hval;
501 hval->pollfd.client_data = callback_data;
503 r = apr_pollset_add (set, &hval->pollfd);
504 if (r != APR_SUCCESS) {
505 paprerror (r, "apr_pollset_add: %s", sock_path);
509 message ("new guest added: %s", hval->name);
513 /* This is called whenever we detect that a guest socket has been
514 * removed from the socket directory. The guest_description parameter
515 * is freed after this call and must not be used again.
518 guest_removed (struct guest_description *hval)
522 message ("guest removed: %s", hval->name);
524 /* Unregister the socket from the pollset. */
525 r = apr_pollset_remove (set, &hval->pollfd);
526 if (r != APR_SUCCESS)
527 paprerror (r, "%s: apr_pollset_remove", hval->name);
529 if (close (hval->sock) == -1)
530 pwarningf ("close: %s", hval->sock_path);
532 /* This also frees hval and all related data. */
533 apr_pool_destroy (hval->pool);
536 /* Forcibly remove a guest, removing the socket from the
537 * socket directory and cleaning up any resources used in
538 * the daemon. The guest_description parameter is freed
539 * after this call and must not be used again.
542 guest_force_close (struct guest_description *hval)
544 debug ("forcibly closing guest: %s", hval->name);
546 apr_hash_set (guests, hval->name, APR_HASH_KEY_STRING, NULL);
547 unlink (hval->sock_path);
548 guest_removed (hval);
551 /* Difference between two timespec structures (r = a - b) */
553 diff_timespec (struct timespec *r,
554 const struct timespec *a, const struct timespec *b)
556 if (a->tv_nsec - b->tv_nsec < 0) {
557 r->tv_sec = a->tv_sec - b->tv_sec - 1;
558 r->tv_nsec = 1000000000 + a->tv_nsec - b->tv_nsec;
560 r->tv_sec = a->tv_sec - b->tv_sec;
561 r->tv_nsec = a->tv_nsec - b->tv_nsec;
567 /* This is called when there is some event from the guest, eg.
568 * connection finished, read, write or closed.
571 guest_event (const apr_pollfd_t *pollfd, void *hvalv)
573 struct guest_description *hval = hvalv;
574 int err, max, r, extra;
579 #ifdef HAVE_CLOCK_GETTIME
580 clock_gettime (CLOCK_MONOTONIC, &now);
583 gettimeofday (&tv, NULL);
584 now.tv_sec = tv.tv_sec;
585 now.tv_nsec = tv.tv_usec * 1000;
588 /* If the guest keeps doing bad stuff, eventually lose patience with it. */
589 if (hval->penalty >= 100) {
590 error ("%s: guest did too much bad stuff, so we stopped talking to it",
592 guest_force_close (hval);
596 /* Decrement the penalty once a minute, so the guest can recover. */
597 if (hval->penalty > 0) {
598 struct timespec diff;
600 diff_timespec (&diff, &now, &hval->last_penalty_decr);
602 if (diff.tv_sec >= 60) {
604 hval->last_penalty_decr = now;
608 switch (hval->state) {
609 case guest_state_connecting:
610 /* Once we get a write event, we know the socket has
611 * connected, or there is an error.
615 getsockopt (hval->sock, SOL_SOCKET, SO_ERROR, &err, &len);
617 hval->state = guest_state_request;
620 perrorf ("connect: %s", hval->sock_path);
621 guest_force_close (hval);
626 case guest_state_request:
627 /* Reading the guest's request, a single line terminated by \r?\n */
628 max = hval->request_max - hval->request_posn;
629 if (max <= 0) { /* Request too long w/o termination. */
631 hval->request_posn = 0;
634 r = read (hval->sock, &hval->request[hval->request_posn], max);
635 if (r == 0) { /* Socket closed. */
636 guest_force_close (hval);
640 if (errno != EAGAIN && errno != EWOULDBLOCK) {
641 perrorf ("read: %s", hval->sock_path);
642 guest_force_close (hval);
648 hval->request_posn += r;
650 /* Have we got a terminating \n character in the buffer yet? Note
651 * the buffer is not NUL-terminated which is why we use memchr.
654 p = memchr (hval->request, '\n', hval->request_posn);
658 /* Is there more after the \n char? Normal guests shouldn't do
659 * this, but it can be an attempt to reestablish synchronization.
660 * It's documented that we throw away all but the last command sent,
663 extra = &hval->request[hval->request_posn]-(p+1);
666 memmove (hval->request, p+1, extra);
667 hval->request_posn = extra;
671 /* Looks like we've got ourselves a command. Remove trailing
672 * \r?\n char(s) and NUL-terminate the command string.
675 assert (hval->request_posn >= 1);
676 assert (p == &hval->request[hval->request_posn-1]);
677 hval->request_posn--;
680 if (hval->request_posn > 0 && *p == '\r') {
681 hval->request_posn--;
687 execute_command (&now, hval, hval->request);
689 hval->request_posn = 0;
692 case guest_state_reply:
693 /* Keep writing out the reply buffer until we've sent
696 max = hval->reply_size - hval->reply_posn;
698 hval->state = guest_state_request;
702 r = write (hval->sock, &hval->reply[hval->reply_posn], max);
704 if (errno != EAGAIN && errno != EWOULDBLOCK) {
705 perrorf ("write: %s", hval->sock_path);
706 guest_force_close (hval);
712 hval->reply_posn += r;
713 if (hval->reply_posn >= hval->reply_size)
714 hval->state = guest_state_request;
718 case guest_state_dead:
719 /* We shouldn't get an event here. */
723 /* Depending on the (new) state we want to set the
724 * events that we would like poll to give us next time.
726 switch (hval->state) {
727 case guest_state_connecting:
728 modify_pollfd_reqevents (hval, APR_POLLOUT);
730 case guest_state_request:
731 modify_pollfd_reqevents (hval, APR_POLLIN);
733 case guest_state_reply:
734 modify_pollfd_reqevents (hval, APR_POLLOUT);
736 case guest_state_dead:
737 modify_pollfd_reqevents (hval, 0);
742 /* It turns out you can't just update the pollfd->reqevents
743 * field. Instead you have to remove the pollfd and reregister
747 modify_pollfd_reqevents (struct guest_description *hval,
748 apr_int16_t new_reqevents)
752 if (hval->pollfd.reqevents != new_reqevents) {
753 r = apr_pollset_remove (set, &hval->pollfd);
754 if (r != APR_SUCCESS) {
755 paprerror (r, "%s: apr_pollset_remove", hval->name);
759 hval->pollfd.reqevents = new_reqevents;
760 r = apr_pollset_add (set, &hval->pollfd);
761 if (r != APR_SUCCESS)
762 paprerror (r, "%s: apr_pollset_add", hval->name);