#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mdns-publish.h" /* --------------------------------------------------------------------- */ static struct xs_handle *xenstore; static int debug = 0; static char *appname = "mdns-publish-xendom"; static struct utsname uts; static char *service = "_xendom._tcp"; static int port = 9; static char vm_uuid[256]; static char dom_id[256]; static struct mdns_pub *mdns; static struct mdns_pub_entry *entry; /* --------------------------------------------------------------------- */ static int xen_init(void) { struct stat st; if (-1 == stat("/proc/xen", &st)) { mdns_log_printf(mdns, LOG_ERR, "/proc/xen not found, running on bare metal?\n"); return -1; } xenstore = xs_domain_open(); if (NULL == xenstore) { mdns_log_printf(mdns, LOG_ERR, "can't connect to xenstore (%s)\n", xs_domain_dev()); return -1; } return 0; } static int xen_get_info(void) { xs_transaction_t xst; char *xs_value; if (!(xst = xs_transaction_start(xenstore))) { mdns_log_printf(mdns, LOG_ERR, "can't start xenstore transaction\n"); goto out; } xs_value = xs_read(xenstore, xst, "vm", NULL); xs_transaction_end(xenstore, xst, 0); if (!xs_value) { mdns_log_printf(mdns, LOG_ERR, "can't read 'vm' value from xenstore\n"); goto out; } snprintf(vm_uuid, sizeof(vm_uuid), "vm-uuid=%s", xs_value+4); if (!(xst = xs_transaction_start(xenstore))) { mdns_log_printf(mdns, LOG_ERR, "can't start xenstore transaction\n"); goto out; } xs_value = xs_read(xenstore, xst, "domid", NULL); xs_transaction_end(xenstore, xst, 0); if (!xs_value) { mdns_log_printf(mdns, LOG_ERR, "can't read 'domid' value from xenstore\n"); goto out; } snprintf(dom_id, sizeof(dom_id), "dom-id=%s", xs_value); return 0; out: return -1; } static int xen_watch_add(char *path) { int ret = 0; /* Hmm, not working ... */ if (!xs_watch(xenstore, path, "token")) { mdns_log_printf(mdns, LOG_ERR, "%s: xs_watch for \"%s\" failed\n", __FUNCTION__, path); ret = -1; } return ret; } static int xen_publish(void) { static int count = 1; char buf[128]; if (debug) snprintf(buf, sizeof(buf), "Xen domain %s (%d)", uts.nodename, count++); else snprintf(buf, sizeof(buf), "Xen domain %s", uts.nodename); if (entry) mdns_pub_del(entry); entry = mdns_pub_add(mdns, buf, service, port, vm_uuid, dom_id, NULL); return 0; } static int xen_watch_data(void) { char **vec = NULL; unsigned int count; vec = xs_read_watch(xenstore, &count); mdns_log_printf(mdns, LOG_DEBUG, "%s: \"%s\"\n", __FUNCTION__, vec[XS_WATCH_PATH]); xen_get_info(); xen_publish(); if (vec) free(vec); return 0; } /* --------------------------------------------------------------------- */ static void usage(FILE *fp) { fprintf(fp, "This little daemon publishes xen domain info,\n" "via mDNS (using avahi), as service '_xendom._tcp'.\n" "\n" "usage: %s [options]\n" "options:\n" " -h print this text\n" " -d enable debug mode\n" "\n" "-- \n" "(c) 2006 Gerd Hoffmann \n", appname); } static int wait_fd(int fd, int secs) { struct timeval tv; fd_set rd; int rc; FD_ZERO(&rd); FD_SET(fd,&rd); tv.tv_sec = secs; tv.tv_usec = 0; rc = select(fd+1, &rd, NULL, NULL, &tv); if (-1 == rc) { if (EINTR == errno) return 0; } return rc; } int main(int argc, char*argv[]) { int ret = 1; int c; /* parse options */ for (;;) { if (-1 == (c = getopt(argc, argv, "hd"))) break; switch (c) { case 'd': debug = 1; break; case 'h': usage(stdout); exit(0); default: usage(stderr); exit(1); } } /* figure name */ uname(&uts); mdns_pub_appname = appname; if (!debug) mdns_daemonize(); mdns = mdns_pub_init(debug); if (NULL == mdns) goto fail; mdns_sigsetup(mdns); /* figure domain info */ if (0 != xen_init()) goto fail; xen_get_info(); xen_watch_add("vm"); xen_watch_add("domid"); /* enter main loop */ ret = 0; mdns_pub_start(mdns); xen_publish(); for (;;) { if (mdns_pub_appquit) break; switch (wait_fd(xs_fileno(xenstore),1)) { case -1: mdns_log_printf(mdns, LOG_ERR, "select: %s\n", strerror(errno)); mdns_pub_appquit = 1; case 0: /* timeout */ break; default: /* data to read */ xen_watch_data(); } } mdns_pub_del_all(mdns); mdns_pub_stop(mdns); fail: mdns_log_printf(mdns, ret ? LOG_ERR : LOG_INFO, "exiting (%d)%s%s\n", ret, mdns_pub_termsig ? ", on signal " : "", mdns_pub_termsig ? strsignal(mdns_pub_termsig) : ""); mdns_pub_fini(mdns); return ret; }