1 /*
2  * Copyright 2009-2017 Citrix Ltd and other contributors
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation; version 2.1 only. with the special
7  * exception on linking described in file LICENSE.
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 Lesser General Public License for more details.
13  */
14 
15 #include "libxl_osdeps.h"
16 
17 #include "libxl_internal.h"
18 
libxl_ctx_alloc(libxl_ctx ** pctx,int version,unsigned flags,xentoollog_logger * lg)19 int libxl_ctx_alloc(libxl_ctx **pctx, int version,
20                     unsigned flags, xentoollog_logger * lg)
21 {
22     libxl_ctx *ctx = NULL;
23     libxl__gc gc_buf, *gc = NULL;
24     int rc;
25 
26     if (version != LIBXL_VERSION) { rc = ERROR_VERSION; goto out; }
27 
28     ctx = malloc(sizeof(*ctx));
29     if (!ctx) {
30         xtl_log(lg, XTL_ERROR, errno, "libxl",
31                 "%s:%d:%s: Failed to allocate context\n",
32                 __FILE__, __LINE__, __func__);
33         rc = ERROR_NOMEM; goto out;
34     }
35 
36     memset(ctx, 0, sizeof(libxl_ctx));
37     ctx->lg = lg;
38 
39     /* First initialise pointers etc. (cannot fail) */
40 
41     ctx->nogc_gc.alloc_maxsize = -1;
42     ctx->nogc_gc.owner = ctx;
43 
44     XEN_TAILQ_INIT(&ctx->occurred);
45 
46     ctx->osevent_hooks = 0;
47 
48     ctx->poller_app = 0;
49     XEN_LIST_INIT(&ctx->pollers_event);
50     XEN_LIST_INIT(&ctx->pollers_idle);
51     XEN_LIST_INIT(&ctx->pollers_active);
52 
53     XEN_LIST_INIT(&ctx->efds);
54     XEN_TAILQ_INIT(&ctx->etimes);
55 
56     ctx->watch_slots = 0;
57     XEN_SLIST_INIT(&ctx->watch_freeslots);
58     libxl__ev_fd_init(&ctx->watch_efd);
59 
60     ctx->xce = 0;
61     XEN_LIST_INIT(&ctx->evtchns_waiting);
62     libxl__ev_fd_init(&ctx->evtchn_efd);
63 
64     XEN_LIST_INIT(&ctx->aos_inprogress);
65 
66     XEN_TAILQ_INIT(&ctx->death_list);
67     libxl__ev_xswatch_init(&ctx->death_watch);
68 
69     ctx->childproc_hooks = &libxl__childproc_default_hooks;
70     ctx->childproc_user = 0;
71 
72     ctx->sigchld_selfpipe[0] = -1;
73     ctx->sigchld_selfpipe[1] = -1;
74     libxl__ev_fd_init(&ctx->sigchld_selfpipe_efd);
75 
76     /* The mutex is special because we can't idempotently destroy it */
77 
78     if (libxl__init_recursive_mutex(ctx, &ctx->lock) < 0) {
79         LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Failed to initialize mutex");
80         free(ctx);
81         ctx = 0;
82         rc = ERROR_FAIL;
83         goto out;
84     }
85 
86     /* Now ctx is safe for ctx_free; failures simply set rc and "goto out" */
87     LIBXL_INIT_GC(gc_buf,ctx);
88     gc = &gc_buf;
89     /* Now gc is useable */
90 
91     rc = libxl__atfork_init(ctx);
92     if (rc) goto out;
93 
94     ctx->poller_app = libxl__poller_get(gc);
95     if (!ctx->poller_app) {
96         rc = ERROR_FAIL;
97         goto out;
98     }
99 
100     ctx->xch = xc_interface_open(lg,lg,0);
101     if (!ctx->xch) {
102         LOGEV(ERROR, errno, "cannot open libxc handle");
103         rc = ERROR_FAIL; goto out;
104     }
105 
106     ctx->xsh = xs_open(0);
107     if (!ctx->xsh) {
108         LOGEV(ERROR, errno, "cannot connect to xenstore");
109         rc = ERROR_FAIL; goto out;
110     }
111 
112     *pctx = ctx;
113     return 0;
114 
115  out:
116     if (gc) libxl__free_all(gc);
117     libxl_ctx_free(ctx);
118     *pctx = NULL;
119     return rc;
120 }
121 
free_disable_deaths(libxl__gc * gc,struct libxl__evgen_domain_death_list * l)122 static void free_disable_deaths(libxl__gc *gc,
123                                 struct libxl__evgen_domain_death_list *l) {
124     libxl_evgen_domain_death *death;
125     while ((death = XEN_TAILQ_FIRST(l)))
126         libxl__evdisable_domain_death(gc, death);
127 }
128 
discard_events(struct libxl__event_list * l)129 static void discard_events(struct libxl__event_list *l) {
130     /* doesn't bother unlinking from the list, so l is corrupt on return */
131     libxl_event *ev, *next;
132     XEN_TAILQ_FOREACH_SAFE(ev, l, link, next)
133         libxl_event_free(0, ev);
134 }
135 
libxl_ctx_free(libxl_ctx * ctx)136 int libxl_ctx_free(libxl_ctx *ctx)
137 {
138     if (!ctx) return 0;
139 
140     int i;
141     GC_INIT(ctx);
142 
143     CTX_LOCK;
144     assert(!ctx->osevent_in_hook);
145     CTX->osevent_in_hook += 1000; /* make violations easier to debug */
146 
147     /* Deregister all libxl__ev_KINDs: */
148 
149     free_disable_deaths(gc, &CTX->death_list);
150     free_disable_deaths(gc, &CTX->death_reported);
151 
152     libxl_evgen_disk_eject *eject;
153     while ((eject = XEN_LIST_FIRST(&CTX->disk_eject_evgens)))
154         libxl__evdisable_disk_eject(gc, eject);
155 
156     libxl_childproc_setmode(CTX,0,0);
157     for (i = 0; i < ctx->watch_nslots; i++)
158         assert(!libxl__watch_slot_contents(gc, i));
159     assert(!libxl__ev_fd_isregistered(&ctx->watch_efd));
160     assert(!libxl__ev_fd_isregistered(&ctx->evtchn_efd));
161     assert(!libxl__ev_fd_isregistered(&ctx->sigchld_selfpipe_efd));
162 
163     /* Now there should be no more events requested from the application: */
164 
165     assert(XEN_LIST_EMPTY(&ctx->efds));
166     assert(XEN_TAILQ_EMPTY(&ctx->etimes));
167     assert(XEN_LIST_EMPTY(&ctx->evtchns_waiting));
168     assert(XEN_LIST_EMPTY(&ctx->aos_inprogress));
169 
170     if (ctx->xch) xc_interface_close(ctx->xch);
171     libxl_version_info_dispose(&ctx->version_info);
172     if (ctx->xsh) xs_close(ctx->xsh);
173     if (ctx->xce) xenevtchn_close(ctx->xce);
174 
175     libxl__poller_put(ctx, ctx->poller_app);
176     ctx->poller_app = NULL;
177     assert(XEN_LIST_EMPTY(&ctx->pollers_event));
178     assert(XEN_LIST_EMPTY(&ctx->pollers_active));
179     libxl__poller *poller, *poller_tmp;
180     XEN_LIST_FOREACH_SAFE(poller, &ctx->pollers_idle, entry, poller_tmp) {
181         libxl__poller_dispose(poller);
182         free(poller);
183     }
184 
185     free(ctx->watch_slots);
186 
187     discard_events(&ctx->occurred);
188 
189     /* If we have outstanding children, then the application inherits
190      * them; we wish the application good luck with understanding
191      * this if and when it reaps them. */
192     libxl__sigchld_notneeded(gc);
193     libxl__pipe_close(ctx->sigchld_selfpipe);
194 
195     CTX_UNLOCK;
196     pthread_mutex_destroy(&ctx->lock);
197 
198     GC_FREE;
199     free(ctx);
200     return 0;
201 }
202 
libxl_string_list_dispose(libxl_string_list * psl)203 void libxl_string_list_dispose(libxl_string_list *psl)
204 {
205     int i;
206     libxl_string_list sl = *psl;
207 
208     if (!sl)
209         return;
210 
211     for (i = 0; sl[i] != NULL; i++) {
212         free(sl[i]);
213         sl[i] = NULL;
214     }
215     free(sl);
216     *psl = NULL;
217 }
218 
libxl_string_list_copy(libxl_ctx * ctx,libxl_string_list * dst,const libxl_string_list * src)219 void libxl_string_list_copy(libxl_ctx *ctx,
220                             libxl_string_list *dst,
221                             const libxl_string_list *src)
222 {
223     GC_INIT(ctx);
224     int i, len;
225 
226     if (!*src) {
227         *dst = NULL;
228         goto out;
229     }
230 
231     len = libxl_string_list_length(src);
232     /* one extra slot for sentinel */
233     *dst = libxl__calloc(NOGC, len + 1, sizeof(char *));
234 
235     for (i = 0; i < len; i++)
236         (*dst)[i] = libxl__strdup(NOGC, (*src)[i]);
237 
238 out:
239     GC_FREE;
240 }
241 
libxl_string_list_length(const libxl_string_list * psl)242 int libxl_string_list_length(const libxl_string_list *psl)
243 {
244     int i = 0;
245 
246     if (*psl)
247         while ((*psl)[i])
248             i++;
249 
250     return i;
251 }
252 
libxl_key_value_list_length(const libxl_key_value_list * pkvl)253 int libxl_key_value_list_length(const libxl_key_value_list *pkvl)
254 {
255     int i = 0;
256     libxl_key_value_list kvl = *pkvl;
257 
258     if (kvl) {
259         while (kvl[2 * i]) /* Only checks keys */
260             i++;
261     }
262 
263     return i;
264 }
265 
libxl_key_value_list_dispose(libxl_key_value_list * pkvl)266 void libxl_key_value_list_dispose(libxl_key_value_list *pkvl)
267 {
268     int i;
269     libxl_key_value_list kvl = *pkvl;
270 
271     if (!kvl)
272         return;
273 
274     for (i = 0; kvl[i] != NULL; i += 2) {
275         free(kvl[i]);
276         kvl[i] = NULL;
277         if (kvl[i + 1]) {
278             free(kvl[i + 1]);
279             kvl[i+1] = NULL;
280         }
281     }
282     free(kvl);
283     *pkvl = NULL;
284 }
285 
libxl_key_value_list_copy(libxl_ctx * ctx,libxl_key_value_list * dst,const libxl_key_value_list * src)286 void libxl_key_value_list_copy(libxl_ctx *ctx,
287                                libxl_key_value_list *dst,
288                                const libxl_key_value_list *src)
289 {
290     GC_INIT(ctx);
291     int i, len;
292 
293     if (*src == NULL) {
294         *dst = NULL;
295         goto out;
296     }
297 
298     len = libxl_key_value_list_length(src);
299     /* one extra slot for sentinel */
300     *dst = libxl__calloc(NOGC, len * 2 + 1, sizeof(char *));
301 
302     for (i = 0; i < len * 2; i += 2) {
303         (*dst)[i] = libxl__strdup(NOGC, (*src)[i]);
304         if ((*src)[i+1])
305             (*dst)[i+1] = libxl__strdup(NOGC, (*src)[i+1]);
306         else
307             (*dst)[i+1] = NULL;
308     }
309 
310 out:
311     GC_FREE;
312 }
313 
libxl_defbool_set(libxl_defbool * db,bool b)314 void libxl_defbool_set(libxl_defbool *db, bool b)
315 {
316     db->val = b ? LIBXL__DEFBOOL_TRUE : LIBXL__DEFBOOL_FALSE;
317 }
318 
libxl_defbool_unset(libxl_defbool * db)319 void libxl_defbool_unset(libxl_defbool *db)
320 {
321     db->val = LIBXL__DEFBOOL_DEFAULT;
322 }
323 
libxl_defbool_is_default(libxl_defbool db)324 bool libxl_defbool_is_default(libxl_defbool db)
325 {
326     return !db.val;
327 }
328 
libxl_defbool_setdefault(libxl_defbool * db,bool b)329 void libxl_defbool_setdefault(libxl_defbool *db, bool b)
330 {
331     if (libxl_defbool_is_default(*db))
332         libxl_defbool_set(db, b);
333 }
334 
libxl_defbool_val(libxl_defbool db)335 bool libxl_defbool_val(libxl_defbool db)
336 {
337     assert(!libxl_defbool_is_default(db));
338     return db.val > 0;
339 }
340 
libxl_defbool_to_string(libxl_defbool b)341 const char *libxl_defbool_to_string(libxl_defbool b)
342 {
343     if (b.val < 0)
344         return LIBXL__DEFBOOL_STR_FALSE;
345     else if (b.val > 0)
346         return LIBXL__DEFBOOL_STR_TRUE;
347     else
348         return LIBXL__DEFBOOL_STR_DEFAULT;
349 }
350 
351 /******************************************************************************/
libxl_get_physinfo(libxl_ctx * ctx,libxl_physinfo * physinfo)352 int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
353 {
354     xc_physinfo_t xcphysinfo;
355     int rc;
356     long l;
357     GC_INIT(ctx);
358 
359     rc = xc_physinfo(ctx->xch, &xcphysinfo);
360     if (rc != 0) {
361         LOGE(ERROR, "getting physinfo");
362         GC_FREE;
363         return ERROR_FAIL;
364     }
365     physinfo->threads_per_core = xcphysinfo.threads_per_core;
366     physinfo->cores_per_socket = xcphysinfo.cores_per_socket;
367     physinfo->max_cpu_id = xcphysinfo.max_cpu_id;
368     physinfo->nr_cpus = xcphysinfo.nr_cpus;
369     physinfo->cpu_khz = xcphysinfo.cpu_khz;
370     physinfo->total_pages = xcphysinfo.total_pages;
371     physinfo->free_pages = xcphysinfo.free_pages;
372     physinfo->scrub_pages = xcphysinfo.scrub_pages;
373     physinfo->outstanding_pages = xcphysinfo.outstanding_pages;
374     physinfo->max_possible_mfn = xcphysinfo.max_mfn;
375     l = xc_sharing_freed_pages(ctx->xch);
376     if (l < 0 && errno == ENOSYS) {
377         l = 0;
378     } else if (l < 0) {
379         LOGEV(ERROR, l, "getting sharing freed pages");
380         GC_FREE;
381         return ERROR_FAIL;
382     }
383     physinfo->sharing_freed_pages = l;
384     l = xc_sharing_used_frames(ctx->xch);
385     if (l < 0 && errno == ENOSYS) {
386         l = 0;
387     } else if (l < 0) {
388         LOGEV(ERROR, l, "getting sharing used frames");
389         GC_FREE;
390         return ERROR_FAIL;
391     }
392     physinfo->sharing_used_frames = l;
393     physinfo->nr_nodes = xcphysinfo.nr_nodes;
394     memcpy(physinfo->hw_cap,xcphysinfo.hw_cap, sizeof(physinfo->hw_cap));
395 
396     physinfo->cap_hvm = !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_hvm);
397     physinfo->cap_pv = !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_pv);
398     physinfo->cap_hvm_directio =
399         !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_directio);
400     physinfo->cap_hap = !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_hap);
401     physinfo->cap_shadow =
402         !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_shadow);
403     physinfo->cap_iommu_hap_pt_share =
404         !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_iommu_hap_pt_share);
405     physinfo->cap_vmtrace =
406         !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_vmtrace);
407     physinfo->cap_vpmu = !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_vpmu);
408     physinfo->cap_gnttab_v1 =
409         !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_gnttab_v1);
410     physinfo->cap_gnttab_v2 =
411         !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_gnttab_v2);
412     physinfo->arch_capabilities = xcphysinfo.arch_capabilities;
413 
414     GC_FREE;
415     return 0;
416 }
417 
libxl_get_cpu_topology(libxl_ctx * ctx,int * nb_cpu_out)418 libxl_cputopology *libxl_get_cpu_topology(libxl_ctx *ctx, int *nb_cpu_out)
419 {
420     GC_INIT(ctx);
421     xc_cputopo_t *cputopo;
422     libxl_cputopology *ret = NULL;
423     int i;
424     unsigned num_cpus = 0;
425 
426     /* Setting buffer to NULL makes the call return number of CPUs */
427     if (xc_cputopoinfo(ctx->xch, &num_cpus, NULL))
428     {
429         LOGE(ERROR, "Unable to determine number of CPUS");
430         goto out;
431     }
432 
433     cputopo = libxl__zalloc(gc, sizeof(*cputopo) * num_cpus);
434 
435     if (xc_cputopoinfo(ctx->xch, &num_cpus, cputopo)) {
436         LOGE(ERROR, "CPU topology info hypercall failed");
437         goto out;
438     }
439 
440     ret = libxl__zalloc(NOGC, sizeof(libxl_cputopology) * num_cpus);
441 
442     for (i = 0; i < num_cpus; i++) {
443 #define V(map, i, invalid) ( cputopo[i].map == invalid) ? \
444    LIBXL_CPUTOPOLOGY_INVALID_ENTRY : cputopo[i].map
445         ret[i].core = V(core, i, XEN_INVALID_CORE_ID);
446         ret[i].socket = V(socket, i, XEN_INVALID_SOCKET_ID);
447         ret[i].node = V(node, i, XEN_INVALID_NODE_ID);
448 #undef V
449     }
450 
451     *nb_cpu_out = num_cpus;
452 
453  out:
454     GC_FREE;
455     return ret;
456 }
457 
libxl_get_pci_topology(libxl_ctx * ctx,int * num_devs)458 libxl_pcitopology *libxl_get_pci_topology(libxl_ctx *ctx, int *num_devs)
459 {
460     GC_INIT(ctx);
461     physdev_pci_device_t *devs;
462     uint32_t *nodes;
463     libxl_pcitopology *ret = NULL;
464     int i, rc;
465 
466     *num_devs = libxl__pci_numdevs(gc);
467     if (*num_devs < 0) {
468         LOG(ERROR, "Unable to determine number of PCI devices, rc %d",
469             *num_devs);
470         goto out;
471     }
472 
473     devs = libxl__zalloc(gc, sizeof(*devs) * *num_devs);
474     nodes = libxl__zalloc(gc, sizeof(*nodes) * *num_devs);
475 
476     rc = libxl__pci_topology_init(gc, devs, *num_devs);
477     if (rc) {
478         LOG(ERROR, "Cannot initialize PCI hypercall structure, rc %d", rc);
479         goto out;
480     }
481 
482     if (xc_pcitopoinfo(ctx->xch, *num_devs, devs, nodes) != 0) {
483         LOGE(ERROR, "PCI topology info hypercall failed");
484         goto out;
485     }
486 
487     ret = libxl__zalloc(NOGC, sizeof(libxl_pcitopology) * *num_devs);
488 
489     for (i = 0; i < *num_devs; i++) {
490         ret[i].seg = devs[i].seg;
491         ret[i].bus = devs[i].bus;
492         ret[i].devfn = devs[i].devfn;
493         ret[i].node = ((nodes[i] == XEN_INVALID_NODE_ID) ||
494                        (nodes[i] == XEN_INVALID_DEV)) ?
495             LIBXL_PCITOPOLOGY_INVALID_ENTRY : nodes[i];
496     }
497 
498  out:
499     GC_FREE;
500     return ret;
501 }
502 
libxl_get_numainfo(libxl_ctx * ctx,int * nr)503 libxl_numainfo *libxl_get_numainfo(libxl_ctx *ctx, int *nr)
504 {
505     GC_INIT(ctx);
506     xc_meminfo_t *meminfo;
507     uint32_t *distance;
508     libxl_numainfo *ret = NULL;
509     int i, j;
510     unsigned num_nodes = 0;
511 
512     if (xc_numainfo(ctx->xch, &num_nodes, NULL, NULL)) {
513         LOGE(ERROR, "Unable to determine number of nodes");
514         goto out;
515     }
516 
517     meminfo = libxl__zalloc(gc, sizeof(*meminfo) * num_nodes);
518     distance = libxl__zalloc(gc, sizeof(*distance) * num_nodes * num_nodes);
519 
520     if (xc_numainfo(ctx->xch, &num_nodes, meminfo, distance)) {
521         LOGE(ERROR, "getting numainfo");
522         goto out;
523     }
524 
525     *nr = num_nodes;
526 
527     ret = libxl__zalloc(NOGC, sizeof(libxl_numainfo) * num_nodes);
528     for (i = 0; i < num_nodes; i++)
529         ret[i].dists = libxl__calloc(NOGC, num_nodes, sizeof(*distance));
530 
531     for (i = 0; i < num_nodes; i++) {
532 #define V(val, invalid) (val == invalid) ? \
533        LIBXL_NUMAINFO_INVALID_ENTRY : val
534         ret[i].size = V(meminfo[i].memsize, XEN_INVALID_MEM_SZ);
535         ret[i].free = V(meminfo[i].memfree, XEN_INVALID_MEM_SZ);
536         ret[i].num_dists = num_nodes;
537         for (j = 0; j < ret[i].num_dists; j++) {
538             unsigned idx = i * num_nodes + j;
539             ret[i].dists[j] = V(distance[idx], XEN_INVALID_NODE_DIST);
540         }
541 #undef V
542     }
543 
544  out:
545     GC_FREE;
546     return ret;
547 }
548 
libxl__xc_version_wrap(libxl__gc * gc,libxl_version_info * info,xen_build_id_t * build)549 static int libxl__xc_version_wrap(libxl__gc *gc, libxl_version_info *info,
550                                   xen_build_id_t *build)
551 {
552     int r;
553 
554     r = xc_version(CTX->xch, XENVER_build_id, build);
555     switch (r) {
556     case -EPERM:
557     case -ENODATA:
558     case 0:
559         info->build_id = libxl__strdup(NOGC, "");
560         break;
561 
562     case -ENOBUFS:
563         break;
564 
565     default:
566         if (r > 0) {
567             unsigned int i;
568 
569             info->build_id = libxl__zalloc(NOGC, (r * 2) + 1);
570 
571             for (i = 0; i < r ; i++)
572                 snprintf(&info->build_id[i * 2], 3, "%02hhx", build->buf[i]);
573 
574             r = 0;
575         }
576         break;
577     }
578     return r;
579 }
580 
libxl_get_version_info(libxl_ctx * ctx)581 const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx)
582 {
583     GC_INIT(ctx);
584     union {
585         xen_extraversion_t xen_extra;
586         xen_compile_info_t xen_cc;
587         xen_changeset_info_t xen_chgset;
588         xen_capabilities_info_t xen_caps;
589         xen_platform_parameters_t p_parms;
590         xen_commandline_t xen_commandline;
591         xen_build_id_t build_id;
592     } u;
593     long xen_version;
594     int r;
595     libxl_version_info *info = &ctx->version_info;
596 
597     if (info->xen_version_extra != NULL)
598         goto out;
599 
600     xen_version = xc_version(ctx->xch, XENVER_version, NULL);
601     info->xen_version_major = xen_version >> 16;
602     info->xen_version_minor = xen_version & 0xFF;
603 
604     xc_version(ctx->xch, XENVER_extraversion, &u.xen_extra);
605     info->xen_version_extra = libxl__strdup(NOGC, u.xen_extra);
606 
607     xc_version(ctx->xch, XENVER_compile_info, &u.xen_cc);
608     info->compiler = libxl__strdup(NOGC, u.xen_cc.compiler);
609     info->compile_by = libxl__strdup(NOGC, u.xen_cc.compile_by);
610     info->compile_domain = libxl__strdup(NOGC, u.xen_cc.compile_domain);
611     info->compile_date = libxl__strdup(NOGC, u.xen_cc.compile_date);
612 
613     xc_version(ctx->xch, XENVER_capabilities, &u.xen_caps);
614     info->capabilities = libxl__strdup(NOGC, u.xen_caps);
615 
616     xc_version(ctx->xch, XENVER_changeset, &u.xen_chgset);
617     info->changeset = libxl__strdup(NOGC, u.xen_chgset);
618 
619     xc_version(ctx->xch, XENVER_platform_parameters, &u.p_parms);
620     info->virt_start = u.p_parms.virt_start;
621 
622     info->pagesize = xc_version(ctx->xch, XENVER_pagesize, NULL);
623 
624     xc_version(ctx->xch, XENVER_commandline, &u.xen_commandline);
625     info->commandline = libxl__strdup(NOGC, u.xen_commandline);
626 
627     u.build_id.len = sizeof(u) - sizeof(u.build_id);
628     r = libxl__xc_version_wrap(gc, info, &u.build_id);
629     if (r == -ENOBUFS) {
630             xen_build_id_t *build_id;
631 
632             build_id = libxl__zalloc(gc, info->pagesize);
633             build_id->len = info->pagesize - sizeof(*build_id);
634             r = libxl__xc_version_wrap(gc, info, build_id);
635             if (r) LOGEV(ERROR, r, "getting build_id");
636     }
637  out:
638     GC_FREE;
639     return info;
640 }
641 
libxl_send_sysrq(libxl_ctx * ctx,uint32_t domid,char sysrq)642 int libxl_send_sysrq(libxl_ctx *ctx, uint32_t domid, char sysrq)
643 {
644     GC_INIT(ctx);
645     char *dompath = libxl__xs_get_dompath(gc, domid);
646 
647     libxl__xs_printf(gc, XBT_NULL, GCSPRINTF("%s/control/sysrq", dompath),
648                      "%c", sysrq);
649 
650     GC_FREE;
651     return 0;
652 }
653 
libxl_send_debug_keys(libxl_ctx * ctx,char * keys)654 int libxl_send_debug_keys(libxl_ctx *ctx, char *keys)
655 {
656     int ret;
657     GC_INIT(ctx);
658     ret = xc_send_debug_keys(ctx->xch, keys);
659     if ( ret < 0 ) {
660         LOGE(ERROR, "sending debug keys");
661         GC_FREE;
662         return ERROR_FAIL;
663     }
664     GC_FREE;
665     return 0;
666 }
667 
libxl_set_parameters(libxl_ctx * ctx,char * params)668 int libxl_set_parameters(libxl_ctx *ctx, char *params)
669 {
670     int ret;
671     GC_INIT(ctx);
672     char *par, *val, *end, *path;
673     xenhypfs_handle *hypfs;
674 
675     hypfs = xenhypfs_open(ctx->lg, 0);
676     if (!hypfs) {
677         LOGE(ERROR, "opening Xen hypfs");
678         ret = ERROR_FAIL;
679         goto out;
680     }
681 
682     while (isblank(*params))
683         params++;
684 
685     for (par = params; *par; par = end) {
686         end = strchr(par, ' ');
687         if (!end)
688             end = par + strlen(par);
689 
690         val = strchr(par, '=');
691         if (val > end)
692             val = NULL;
693         if (!val && !strncmp(par, "no", 2)) {
694             path = libxl__sprintf(gc, "/params/%s", par + 2);
695             path[end - par - 2 + 8] = 0;
696             val = "no";
697             par += 2;
698         } else {
699             path = libxl__sprintf(gc, "/params/%s", par);
700             path[val - par + 8] = 0;
701             val = libxl__strndup(gc, val + 1, end - val - 1);
702         }
703 
704 	LOG(DEBUG, "setting node \"%s\" to value \"%s\"", path, val);
705         ret = xenhypfs_write(hypfs, path, val);
706         if (ret < 0) {
707             LOGE(ERROR, "setting parameters");
708             ret = ERROR_FAIL;
709             goto out;
710         }
711 
712         while (isblank(*end))
713             end++;
714     }
715 
716     ret = 0;
717 
718 out:
719     xenhypfs_close(hypfs);
720     GC_FREE;
721     return ret;
722 }
723 
fd_set_flags(libxl_ctx * ctx,int fd,int fcntlgetop,int fcntlsetop,const char * fl,int flagmask,int set_p)724 static int fd_set_flags(libxl_ctx *ctx, int fd,
725                         int fcntlgetop, int fcntlsetop, const char *fl,
726                         int flagmask, int set_p)
727 {
728     int flags, r;
729     GC_INIT(ctx);
730 
731     flags = fcntl(fd, fcntlgetop);
732     if (flags == -1) {
733         LOGE(ERROR, "fcntl(,F_GET%s) failed", fl);
734         GC_FREE;
735         return ERROR_FAIL;
736     }
737 
738     if (set_p)
739         flags |= flagmask;
740     else
741         flags &= ~flagmask;
742 
743     r = fcntl(fd, fcntlsetop, flags);
744     if (r == -1) {
745         LOGE(ERROR, "fcntl(,F_SET%s) failed", fl);
746         GC_FREE;
747         return ERROR_FAIL;
748     }
749 
750     GC_FREE;
751     return 0;
752 }
753 
libxl_fd_set_cloexec(libxl_ctx * ctx,int fd,int cloexec)754 int libxl_fd_set_cloexec(libxl_ctx *ctx, int fd, int cloexec)
755   { return fd_set_flags(ctx,fd, F_GETFD,F_SETFD,"FD", FD_CLOEXEC, cloexec); }
756 
libxl_fd_set_nonblock(libxl_ctx * ctx,int fd,int nonblock)757 int libxl_fd_set_nonblock(libxl_ctx *ctx, int fd, int nonblock)
758   { return fd_set_flags(ctx,fd, F_GETFL,F_SETFL,"FL", O_NONBLOCK, nonblock); }
759 
libxl__fd_flags_modify_save(libxl__gc * gc,int fd,int mask,int val,int * r_oldflags)760 int libxl__fd_flags_modify_save(libxl__gc *gc, int fd,
761                                 int mask, int val, int *r_oldflags)
762 {
763     int rc, ret, fdfl;
764 
765     fdfl = fcntl(fd, F_GETFL);
766     if (fdfl < 0) {
767         LOGE(ERROR, "failed to fcntl.F_GETFL for fd %d", fd);
768         rc = ERROR_FAIL;
769         goto out_err;
770     }
771 
772     LOG(DEBUG, "fnctl F_GETFL flags for fd %d are 0x%x", fd, fdfl);
773 
774     if (r_oldflags)
775         *r_oldflags = fdfl;
776 
777     fdfl &= mask;
778     fdfl |= val;
779 
780     LOG(DEBUG, "fnctl F_SETFL of fd %d to 0x%x", fd, fdfl);
781 
782     ret = fcntl(fd, F_SETFL, fdfl);
783     if (ret < 0) {
784         LOGE(ERROR, "failed to fcntl.F_SETFL for fd %d", fd);
785         rc = ERROR_FAIL;
786         goto out_err;
787     }
788 
789     rc = 0;
790 
791 out_err:
792     return rc;
793 }
794 
libxl__fd_flags_restore(libxl__gc * gc,int fd,int fdfl)795 int libxl__fd_flags_restore(libxl__gc *gc, int fd, int fdfl)
796 {
797     int ret, rc;
798 
799     LOG(DEBUG, "fnctl F_SETFL of fd %d to 0x%x", fd, fdfl);
800 
801     ret = fcntl(fd, F_SETFL, fdfl);
802     if (ret < 0) {
803         LOGE(ERROR, "failed to fcntl.F_SETFL for fd %d", fd);
804         rc = ERROR_FAIL;
805         goto out_err;
806     }
807 
808     rc = 0;
809 
810 out_err:
811     return rc;
812 
813 }
814 
libxl_hwcap_copy(libxl_ctx * ctx,libxl_hwcap * dst,const libxl_hwcap * src)815 void libxl_hwcap_copy(libxl_ctx *ctx,libxl_hwcap *dst, const libxl_hwcap *src)
816 {
817     int i;
818 
819     for (i = 0; i < 8; i++)
820         (*dst)[i] = (*src)[i];
821 }
822 
libxl_mac_copy(libxl_ctx * ctx,libxl_mac * dst,const libxl_mac * src)823 void libxl_mac_copy(libxl_ctx *ctx, libxl_mac *dst, const libxl_mac *src)
824 {
825     int i;
826 
827     for (i = 0; i < 6; i++)
828         (*dst)[i] = (*src)[i];
829 }
830 
831 /*
832  * Local variables:
833  * mode: C
834  * c-basic-offset: 4
835  * indent-tabs-mode: nil
836  * End:
837  */
838