/* Get qemu to change buffers. */ static void qemu_flip_buffer(int domid, int next_active) { char digit = '0' + next_active; unsigned int len; char *active_str, **watch; struct timeval tv; fd_set fdset; /* Tell qemu that we want it to start writing log-dirty bits to the * other buffer */ if (!xs_write(xs, XBT_NULL, qemu_next_active_path, &digit, 1)) errx(1, "can't write next-active to store path (%s)\n", qemu_next_active_path); /* Wait a while for qemu to signal that it has switched to the new * active buffer */ read_again: tv.tv_sec = 5; tv.tv_usec = 0; FD_ZERO(&fdset); FD_SET(xs_fileno(xs), &fdset); if ((select(xs_fileno(xs) + 1, &fdset, NULL, NULL, &tv)) != 1) errx(1, "timed out waiting for qemu to switch buffers\n"); watch = xs_read_watch(xs, &len); free(watch); active_str = xs_read(xs, XBT_NULL, qemu_active_path, &len); if (active_str == NULL || active_str[0] - '0' != next_active) /* Watch fired but value is not yet right */ goto read_again; }
static int get_pty_fd(struct xs_handle *xs, char *path, int seconds) /* Check for a pty in xenstore, open it and return its fd. * Assumes there is already a watch set in the store for this path. */ { struct timeval tv; fd_set watch_fdset; int xs_fd = xs_fileno(xs), pty_fd = -1; int start, now; unsigned int len = 0; char *pty_path, **watch_paths;; start = now = time(NULL); do { tv.tv_usec = 0; tv.tv_sec = (start + seconds) - now; FD_ZERO(&watch_fdset); FD_SET(xs_fd, &watch_fdset); if (select(xs_fd + 1, &watch_fdset, NULL, NULL, &tv)) { /* Read the watch to drain the buffer */ watch_paths = xs_read_watch(xs, &len); free(watch_paths); /* We only watch for one thing, so no need to * disambiguate: just read the pty path */ pty_path = xs_read(xs, XBT_NULL, path, &len); if (pty_path != NULL) { pty_fd = open(pty_path, O_RDWR | O_NOCTTY); if (pty_fd == -1) err(errno, "Could not open tty `%s'", pty_path); free(pty_path); } } } while (pty_fd == -1 && (now = time(NULL)) < start + seconds); return pty_fd; }
/* Register a QEMU graphical console, and key/mouse handler, * connecting up their events to the frontend */ static int xenfb_register_console(struct xenfb *xenfb) { /* Register our keyboard & mouse handlers */ qemu_add_kbd_event_handler(xenfb_key_event, xenfb); qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb, xenfb->abs_pointer_wanted, "Xen PVFB Mouse"); /* Tell QEMU to allocate a graphical console */ graphic_console_init(xenfb->ds, xenfb_update, xenfb_invalidate, xenfb_screen_dump, xenfb); if (xenfb->ds->dpy_resize_shared) dpy_resize_shared(xenfb->ds, xenfb->width, xenfb->height, xenfb->depth, xenfb->row_stride, xenfb->pixels + xenfb->offset); else dpy_resize(xenfb->ds, xenfb->width, xenfb->height); if (qemu_set_fd_handler2(xc_evtchn_fd(xenfb->evt_xch), NULL, xenfb_dispatch_channel, NULL, xenfb) < 0) return -1; if (qemu_set_fd_handler2(xs_fileno(xenfb->xsh), NULL, xenfb_dispatch_store, NULL, xenfb) < 0) return -1; fprintf(stderr, "Xen Framebuffer registered\n"); return 0; }
static int get_pty_fd(struct xs_handle *xs, char *path, int seconds) /* Check for a pty in xenstore, open it and return its fd. * Assumes there is already a watch set in the store for this path. */ { struct timeval tv; fd_set watch_fdset; int xs_fd = xs_fileno(xs), pty_fd = -1; int start, now; unsigned int len = 0; char *pty_path, **watch_paths; start = now = time(NULL); do { tv.tv_usec = 0; tv.tv_sec = (start + seconds) - now; FD_ZERO(&watch_fdset); FD_SET(xs_fd, &watch_fdset); if (select(xs_fd + 1, &watch_fdset, NULL, NULL, &tv)) { /* Read the watch to drain the buffer */ watch_paths = xs_read_watch(xs, &len); free(watch_paths); /* We only watch for one thing, so no need to * disambiguate: just read the pty path */ pty_path = xs_read(xs, XBT_NULL, path, &len); if (pty_path != NULL) { if (access(pty_path, R_OK|W_OK) != 0) continue; pty_fd = open(pty_path, O_RDWR | O_NOCTTY); if (pty_fd == -1) err(errno, "Could not open tty `%s'", pty_path); free(pty_path); } } } while (pty_fd == -1 && (now = time(NULL)) < start + seconds); #ifdef __sun__ if (pty_fd != -1) { struct termios term; /* * The pty may come from either xend (with pygrub) or * xenconsoled. It may have tty semantics set up, or not. * While it isn't strictly necessary to have those * semantics here, it is good to have a consistent * state that is the same as under Linux. * * If tcgetattr fails, they have not been set up, * so go ahead and set them up now, by pushing the * ptem and ldterm streams modules. */ if (tcgetattr(pty_fd, &term) < 0) { ioctl(pty_fd, I_PUSH, "ptem"); ioctl(pty_fd, I_PUSH, "ldterm"); } } #endif return pty_fd; }
static int wait_for_backend_state_change() { char keybuf[128]; int my_domid; unsigned int len; int backend_state; int seconds; char *buf, **vec; int ret; int xs_fd; struct timeval tv; fd_set watch_fdset; int start, now; backend_state = STATE_UNDEFINED; xs_fd = xs_fileno(xsh); start = now = time(NULL); my_domid = atoi(xs_read(xsh, 0, "domid", &len)); snprintf(keybuf, sizeof(keybuf), "/local/domain/0/backend/audio/%d/%d/state", my_domid, device_id); /*XXX: hardcoded */ seconds = 10; do { tv.tv_usec = 0; tv.tv_sec = (start + seconds) - now; FD_ZERO(&watch_fdset); FD_SET(xs_fd, &watch_fdset); ret=select(xs_fd + 1, &watch_fdset, NULL, NULL, &tv); if (ret==-1) /* error */ return -1; else if (ret) { /* Read the watch to drain the buffer */ vec = xs_read_watch(xsh, &len); buf = xs_read(xsh, XBT_NULL, vec[0], &len); if (buf == 0) { /* usually means that the backend isn't there yet */ continue; }; backend_state = atoi(buf); free(buf); free(vec); } /* else: timeout */ } while (backend_state == STATE_UNDEFINED && \ (now = time(NULL)) < start + seconds); return backend_state; }
char* clickos_read_handler(int domid, char *elem, char *attr) { char *ctrlpath = NULL, *elempath = NULL; char *rpath = NULL, *wpath = NULL; char *value; int err; unsigned int len = 0; struct pollfd fds[1]; if (!xs) { xenstore_init(domid); } asprintf(&ctrlpath, "/local/domain/%d/clickos/0/control", domid); asprintf(&elempath, "/local/domain/%d/clickos/0/elements", domid); asprintf(&wpath, "%s/read/%s/%s", ctrlpath, elem, attr); asprintf(&rpath, "%s/%s/%s", elempath, elem, attr); th = xs_transaction_start(xs); xenstore_write(wpath, " "); xs_transaction_end(xs, th, 0); err = xs_watch(xs, rpath, "lock"); if (!err) { printf("Error setting a watch\n"); return NULL; } fds[0].fd = xs_fileno(xs); fds[0].events = (POLLIN); while (len <= 0) { if (poll(fds, 1, 1000) <= 0) { continue; } retry_wh: th = xs_transaction_start(xs); //value = xenstore_read(rpath); value = xs_read(xs, XBT_NULL, rpath, &len); //printf("read: len %d value %s\n", len, value); if (!xs_transaction_end(xs, th, 0)) { if (errno == EAGAIN) goto retry_wh; } usleep(5000); } err = xs_unwatch(xs, rpath, "lock"); th = xs_transaction_start(xs); xs_write(xs, th, rpath, "", 0); err = xs_transaction_end(xs, th, 0); return value; }
/* Register a watch against a backend device, and setup * QEMU event loop to poll the xenstore FD for notification */ static int xenfb_wait_for_backend(struct xenfb_device *dev, IOHandler *handler) { fprintf(stderr, "Doing backend watch on %s\n", dev->nodename); if (!xs_watch(dev->xenfb->xsh, dev->nodename, "")) { fprintf(stderr, "Watch for dev failed\n"); return -1; } if (qemu_set_fd_handler2(xs_fileno(dev->xenfb->xsh), NULL, handler, NULL, dev) < 0) return -1; return 0; }
/* returns -1 on error or death, 0 if domain is running, 1 if suspended */ static int check_shutdown(checkpoint_state* s) { unsigned int count; int xsfd; char **vec; char buf[16]; xc_dominfo_t info; xsfd = xs_fileno(s->xsh); /* loop on watch if it fires for another domain */ while (1) { if (pollfd(s, xsfd) < 0) return -1; vec = xs_read_watch(s->xsh, &count); if (s->watching_shutdown == 1) { s->watching_shutdown = 2; return 0; } if (!vec) { fprintf(stderr, "empty watch fired\n"); continue; } snprintf(buf, sizeof(buf), "%d", s->domid); if (!strcmp(vec[XS_WATCH_TOKEN], buf)) break; } if (xc_domain_getinfo(s->xch, s->domid, 1, &info) != 1 || info.domid != s->domid) { snprintf(errbuf, sizeof(errbuf), "error getting info for domain %u", s->domid); s->errstr = errbuf; return -1; } if (!info.shutdown) { snprintf(errbuf, sizeof(errbuf), "domain %u not shut down", s->domid); s->errstr = errbuf; return 0; } if (info.shutdown_reason != SHUTDOWN_suspend) return -1; return 1; }
static int xenpaging_wait_for_event_or_timeout(struct xenpaging *paging) { xc_interface *xch = paging->xc_handle; xc_evtchn *xce = paging->vm_event.xce_handle; char **vec, *val; unsigned int num; struct pollfd fd[2]; int port; int rc; int timeout; /* Wait for event channel and xenstore */ fd[0].fd = xc_evtchn_fd(xce); fd[0].events = POLLIN | POLLERR; fd[1].fd = xs_fileno(paging->xs_handle); fd[1].events = POLLIN | POLLERR; /* No timeout while page-out is still in progress */ timeout = paging->use_poll_timeout ? 100 : 0; rc = poll(fd, 2, timeout); if ( rc < 0 ) { if (errno == EINTR) return 0; PERROR("Poll exited with an error"); return -1; } /* First check for guest shutdown */ if ( rc && fd[1].revents & POLLIN ) { DPRINTF("Got event from xenstore\n"); vec = xs_read_watch(paging->xs_handle, &num); if ( vec ) { DPRINTF("path '%s' token '%s'\n", vec[XS_WATCH_PATH], vec[XS_WATCH_TOKEN]); if ( strcmp(vec[XS_WATCH_TOKEN], watch_token) == 0 ) { /* If our guest disappeared, set interrupt flag and fall through */ if ( xs_is_domain_introduced(paging->xs_handle, paging->vm_event.domain_id) == false ) { xs_unwatch(paging->xs_handle, "@releaseDomain", watch_token); interrupted = SIGQUIT; /* No further poll result processing */ rc = 0; } } else if ( strcmp(vec[XS_WATCH_PATH], watch_target_tot_pages) == 0 ) { int ret, target_tot_pages; val = xs_read(paging->xs_handle, XBT_NULL, vec[XS_WATCH_PATH], NULL); if ( val ) { ret = sscanf(val, "%d", &target_tot_pages); if ( ret > 0 ) { /* KiB to pages */ target_tot_pages >>= 2; if ( target_tot_pages < 0 || target_tot_pages > paging->max_pages ) target_tot_pages = paging->max_pages; paging->target_tot_pages = target_tot_pages; /* Disable poll() delay while new target is not yet reached */ paging->use_poll_timeout = 0; DPRINTF("new target_tot_pages %d\n", target_tot_pages); } free(val); } }
int main(int argc, char **argv) { struct termios attr; int domid; char *sopt = "h"; int ch; int opt_ind=0; struct option lopt[] = { { "help", 0, 0, 'h' }, { 0 }, }; char *path; int spty, xsfd; struct xs_handle *xs; char *end; while((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { switch(ch) { case 'h': usage(argv[0]); exit(0); break; } } if ((argc - optind) != 1) { fprintf(stderr, "Invalid number of arguments\n"); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); exit(EINVAL); } domid = strtol(argv[optind], &end, 10); if (end && *end) { fprintf(stderr, "Invalid DOMID `%s'\n", argv[optind]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); exit(EINVAL); } xs = xs_daemon_open(); if (xs == NULL) { err(errno, "Could not contact XenStore"); } signal(SIGTERM, sighandler); path = xs_get_domain_path(xs, domid); if (path == NULL) err(errno, "xs_get_domain_path()"); path = realloc(path, strlen(path) + strlen("/console/tty") + 1); if (path == NULL) err(ENOMEM, "realloc"); strcat(path, "/console/tty"); /* FIXME consoled currently does not assume domain-0 doesn't have a console which is good when we break domain-0 up. To keep us user friendly, we'll bail out here since no data will ever show up on domain-0. */ if (domid == 0) { fprintf(stderr, "Can't specify Domain-0\n"); exit(EINVAL); } /* Set a watch on this domain's console pty */ if (!xs_watch(xs, path, "")) err(errno, "Can't set watch for console pty"); xsfd = xs_fileno(xs); /* Wait a little bit for tty to appear. There is a race condition that occurs after xend creates a domain. This code might be running before consoled has noticed the new domain and setup a pty for it. */ spty = get_pty_fd(xs, path, 5); if (spty == -1) { err(errno, "Could not read tty from store"); } init_term(spty, &attr); init_term(STDIN_FILENO, &attr); console_loop(spty, xs, path); restore_term(STDIN_FILENO, &attr); free(path); return 0; }
int main(int argc, char **argv) { sigset_t sigmask; struct pollfd pollfds[NPFD_COUNT]; int npollfds; int k; int64_t wait_ms; struct paging_data pd0; struct paging_data pd1; bool recheck_time; int init_pass = 0; /* * if running interactively, output initially to the terminal, * otherwise to syslog right away */ if (isatty(fileno(stderr))) { log_fp = stderr; log_syslog = false; } else { log_fp = NULL; log_syslog = true; } if (log_syslog) openlog(progname, LOG_CONS | LOG_PID, LOG_DAEMON); /* parse arguments */ handle_cmdline(argc, argv); if (run_as_daemon) daemonize(); debug_msg(1, "debug level set to %d", debug_level); // page_size = sysconf(_SC_PAGESIZE); // if (page_size <= 0) // fatal_msg("unable to get system page size"); /* * Block signals so that they aren't handled according to their * default dispositions */ sigemptyset(&sigmask); sigaddset(&sigmask, SIGHUP); sigaddset(&sigmask, SIGTERM); if (sigprocmask(SIG_BLOCK, &sigmask, NULL) < 0) fatal_perror("sigprocmask"); /* * Receive signals on file descriptors */ sigemptyset(&sigmask); sigaddset(&sigmask, SIGHUP); fd_sighup = signalfd(-1, &sigmask, 0); if (fd_sighup < 0) fatal_perror("signalfd(SIGHUP)"); sigemptyset(&sigmask); sigaddset(&sigmask, SIGTERM); fd_sigterm = signalfd(-1, &sigmask, 0); if (fd_sigterm < 0) fatal_perror("signalfd(SIGTERM)"); /* select clock to use */ select_clk_id(); /* verify we are running under a hypervisor */ verify_hypervisor(); pollfds[NPFD_SIGTERM].fd = fd_sigterm; pollfds[NPFD_SIGTERM].events = POLLIN|POLLPRI; pollfds[NPFD_SIGHUP].fd = fd_sighup; pollfds[NPFD_SIGHUP].events = POLLIN|POLLPRI; /* keep xs poll fd last in the array */ pollfds[NPFD_XS].fd = -1; pollfds[NPFD_XS].events = POLLIN|POLLPRI; /* initialize xenstore structure */ initialize_xs(pollfds); pollfds[NPFD_XS].fd = xs_fileno(xs); get_paging_data(&pd0); for (;;) { try_subscribe_membalance_settings(); /* calculate sleep time till next sample point */ if (initialized_xs) { wait_ms = timespec_diff_ms(pd0.ts, getnow()) + interval * MSEC_PER_SEC; } else { /* if xs not initialzied, keep retrying */ wait_ms = interval * MSEC_PER_SEC; if (++init_pass > 30) wait_ms *= 2; } if (wait_ms >= tolerance_ms) { for (k = 0; k < countof(pollfds); k++) pollfds[k].revents = 0; /* if settings need to be updated, retry in 1 sec or sooner */ if (need_update_membalance_settings) wait_ms = min(wait_ms, MSEC_PER_SEC); /* include xs in the poll only if has initialized xs */ npollfds = countof(pollfds); if (!initialized_xs) npollfds--; if (poll(pollfds, npollfds, wait_ms) < 0) { if (errno == EINTR) continue; fatal_perror("poll"); } recheck_time = false; handle_signals(pollfds, &recheck_time); if (!initialized_xs) { /* try to initialzie xs */ initialize_xs(NULL); /* if successful, start monitoring page map-in rate */ if (initialized_xs) get_paging_data(&pd0); continue; } if (pollfds[NPFD_XS].revents & (POLLIN|POLLPRI)) { /* a watched value in xenstore has been changed */ handle_xs_watch(); recheck_time = true; } if (need_update_membalance_settings) update_membalance_settings(); if (recheck_time) { /* go sleep again if wait interval has not expired yet */ if (timespec_diff_ms(getnow(), pd0.ts) < interval * MSEC_PER_SEC - tolerance_ms) continue; } } if (!initialized_xs) { /* try to initialzie xs */ initialize_xs(NULL); /* if successful, start monitoring page map-in rate */ if (initialized_xs) get_paging_data(&pd0); continue; } /* process sample and set it as the new "previous" one */ get_paging_data(&pd1); process_sample(&pd1, &pd0); pd0 = pd1; } /* close connection to xenstore */ shutdown_xs(); return EXIT_SUCCESS; }
bool XenDomainWatcher::waitForDomainsOrTimeout( std::list<DomainInfo> &domains, int ms ) { struct pollfd fd; bool ret = false; fd.revents = 0; fd.fd = xs_fileno( xsh_ ); fd.events = POLLIN | POLLERR; int rc = poll( &fd, 1, ms ); domains.clear(); if ( rc == 0 ) return false; // timeout if ( fd.revents & POLLIN ) { unsigned int num; char **vec = xs_read_watch( xsh_, &num ); if ( vec && introduceToken_ == vec[XS_WATCH_TOKEN] ) { int domid = 1; xc_dominfo_t dominfo; int err = -1; while ( ( err = xc_domain_getinfo( xci_, domid, 1, &dominfo ) ) == 1 ) { domid = dominfo.domid + 1; if ( xs_is_domain_introduced( xsh_, dominfo.domid ) ) { // New domain if ( domIds_.find( dominfo.domid ) == domIds_.end() ) { domIds_.insert( dominfo.domid ); std::stringstream ss; ss << "/local/domain/" << dominfo.domid << "/name"; std::string path = ss.str(); errno = 0; char *name = static_cast<char *>( xs_read_timeout( xsh_, XBT_NULL, path.c_str(), NULL, 1 ) ); if ( !name && errno && logHelper_ ) logHelper_->error( std::string( "xs_read() error reading " ) + ss.str() + ": " + strerror( errno ) ); if ( name ) { // domain running or new domain w name set ss.str( "" ); ss << "/local/domain/" << dominfo.domid << "/console/tty"; path = ss.str(); DomainInfo domain; errno = 0; void *console = xs_read_timeout( xsh_, XBT_NULL, path.c_str(), NULL, 1 ); if ( !console && errno && logHelper_ ) logHelper_->error( std::string( "xs_read() error reading " ) + ss.str() + ": " + strerror( errno ) ); if ( console ) { free( console ); domain.isAlreadyRunning = true; } else { domain.isAlreadyRunning = false; } domain.name = name; free( name ); domains.push_back( domain ); ret = true; } else { // new domain, name not yet set ss.str( "" ); ss << "dom" << dominfo.domid; xs_watch( xsh_, path.c_str(), ss.str().c_str() ); } } } } if ( err == -1 && ( errno == EACCES || errno == EPERM ) ) throw Exception( "access denied for xc_domain_getinfo()" ); } if ( vec && releaseToken_ == vec[XS_WATCH_TOKEN] ) { int domid = 1; xc_dominfo_t dominfo; while ( xc_domain_getinfo( xci_, domid, 1, &dominfo ) == 1 ) { domid = dominfo.domid + 1; if ( !xs_is_domain_introduced( xsh_, dominfo.domid ) ) domIds_.erase( dominfo.domid ); } } if ( vec && !strncmp( vec[XS_WATCH_TOKEN], "dom", 3 ) ) { int domid = 1; if ( sscanf( vec[XS_WATCH_TOKEN], "dom%u", &domid ) == 1 ) { char *name = static_cast<char *>( xs_read_timeout( xsh_, XBT_NULL, vec[XS_WATCH_PATH], NULL, 1 ) ); if ( name ) { DomainInfo domain; domain.isAlreadyRunning = false; domain.name = name; free( name ); domains.push_back( domain ); xs_unwatch( xsh_, vec[XS_WATCH_PATH], vec[XS_WATCH_TOKEN] ); ret = true; } } } free( vec ); } return ret; }
int xenstore_fd(void) { if (xsh) return xs_fileno(xsh); return -1; }
int main (int argc, char **argv) { int i; struct xs_handle *xs; xs_transaction_t th; char *path; int fd; fd_set set; int er; char **vec; unsigned int num_strings; char * buf; unsigned int len; char *program; char **arguments; int arguments_count; pid_t pid; int j; char *last_value = NULL; int status; program_name = argv[0]; i = decode_switches (argc, argv); if (argc - i < 1) usage(1); path = argv[i++]; if (argc - i > 0) { program = argv[i++]; arguments_count = argc - i; arguments = malloc(sizeof(char*) * (argc - i + 2)); arguments[0] = program; for (j=0; j<arguments_count; j++) arguments[j + 1] = argv[i + j]; arguments[j + 1] = NULL; } else { program = NULL; arguments = NULL; arguments_count = 0; } if (want_verbose) { printf("Path: %s\n", path); if (program) { printf("Program: %s", program); for (i=1; i<arguments_count + 1; i++) printf(" %s", arguments[i]); printf("\n"); } } /* Get a connection to the daemon */ xs = xs_daemon_open(); if ( xs == NULL ) xs = xs_domain_open(); if ( xs == NULL ) { error("Unable to connect to XenStore"); exit(1); } /* Create a watch on /local/domain/0/mynode. */ er = xs_watch(xs, path, "token"); if ( er == 0 ) { error("Unable to create watch"); exit(1); } /* We are notified of read availability on the watch via the * file descriptor. */ fd = xs_fileno(xs); while (1) { FD_ZERO(&set); FD_SET(fd, &set); /* Poll for data. */ if ( select(fd + 1, &set, NULL, NULL, NULL) > 0 && FD_ISSET(fd, &set)) { /* num_strings will be set to the number of elements in vec * (typically, 2 - the watched path and the token) */ vec = xs_read_watch(xs, &num_strings); if ( !vec ) { error("Unable to read watch"); continue; } if (want_verbose) printf("Path changed: %s\n", vec[XS_WATCH_PATH]); /* Prepare a transaction and do a read. */ th = xs_transaction_start(xs); buf = xs_read(xs, th, vec[XS_WATCH_PATH], &len); xs_transaction_end(xs, th, false); if (buf) { if (last_value && strcmp(buf, last_value) == 0) { if (want_verbose) printf("Value did not change\n"); continue; } if (want_verbose) printf("New value: %s\n", buf); if (program) { pid = fork(); if (pid == 0) { setenv("XENSTORE_WATCH_PATH", vec[XS_WATCH_PATH], 1); setenv("XENSTORE_WATCH_VALUE", buf, 1); for (i=0; arguments[i]; i++) { if (strcmp(arguments[i], "%v") == 0) arguments[i] = buf; else if (strcmp(arguments[i], "%p") == 0) arguments[i] = vec[XS_WATCH_PATH]; } execvp(program, arguments); error("Unable to start program"); exit(1); } else { waitpid(pid, &status, 0); } } else { if (!want_verbose) printf("%s\n", buf); } if (last_value) free(last_value); last_value = buf; } } } /* Cleanup */ close(fd); xs_daemon_close(xs); free(path); exit(0); }
int main(int argc, char *argv[]) { char *devname; tapdev_info_t *ctlinfo; int tap_pfd, store_pfd, xs_fd, ret, timeout, pfd_count, count=0; struct xs_handle *h; struct pollfd pfd[NUM_POLL_FDS]; pid_t process; char buf[128]; __init_blkif(); snprintf(buf, sizeof(buf), "BLKTAPCTRL[%d]", getpid()); openlog(buf, LOG_CONS|LOG_ODELAY, LOG_DAEMON); if (daemon(0,0)) { DPRINTF("daemon failed (%d)\n", errno); goto open_failed; } print_drivers(); init_driver_list(); init_rng(); register_new_blkif_hook(blktapctrl_new_blkif); register_new_devmap_hook(map_new_blktapctrl); register_new_unmap_hook(unmap_blktapctrl); ctlfd = blktap_interface_open(); if (ctlfd < 0) { DPRINTF("couldn't open blktap interface\n"); goto open_failed; } #ifdef MEMSHR memshr_daemon_initialize(); #endif retry: /* Set up store connection and watch. */ h = xs_daemon_open(); if (h == NULL) { DPRINTF("xs_daemon_open failed -- " "is xenstore running?\n"); if (count < MAX_ATTEMPTS) { count++; sleep(2); goto retry; } else goto open_failed; } ret = setup_probe_watch(h); if (ret != 0) { DPRINTF("Failed adding device probewatch\n"); xs_daemon_close(h); goto open_failed; } ioctl(ctlfd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_INTERPOSE ); process = getpid(); write_pidfile(process); ret = ioctl(ctlfd, BLKTAP_IOCTL_SENDPID, process ); /*Static pollhooks*/ pfd_count = 0; tap_pfd = pfd_count++; pfd[tap_pfd].fd = ctlfd; pfd[tap_pfd].events = POLLIN; store_pfd = pfd_count++; pfd[store_pfd].fd = xs_fileno(h); pfd[store_pfd].events = POLLIN; while (run) { timeout = 1000; /*Milliseconds*/ ret = poll(pfd, pfd_count, timeout); if (ret > 0) { if (pfd[store_pfd].revents) { ret = xs_fire_next_watch(h); } } } xs_daemon_close(h); ioctl(ctlfd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_PASSTHROUGH ); close(ctlfd); closelog(); return 0; open_failed: DPRINTF("Unable to start blktapctrl\n"); closelog(); return -1; }
int xenbus_get_watch_fd(void) { assert(xsh != NULL); assert(xs_watch(xsh, WATCH_NODE, "conn-watch")); return xs_fileno(xsh); }
int main(int argc, char **argv) { struct termios attr; int domid; char *sopt = "hn:"; int ch; unsigned int num = 0; int opt_ind=0; struct option lopt[] = { { "type", 1, 0, 't' }, { "num", 1, 0, 'n' }, { "help", 0, 0, 'h' }, { 0 }, }; char *dom_path = NULL, *path = NULL; int spty, xsfd; struct xs_handle *xs; char *end; console_type type = CONSOLE_INVAL; while((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) { switch(ch) { case 'h': usage(argv[0]); exit(0); break; case 'n': num = atoi(optarg); break; case 't': if (!strcmp(optarg, "serial")) type = CONSOLE_SERIAL; else if (!strcmp(optarg, "pv")) type = CONSOLE_PV; else { fprintf(stderr, "Invalid type argument\n"); fprintf(stderr, "Console types supported are: serial, pv\n"); exit(EINVAL); } break; default: fprintf(stderr, "Invalid argument\n"); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); exit(EINVAL); } } if (optind >= argc) { fprintf(stderr, "DOMID should be specified\n"); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); exit(EINVAL); } domid = strtol(argv[optind], &end, 10); if (end && *end) { fprintf(stderr, "Invalid DOMID `%s'\n", argv[optind]); fprintf(stderr, "Try `%s --help' for more information.\n", argv[0]); exit(EINVAL); } xs = xs_daemon_open(); if (xs == NULL) { err(errno, "Could not contact XenStore"); } signal(SIGTERM, sighandler); dom_path = xs_get_domain_path(xs, domid); if (dom_path == NULL) err(errno, "xs_get_domain_path()"); if (type == CONSOLE_INVAL) { xc_dominfo_t xcinfo; xc_interface *xc_handle = xc_interface_open(0,0,0); if (xc_handle == NULL) err(errno, "Could not open xc interface"); xc_domain_getinfo(xc_handle, domid, 1, &xcinfo); /* default to pv console for pv guests and serial for hvm guests */ if (xcinfo.hvm) type = CONSOLE_SERIAL; else type = CONSOLE_PV; xc_interface_close(xc_handle); } path = malloc(strlen(dom_path) + strlen("/device/console/0/tty") + 5); if (path == NULL) err(ENOMEM, "malloc"); if (type == CONSOLE_SERIAL) snprintf(path, strlen(dom_path) + strlen("/serial/0/tty") + 5, "%s/serial/%d/tty", dom_path, num); else { if (num == 0) snprintf(path, strlen(dom_path) + strlen("/console/tty") + 1, "%s/console/tty", dom_path); else snprintf(path, strlen(dom_path) + strlen("/device/console/%d/tty") + 5, "%s/device/console/%d/tty", dom_path, num); } /* FIXME consoled currently does not assume domain-0 doesn't have a console which is good when we break domain-0 up. To keep us user friendly, we'll bail out here since no data will ever show up on domain-0. */ if (domid == 0) { fprintf(stderr, "Can't specify Domain-0\n"); exit(EINVAL); } /* Set a watch on this domain's console pty */ if (!xs_watch(xs, path, "")) err(errno, "Can't set watch for console pty"); xsfd = xs_fileno(xs); /* Wait a little bit for tty to appear. There is a race condition that occurs after xend creates a domain. This code might be running before consoled has noticed the new domain and setup a pty for it. */ spty = get_pty_fd(xs, path, 5); if (spty == -1) { err(errno, "Could not read tty from store"); } init_term(spty, &attr); init_term(STDIN_FILENO, &attr); console_loop(spty, xs, path); restore_term(STDIN_FILENO, &attr); free(path); free(dom_path); return 0; }
static int console_loop(int fd, struct xs_handle *xs, char *pty_path) { int ret, xs_fd = xs_fileno(xs), max_fd; do { fd_set fds; FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); max_fd = STDIN_FILENO; FD_SET(xs_fd, &fds); if (xs_fd > max_fd) max_fd = xs_fd; if (fd != -1) FD_SET(fd, &fds); if (fd > max_fd) max_fd = fd; ret = select(max_fd + 1, &fds, NULL, NULL, NULL); if (ret == -1) { if (errno == EINTR || errno == EAGAIN) { continue; } return -1; } if (FD_ISSET(xs_fileno(xs), &fds)) { int newfd = get_pty_fd(xs, pty_path, 0); if (fd != -1) close(fd); if (newfd == -1) /* Console PTY has become invalid */ return 0; fd = newfd; continue; } if (FD_ISSET(STDIN_FILENO, &fds)) { ssize_t len; char msg[60]; len = read(STDIN_FILENO, msg, sizeof(msg)); if (len == 1 && msg[0] == ESCAPE_CHARACTER) { return 0; } if (len == 0 || len == -1) { if (len == -1 && (errno == EINTR || errno == EAGAIN)) { continue; } return -1; } if (!write_sync(fd, msg, len)) { close(fd); fd = -1; continue; } } if (fd != -1 && FD_ISSET(fd, &fds)) { ssize_t len; char msg[512]; len = read(fd, msg, sizeof(msg)); if (len == 0 || len == -1) { if (len == -1 && (errno == EINTR || errno == EAGAIN)) { continue; } close(fd); fd = -1; continue; } if (!write_sync(STDOUT_FILENO, msg, len)) { perror("write() failed"); return -1; } } } while (received_signal == 0); return 0; }
main( int argc, char **argv) { vxt_db_start_arg_t start_db_args; struct xs_handle *xs; char token; char **vec; char *tail; int ret; int parse_result; int num; int domid; int auth_dev; fd_set set; int fd; char target_uuid[MAX_VXT_UUID] = " "; int is_provision = 0; if (daemon(0, 0) < 0) { perror("daemon"); } auth_dev = open(VXT_AUTH_DEVICE_NAME, O_RDWR); if(auth_dev < 0) { printf("main: Failed to open the Vxt authorization" " database device\n"); } /* * Start the database if it hasn't already been * started */ strncpy(start_db_args.db_file_name, VXT_DB_DEFAULT_FILE_NAME, VXT_DB_NAME_MAX); ioctl(auth_dev, VXT_AUTH_DB_START, (void *)(long)&start_db_args); /* printf("The domain device %s\n", xs_domain_dev()); */ xs = xs_domain_open(); if (!xs) { perror("xs_domain_open failure"); exit(1); } ret = xs_watch(xs, "/vm", "vxtToken"); if (ret == 0) { perror("xs_watch failed\n"); exit(1); } fd = xs_fileno(xs); while (1) { FD_ZERO(&set); FD_SET(fd, &set); /* * Poll for data * printf("Poll for data, 0x%x\n", fd); */ if ((ret = select(fd+1, &set, NULL, NULL, NULL)) >= 0) { /* printf("Watch point triggered ret = 0x%x\n", ret); */ vec = xs_read_watch(xs, &num); printf("\n after read watch "); if (!vec) error(); parse_result = xsd_vm_name(vec[XS_WATCH_PATH], target_uuid); if (parse_result == 1) { char **list; char path[64]; int entry_cnt; int i; /* * get a list of all the domain ids, * then check the name of each one * to find the id for the specified domain */ list = xs_directory(xs, XBT_NULL, "/local/domain", &entry_cnt); for (i = (entry_cnt-1); i > 0; i--) { char *rec_uuid; sprintf(path, "/local/domain/%s/vm", list[i]); rec_uuid = xs_read(xs, XBT_NULL, path, NULL); if ( rec_uuid == NULL ) { continue; } if (strcmp(&(rec_uuid[4]), target_uuid) == 0) { free(rec_uuid); domid = atoi(list[i]); break; } free(rec_uuid); } free(list); if (i == 0) { free(vec); continue; } xsd_write_auth_record(auth_dev, target_uuid); /* printf("main: call vxt_auth_db on uuid = %s\n", target_uuid); */ xsd_provision_controller(xs, domid); is_provision = 1; update_vm_state(target_uuid, is_provision); } else if (parse_result == 2) { /* treating this case as deprovision */ is_provision = 0; update_vm_state(target_uuid, is_provision); } else { /* target_uuid is undefined * don't call update_vm_state */ } free(vec); } else { break; } } printf("returned from xs_watch, xenstore exited\n"); }
/** * xenStoreOpen: * @conn: pointer to the connection block * @name: URL for the target, NULL for local * @flags: combination of virDrvOpenFlag(s) * * Connects to the Xen hypervisor. * * Returns 0 or -1 in case of error. */ int xenStoreOpen(virConnectPtr conn, virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags) { xenUnifiedPrivatePtr priv = conn->privateData; virCheckFlags(VIR_CONNECT_RO, -1); if (flags & VIR_CONNECT_RO) priv->xshandle = xs_daemon_open_readonly(); else priv->xshandle = xs_daemon_open(); if (priv->xshandle == NULL) { /* * not being able to connect via the socket as an unprivileged * user is rather normal, this should fallback to the proxy (or * remote) mechanism. */ if (xenHavePrivilege()) { virReportError(VIR_ERR_NO_XEN, "%s", _("failed to connect to Xen Store")); } return -1; } /* Init activeDomainList */ if (VIR_ALLOC(priv->activeDomainList) < 0) return -1; /* Init watch list before filling in domInfoList, so we can know if it is the first time through when the callback fires */ if (VIR_ALLOC(priv->xsWatchList) < 0) return -1; /* This will get called once at start */ if (xenStoreAddWatch(conn, "@releaseDomain", "releaseDomain", xenStoreDomainReleased, priv) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("adding watch @releaseDomain")); return -1; } /* The initial call of this will fill domInfoList */ if (xenStoreAddWatch(conn, "@introduceDomain", "introduceDomain", xenStoreDomainIntroduced, priv) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("adding watch @introduceDomain")); return -1; } /* Add an event handle */ if ((priv->xsWatch = virEventAddHandle(xs_fileno(priv->xshandle), VIR_EVENT_HANDLE_READABLE, xenStoreWatchEvent, conn, NULL)) < 0) VIR_DEBUG("Failed to add event handle, disabling events"); return 0; }