Documentation fixes.
[virt-hostinfo.git] / hostinfod / main.c
1 /* virt-hostinfo
2  * Copyright (C) 2009 Red Hat Inc.
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <unistd.h>
27 #include <dirent.h>
28 #include <time.h>
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <sys/stat.h>
32 #include <sys/socket.h>
33 #include <sys/un.h>
34
35 #define UNIX_PATH_MAX 108
36
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>
42 #include <apr_poll.h>
43 #include <apr_hash.h>
44 #include <apr_portable.h>
45
46 #include "hostinfod.h"
47
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);
55
56 const char *conf_file = DEFAULT_CONF_FILE;
57 char *socket_dir = NULL;
58 char *guests_file = NULL;
59
60 char *libvirt_uri = NULL;
61 int libvirt_uri_set_on_cmdline = 0;
62
63 int verbose = 0;
64 int verbose_set_on_cmdline = 0;
65 int foreground = 0;
66 int foreground_set_on_cmdline = 0;
67
68 int messages_to_stderr = 1;
69
70 static int reread_socket_dir = 1;
71 static int quit = 0;
72
73 apr_pool_t *pool = NULL;
74 static apr_pollset_t *set = NULL;
75
76 static apr_hash_t *guests = NULL; /* Hash "driver-name" -> guest_description */
77
78 typedef void (*poll_callback) (const apr_pollfd_t *, void *data);
79 struct callback_data {
80   poll_callback callback;
81   void *data;
82 };
83
84 static void
85 usage (void)
86 {
87   printf ("hostinfod (virt-hostinfo daemon)\n"
88           "Copyright (C) 2009 Red Hat Inc.\n"
89           "\n"
90           "Usage:\n"
91           "  hostinfod [--options]\n"
92           "\n"
93           "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",
102           DEFAULT_CONF_FILE);
103 }
104
105 void
106 initialize (void)
107 {
108   apr_initialize ();
109   apr_pool_create (&pool, NULL);
110   init_syslog ();
111 }
112
113 int
114 main (int argc, char *argv[])
115 {
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 },
123   };
124   apr_status_t r;
125   apr_getopt_t *opt;
126   int c;
127   const char *optarg;
128
129   /* REGISTER_COMMAND macro should have caused this to be
130    * initialized.  If it's not, then something is badly wrong ...
131    */
132   if (!pool) {
133     error ("internal error: daemon not initialized - no commands registered");
134     exit (1);
135   }
136
137   apr_getopt_init (&opt, pool, argc, argv);
138
139   socket_dir = apr_pstrdup (pool, DEFAULT_SOCKET_DIR);
140   guests_file = apr_pstrdup (pool, DEFAULT_GUESTS_FILE);
141
142   /* Command line. */
143   while ((r = apr_getopt_long (opt, options, &c, &optarg)) == APR_SUCCESS) {
144     switch (c) {
145     case 'c':
146       conf_file = optarg;
147       /* If the user is specifying this on the command line, then
148        * it should exist.  They may have typo'd the name.
149        */
150       if (access (conf_file, R_OK) == -1) {
151         perrorf ("%s", conf_file);
152         exit (1);
153       }
154       break;
155     case 'C':
156       libvirt_uri = optarg;
157       libvirt_uri_set_on_cmdline = 1;
158       break;
159     case 'f':
160       foreground = 1;
161       foreground_set_on_cmdline = 1;
162       break;
163     case 'v':
164       verbose = 1;
165       verbose_set_on_cmdline = 1;
166       break;
167     case '?':
168       usage ();
169       exit (0);
170     default:
171       abort ();
172     }
173   }
174   if (r != APR_EOF) {
175     fprintf (stderr, "%s: unknown command line option\n", argv[0]);
176     exit (1);
177   }
178
179   /* Read the config file. */
180   read_main_conf_file ();
181
182   /* Connect to libvirt. */
183   init_libvirt ();
184
185   /* Monitor the socket directory. */
186   monitor_socket_dir ();
187
188   /* Create the guests hash. */
189   guests = apr_hash_make (pool);
190
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");
195     exit (1);
196   }
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");
201     exit (1);
202   }
203   apr_pollfd_t *tpollfd = apr_palloc (pool, sizeof *tpollfd);
204   tpollfd->p = pool;
205   tpollfd->desc_type = APR_POLL_SOCKET;
206   tpollfd->reqevents = APR_POLLIN;
207   tpollfd->rtnevents = 0;
208   tpollfd->desc.s = tsock;
209
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;
215
216   r = apr_pollset_add (set, tpollfd);
217   if (r != APR_SUCCESS) {
218     paprerror (r, "apr_pollset_add");
219     exit (1);
220   }
221
222   /* Daemonize. */
223   chdir ("/");
224   if (!foreground) {
225     apr_proc_detach (1);
226
227     /* After we detach from the terminal, all further messages
228      * should just go to syslog.
229      */
230     messages_to_stderr = 0;
231   }
232
233   message ("%s started", PACKAGE_STRING);
234   main_loop ();
235   message ("%s exiting", PACKAGE_STRING);
236
237   apr_terminate ();
238   return 0;
239 }
240
241 static void
242 main_loop (void)
243 {
244   apr_status_t r;
245   apr_int32_t numdescs;
246   const apr_pollfd_t *descs;
247   int i;
248
249   while (!quit) {
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;
254     }
255
256     /* Poll. */
257     numdescs = 0;
258     descs = NULL;
259     r = apr_pollset_poll (set, -1, &numdescs, &descs);
260     if (r != APR_SUCCESS) {
261       paprerror (r, "apr_pollset_poll");
262       exit (1);
263     }
264
265     /* Perform the callbacks. */
266     for (i = 0; i < numdescs; ++i) {
267       struct callback_data *callback_data;
268
269       callback_data = descs[i].client_data;
270       callback_data->callback (&descs[i], callback_data->data);
271     }
272   }
273 }
274
275 static void
276 set_reread_socket_dir (const apr_pollfd_t *ignored1, void *ignored2)
277 {
278   reread_socket_dir = 1;
279 }
280
281 static void
282 do_reread_socket_dir (void)
283 {
284   static int count = 0;
285   int added = 0, removed = 0;
286   char buf[PATH_MAX];
287   int r;
288   DIR *dir;
289   struct dirent *d;
290   struct stat statbuf;
291   struct guest_description *hval;
292   apr_hash_index_t *hi;
293
294   count++;
295   debug ("reading socket directory (counter = %d)", count);
296
297   /* Discard anything which appears on the inotify socket.  We will
298    * reread the whole directory each time.
299    */
300   do {
301     r = read (sockets_inotify_fd, buf, sizeof buf);
302     if (r == -1) {
303       if (errno != EAGAIN && errno != EWOULDBLOCK) {
304         perrorf ("inotify socket: read");
305         exit (1);
306       }
307     }
308   } while (r > 0);
309
310   dir = opendir (socket_dir);
311   if (dir == NULL) {
312     perrorf ("%s: failed to open socket directory", socket_dir);
313     exit (1);
314   }
315
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
320      * this form.
321      */
322     if (d->d_name[0] == '.')
323       continue;
324     if (strlen (d->d_name) < 3 || strchr (&d->d_name[1], '-') == NULL)
325       continue;
326
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);
331       continue;
332     }
333     if (!S_ISSOCK (statbuf.st_mode))
334       continue;
335
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);
339     if (!hval) {
340       hval = guest_added (buf, d->d_name);
341       if (!hval)
342         continue;
343
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.
348        */
349       apr_hash_set (guests, hval->name, APR_HASH_KEY_STRING, hval);
350       added++;
351     }
352
353     hval->counter = count;
354   }
355   if (errno != 0) {
356     perrorf ("%s: error reading socket directory", socket_dir);
357     exit (1);
358   }
359
360   if (closedir (dir) == -1) {
361     perrorf ("%s: error closing socket directory", socket_dir);
362     exit (1);
363   }
364
365   /* Iterate over the hash and look for any guests which have
366    * gone away.  The guest_description.counter field won't have
367    * been updated.
368    */
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
372      * XXX
373      */
374     apr_hash_this (hi, NULL, NULL, (void **) &hval);
375
376     if (hval->counter != count) {
377       /* This hash table implementation allows you to delete the
378        * current entry safely.
379        */
380       apr_hash_set (guests, hval->name, APR_HASH_KEY_STRING, NULL);
381
382       /* guest_removed frees hval but does not unregister it from the
383        * hash.
384        */
385       guest_removed (hval);
386       removed++;
387     }
388   }
389
390   debug ("finished reading socket directory, added %d, removed %d, guests %d",
391          added, removed, apr_hash_count (guests));
392 }
393
394 /* This is called whenever we detect that a guest socket has been
395  * created in the socket directory.
396  */
397 static struct guest_description *
398 guest_added (const char *sock_path, const char *name)
399 {
400   struct guest_description *hval = NULL;
401   int sock;
402   int r;
403   unsigned retries = 0, tns;
404   enum guest_state state;
405   apr_pool_t *guest_pool = NULL;
406   struct sockaddr_un addr;
407   struct timespec ts;
408
409   sock = socket (AF_UNIX, SOCK_STREAM, 0);
410   if (sock == -1) {
411     perrorf ("socket");
412     return NULL;
413   }
414
415   if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1) {
416     perrorf ("fcntl: O_NONBLOCK");
417     close (sock);
418     return NULL;
419   }
420   if (fcntl (sock, F_SETFD, FD_CLOEXEC) == -1) {
421     perrorf ("fcntl: FD_CLOEXEC");
422     close (sock);
423     return NULL;
424   }
425
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';
429
430  again:
431   r = connect (sock, (struct sockaddr *) &addr, sizeof addr);
432   if (r == -1) {
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
438      * times.
439      */
440     if (errno == ECONNREFUSED) {
441       if (retries <= 10) {
442         tns = 1 << retries;
443         ts.tv_sec = tns / 1000000000;
444         ts.tv_nsec = tns % 1000000000;
445         nanosleep (&ts, NULL);
446         retries++;
447         goto again;
448       }
449     }
450
451     if (errno != EINPROGRESS) {
452       /* Dead socket - cull these dead sockets from the directory. */
453       perrorf ("connect: %s", sock_path);
454       close (sock);
455       unlink (sock_path);
456       return NULL;
457     }
458     state = guest_state_connecting;
459   }
460   else
461     state = guest_state_request;
462
463   /* Create a pool which can be used for allocations
464    * during the lifetime of this guest connection.
465    */
466   apr_pool_create (&guest_pool, pool);
467
468   hval = apr_pcalloc (guest_pool, sizeof *hval);
469   hval->pool = guest_pool;
470
471   /* Create the remaining hash fields. */
472   hval->state = state;
473   hval->name = apr_pstrdup (hval->pool, name);
474   hval->sock_path = apr_pstrdup (hval->pool, sock_path);
475   hval->sock = sock;
476   hval->request_max = 4096;
477   hval->request = apr_palloc (hval->pool, hval->request_max);
478   hval->lasttime = apr_hash_make (hval->pool);
479
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);
484     exit (1);
485   }
486
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;
492   else
493     hval->pollfd.reqevents = APR_POLLIN;
494   hval->pollfd.rtnevents = 0;
495   hval->pollfd.desc.s = hval->aprsock;
496
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;
502
503   r = apr_pollset_add (set, &hval->pollfd);
504   if (r != APR_SUCCESS) {
505     paprerror (r, "apr_pollset_add: %s", sock_path);
506     exit (1);
507   }
508
509   message ("new guest added: %s", hval->name);
510   return hval;
511 }
512
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.
516  */
517 static void
518 guest_removed (struct guest_description *hval)
519 {
520   apr_status_t r;
521
522   message ("guest removed: %s", hval->name);
523
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);
528
529   if (close (hval->sock) == -1)
530     pwarningf ("close: %s", hval->sock_path);
531
532   /* This also frees hval and all related data. */
533   apr_pool_destroy (hval->pool);
534 }
535
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.
540  */
541 static void
542 guest_force_close (struct guest_description *hval)
543 {
544   debug ("forcibly closing guest: %s", hval->name);
545
546   apr_hash_set (guests, hval->name, APR_HASH_KEY_STRING, NULL);
547   unlink (hval->sock_path);
548   guest_removed (hval);
549 }
550
551 /* Difference between two timespec structures (r = a - b) */
552 struct timespec *
553 diff_timespec (struct timespec *r,
554                const struct timespec *a, const struct timespec *b)
555 {
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;
559   } else {
560     r->tv_sec = a->tv_sec - b->tv_sec;
561     r->tv_nsec = a->tv_nsec - b->tv_nsec;
562   }
563
564   return r;
565 }
566
567 /* This is called when there is some event from the guest, eg.
568  * connection finished, read, write or closed.
569  */
570 static void
571 guest_event (const apr_pollfd_t *pollfd, void *hvalv)
572 {
573   struct guest_description *hval = hvalv;
574   int err, max, r, extra;
575   socklen_t len;
576   char *p;
577   struct timespec now;
578
579 #ifdef HAVE_CLOCK_GETTIME
580   clock_gettime (CLOCK_MONOTONIC, &now);
581 #else
582   struct timeval tv;
583   gettimeofday (&tv, NULL);
584   now.tv_sec = tv.tv_sec;
585   now.tv_nsec = tv.tv_usec * 1000;
586 #endif
587
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",
591            hval->name);
592     guest_force_close (hval);
593     return;
594   }
595
596   /* Decrement the penalty once a minute, so the guest can recover. */
597   if (hval->penalty > 0) {
598     struct timespec diff;
599
600     diff_timespec (&diff, &now, &hval->last_penalty_decr);
601
602     if (diff.tv_sec >= 60) {
603       hval->penalty--;
604       hval->last_penalty_decr = now;
605     }
606   }
607
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.
612      */
613     err = 0;
614     len = sizeof err;
615     getsockopt (hval->sock, SOL_SOCKET, SO_ERROR, &err, &len);
616     if (err == 0)
617       hval->state = guest_state_request;
618     else {
619       errno = err;
620       perrorf ("connect: %s", hval->sock_path);
621       guest_force_close (hval);
622       return;
623     }
624     break;
625
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. */
630       hval->penalty++;
631       hval->request_posn = 0;
632       break;
633     }
634     r = read (hval->sock, &hval->request[hval->request_posn], max);
635     if (r == 0) {               /* Socket closed. */
636       guest_force_close (hval);
637       return;
638     }
639     if (r == -1) {
640       if (errno != EAGAIN && errno != EWOULDBLOCK) {
641         perrorf ("read: %s", hval->sock_path);
642         guest_force_close (hval);
643         return;
644       }
645       break;
646     }
647
648     hval->request_posn += r;
649
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.
652      */
653   again:
654     p = memchr (hval->request, '\n', hval->request_posn);
655     if (p == NULL)
656       break;
657
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,
661      * so let's do that.
662      */
663     extra = &hval->request[hval->request_posn]-(p+1);
664     if (extra > 0) {
665       hval->penalty++;
666       memmove (hval->request, p+1, extra);
667       hval->request_posn = extra;
668       goto again;
669     }
670
671     /* Looks like we've got ourselves a command.  Remove trailing
672      * \r?\n char(s) and NUL-terminate the command string.
673      */
674     assert (*p == '\n');
675     assert (hval->request_posn >= 1);
676     assert (p == &hval->request[hval->request_posn-1]);
677     hval->request_posn--;
678     p--;
679
680     if (hval->request_posn > 0 && *p == '\r') {
681       hval->request_posn--;
682       p--;
683     }
684
685     *(p+1) = '\0';
686
687     execute_command (&now, hval, hval->request);
688
689     hval->request_posn = 0;
690     break;
691
692   case guest_state_reply:
693     /* Keep writing out the reply buffer until we've sent
694      * the whole thing.
695      */
696     max = hval->reply_size - hval->reply_posn;
697     if (max <= 0) {
698       hval->state = guest_state_request;
699       break;
700     }
701
702     r = write (hval->sock, &hval->reply[hval->reply_posn], max);
703     if (r == -1) {
704       if (errno != EAGAIN && errno != EWOULDBLOCK) {
705         perrorf ("write: %s", hval->sock_path);
706         guest_force_close (hval);
707         return;
708       }
709       break;
710     }
711
712     hval->reply_posn += r;
713     if (hval->reply_posn >= hval->reply_size)
714       hval->state = guest_state_request;
715
716     break;
717
718   case guest_state_dead:
719     /* We shouldn't get an event here. */
720     hval->penalty++;
721   }
722
723   /* Depending on the (new) state we want to set the
724    * events that we would like poll to give us next time.
725    */
726   switch (hval->state) {
727   case guest_state_connecting:
728     modify_pollfd_reqevents (hval, APR_POLLOUT);
729     break;
730   case guest_state_request:
731     modify_pollfd_reqevents (hval, APR_POLLIN);
732     break;
733   case guest_state_reply:
734     modify_pollfd_reqevents (hval, APR_POLLOUT);
735     break;
736   case guest_state_dead:
737     modify_pollfd_reqevents (hval, 0);
738     break;
739   }
740 }
741
742 /* It turns out you can't just update the pollfd->reqevents
743  * field.  Instead you have to remove the pollfd and reregister
744  * it in the pollset.
745  */
746 static void
747 modify_pollfd_reqevents (struct guest_description *hval,
748                          apr_int16_t new_reqevents)
749 {
750   apr_status_t r;
751
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);
756       return;
757     }
758
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);
763   }
764 }