/* virt-hostinfo * Copyright (C) 2009 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include "hostinfod.h" static void main_loop (void); static void set_reread_socket_dir (const apr_pollfd_t *); static void do_reread_socket_dir (void); typedef void (*poll_callback) (const apr_pollfd_t *); const char *conf_file = DEFAULT_CONF_FILE; char *socket_dir = NULL; char *guests_file = NULL; int verbose = 0; int verbose_set_on_cmdline = 0; int foreground = 0; int foreground_set_on_cmdline = 0; int messages_to_stderr = 1; static int reread_socket_dir = 1; static int quit = 0; apr_pool_t *pool = NULL; static apr_pollset_t *set; static void usage (void) { printf ("hostinfod (virt-hostinfo daemon)\n" "Copyright (C) 2009 Red Hat Inc.\n" "\n" "Usage:\n" " hostinfod [--options]\n" "\n" "Options:\n" " --help Display full usage\n" " -c file | --config file\n" " Configuration file (default: %s)\n" " -f | --foreground\n" " Run in the foreground (don't fork)\n" " -v Enable verbose messages (sent to syslog, and to\n" " stderr if -d option is given)\n", DEFAULT_CONF_FILE); } int main (int argc, char *argv[]) { static const apr_getopt_option_t options[] = { { "config", 'c', TRUE, "configuration file" }, { "foreground", 'f', FALSE, "run in foreground (don't fork)" }, { "verbose", 'v', FALSE, "enable verbose messages" }, { "help", '?', FALSE, "display help" }, { NULL, 0, 0, NULL }, }; apr_status_t r; apr_getopt_t *opt; int c; const char *optarg; apr_initialize (); apr_pool_create (&pool, NULL); apr_getopt_init (&opt, pool, argc, argv); init_syslog (); socket_dir = apr_pstrdup (pool, DEFAULT_SOCKET_DIR); guests_file = apr_pstrdup (pool, DEFAULT_GUESTS_FILE); /* Command line. */ while ((r = apr_getopt_long (opt, options, &c, &optarg)) == APR_SUCCESS) { switch (c) { case 'c': conf_file = optarg; /* If the user is specifying this on the command line, then * it should exist. They may have typo'd the name. */ if (access (conf_file, R_OK) == -1) { perrorf ("%s", conf_file); exit (1); } break; case 'f': foreground = 1; foreground_set_on_cmdline = 1; break; case 'v': verbose = 1; verbose_set_on_cmdline = 1; break; case '?': usage (); exit (0); default: abort (); } } if (r != APR_EOF) { fprintf (stderr, "%s: unknown command line option\n", argv[0]); exit (1); } /* Read the config file. */ read_main_conf_file (); /* Monitor the socket directory. */ monitor_socket_dir (); /* Create the initial pollset, just containing inotify socket. */ r = apr_pollset_create (&set, 1024 /* ? */, pool, 0); if (r != APR_SUCCESS) { paprerror (r, "apr_pollset_create"); exit (1); } apr_socket_t *tsock; r = apr_os_sock_put (&tsock, &sockets_inotify_fd, pool); if (r != APR_SUCCESS) { paprerror (r, "apr_os_sock_put"); exit (1); } apr_pollfd_t *tpollfd = apr_palloc (pool, sizeof *tpollfd); tpollfd->p = pool; tpollfd->desc_type = APR_POLL_SOCKET; tpollfd->reqevents = APR_POLLIN; tpollfd->rtnevents = 0; tpollfd->desc.s = tsock; tpollfd->client_data = set_reread_socket_dir; r = apr_pollset_add (set, tpollfd); if (r != APR_SUCCESS) { paprerror (r, "apr_pollset_add"); exit (1); } /* Daemonize. */ chdir ("/"); if (!foreground) { apr_proc_detach (1); /* After we detach from the terminal, all further messages * should just go to syslog. */ messages_to_stderr = 0; } message (PACKAGE_STRING); main_loop (); apr_terminate (); return 0; } static void main_loop (void) { apr_status_t r; apr_int32_t numdescs; const apr_pollfd_t *descs; int i; while (!quit) { /* A socket has appeared or disappeared from the socket directory. */ if (reread_socket_dir) { do_reread_socket_dir (); reread_socket_dir = 0; } /* Poll. */ r = apr_pollset_poll (set, 0, &numdescs, &descs); if (r != APR_SUCCESS) { paprerror (r, "apr_pollset_poll"); exit (1); } /* Perform the callbacks. */ for (i = 0; i < numdescs; ++i) { poll_callback callback; callback = descs[i].client_data; callback (&descs[i]); } } } static void set_reread_socket_dir (const apr_pollfd_t *_) { reread_socket_dir = 1; } static void do_reread_socket_dir (void) { char buf[256]; debug ("reading socket directory"); /* Discard anything which appears on the inotify socket. We will * reread the whole directory each time. */ while (read (sockets_inotify_fd, buf, sizeof buf) > 0) ; }