debuggers.hg

view tools/libxl/libxl_dom.c @ 22624:60782cefa154

libxc: convert evtchn interfaces to use an opaque handle type

This makes the interface consistent with the changes made to the main
interface in 21483:779c0ef9682c.

Also fix some references to "struct xc_interface" which should have
been simply "xc_interface" in tools/xenpaging, and update QEMU_TAG to
pull in the corresponding qemu change.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Ian Campbell <ian.campbell@citrix.com>
date Thu Dec 23 15:25:57 2010 +0000 (2010-12-23)
parents ab785e37499c
children 4fea7664a6fb
line source
1 /*
2 * Copyright (C) 2009 Citrix Ltd.
3 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published
7 * by the Free Software Foundation; version 2.1 only. with the special
8 * exception on linking described in file LICENSE.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 */
16 #include "libxl_osdeps.h"
18 #include <stdio.h>
19 #include <assert.h>
20 #include <glob.h>
21 #include <inttypes.h>
22 #include <string.h>
23 #include <sys/mman.h>
24 #include <sys/time.h> /* for struct timeval */
25 #include <sys/stat.h> /* for stat */
26 #include <unistd.h> /* for sleep(2) */
28 #include <xenctrl.h>
29 #include <xc_dom.h>
30 #include <xenguest.h>
31 #include <fcntl.h>
33 #include <xen/hvm/hvm_info_table.h>
35 #include "libxl.h"
36 #include "libxl_internal.h"
38 int libxl__domain_is_hvm(libxl_ctx *ctx, uint32_t domid)
39 {
40 xc_domaininfo_t info;
41 int ret;
43 ret = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
44 if (ret != 1)
45 return -1;
46 if (info.domain != domid)
47 return -1;
48 return !!(info.flags & XEN_DOMINF_hvm_guest);
49 }
51 int libxl__domain_shutdown_reason(libxl_ctx *ctx, uint32_t domid)
52 {
53 xc_domaininfo_t info;
54 int ret;
56 ret = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
57 if (ret != 1)
58 return -1;
59 if (info.domain != domid)
60 return -1;
61 if (!(info.flags & XEN_DOMINF_shutdown))
62 return -1;
64 return (info.flags >> XEN_DOMINF_shutdownshift) & XEN_DOMINF_shutdownmask;
65 }
67 int libxl__build_pre(libxl_ctx *ctx, uint32_t domid,
68 libxl_domain_build_info *info, libxl_domain_build_state *state)
69 {
70 xc_domain_max_vcpus(ctx->xch, domid, info->max_vcpus);
71 xc_domain_setmaxmem(ctx->xch, domid, info->target_memkb + LIBXL_MAXMEM_CONSTANT);
72 xc_domain_set_memmap_limit(ctx->xch, domid,
73 (info->hvm) ? info->max_memkb :
74 (info->max_memkb + info->u.pv.slack_memkb));
75 xc_domain_set_tsc_info(ctx->xch, domid, info->tsc_mode, 0, 0, 0);
76 if ( info->disable_migrate )
77 xc_domain_disable_migrate(ctx->xch, domid);
79 if (info->hvm) {
80 unsigned long shadow;
81 shadow = (info->shadow_memkb + 1023) / 1024;
82 xc_shadow_control(ctx->xch, domid, XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION, NULL, 0, &shadow, 0, NULL);
83 }
85 state->store_port = xc_evtchn_alloc_unbound(ctx->xch, domid, 0);
86 state->console_port = xc_evtchn_alloc_unbound(ctx->xch, domid, 0);
87 return 0;
88 }
90 int libxl__build_post(libxl_ctx *ctx, uint32_t domid,
91 libxl_domain_build_info *info, libxl_domain_build_state *state,
92 char **vms_ents, char **local_ents)
93 {
94 libxl__gc gc = LIBXL_INIT_GC(ctx);
95 char *dom_path, *vm_path;
96 xs_transaction_t t;
97 char **ents;
98 int i;
100 libxl_cpuid_apply_policy(ctx, domid);
101 if (info->cpuid != NULL)
102 libxl_cpuid_set(ctx, domid, info->cpuid);
104 ents = libxl__calloc(&gc, 12 + (info->max_vcpus * 2) + 2, sizeof(char *));
105 ents[0] = "memory/static-max";
106 ents[1] = libxl__sprintf(&gc, "%d", info->max_memkb);
107 ents[2] = "memory/target";
108 ents[3] = libxl__sprintf(&gc, "%d", info->target_memkb - info->video_memkb);
109 ents[4] = "memory/videoram";
110 ents[5] = libxl__sprintf(&gc, "%d", info->video_memkb);
111 ents[6] = "domid";
112 ents[7] = libxl__sprintf(&gc, "%d", domid);
113 ents[8] = "store/port";
114 ents[9] = libxl__sprintf(&gc, "%"PRIu32, state->store_port);
115 ents[10] = "store/ring-ref";
116 ents[11] = libxl__sprintf(&gc, "%lu", state->store_mfn);
117 for (i = 0; i < info->max_vcpus; i++) {
118 ents[12+(i*2)] = libxl__sprintf(&gc, "cpu/%d/availability", i);
119 ents[12+(i*2)+1] = (i && info->cur_vcpus && !(info->cur_vcpus & (1 << i)))
120 ? "offline" : "online";
121 }
123 dom_path = libxl__xs_get_dompath(&gc, domid);
124 if (!dom_path) {
125 libxl__free_all(&gc);
126 return ERROR_FAIL;
127 }
129 vm_path = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dom_path), NULL);
130 retry_transaction:
131 t = xs_transaction_start(ctx->xsh);
133 libxl__xs_writev(&gc, t, dom_path, ents);
134 libxl__xs_writev(&gc, t, dom_path, local_ents);
135 libxl__xs_writev(&gc, t, vm_path, vms_ents);
137 if (!xs_transaction_end(ctx->xsh, t, 0))
138 if (errno == EAGAIN)
139 goto retry_transaction;
140 xs_introduce_domain(ctx->xsh, domid, state->store_mfn, state->store_port);
141 free(vm_path);
142 libxl__free_all(&gc);
143 return 0;
144 }
146 int libxl__build_pv(libxl_ctx *ctx, uint32_t domid,
147 libxl_domain_build_info *info, libxl_domain_build_state *state)
148 {
149 struct xc_dom_image *dom;
150 int ret;
151 int flags = 0;
153 xc_dom_loginit(ctx->xch);
155 dom = xc_dom_allocate(ctx->xch, info->u.pv.cmdline, info->u.pv.features);
156 if (!dom) {
157 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_allocate failed");
158 return ERROR_FAIL;
159 }
161 if (info->kernel.mapped) {
162 if ( (ret = xc_dom_kernel_mem(dom, info->kernel.data, info->kernel.size)) != 0) {
163 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_kernel_mem failed");
164 goto out;
165 }
166 } else {
167 if ( (ret = xc_dom_kernel_file(dom, info->kernel.path)) != 0) {
168 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_kernel_file failed");
169 goto out;
170 }
171 }
173 if ( info->u.pv.ramdisk.path && strlen(info->u.pv.ramdisk.path) ) {
174 if (info->u.pv.ramdisk.mapped) {
175 if ( (ret = xc_dom_ramdisk_mem(dom, info->u.pv.ramdisk.data, info->u.pv.ramdisk.size)) != 0 ) {
176 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_ramdisk_mem failed");
177 goto out;
178 }
179 } else {
180 if ( (ret = xc_dom_ramdisk_file(dom, info->u.pv.ramdisk.path)) != 0 ) {
181 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_ramdisk_file failed");
182 goto out;
183 }
184 }
185 }
187 dom->flags = flags;
188 dom->console_evtchn = state->console_port;
189 dom->xenstore_evtchn = state->store_port;
191 if ( (ret = xc_dom_boot_xen_init(dom, ctx->xch, domid)) != 0 ) {
192 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_boot_xen_init failed");
193 goto out;
194 }
195 if ( (ret = xc_dom_parse_image(dom)) != 0 ) {
196 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_parse_image failed");
197 goto out;
198 }
199 if ( (ret = xc_dom_mem_init(dom, info->target_memkb / 1024)) != 0 ) {
200 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_mem_init failed");
201 goto out;
202 }
203 if ( (ret = xc_dom_boot_mem_init(dom)) != 0 ) {
204 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_boot_mem_init failed");
205 goto out;
206 }
207 if ( (ret = xc_dom_build_image(dom)) != 0 ) {
208 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_build_image failed");
209 goto out;
210 }
211 if ( (ret = xc_dom_boot_image(dom)) != 0 ) {
212 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_dom_boot_image failed");
213 goto out;
214 }
216 state->console_mfn = xc_dom_p2m_host(dom, dom->console_pfn);
217 state->store_mfn = xc_dom_p2m_host(dom, dom->xenstore_pfn);
219 ret = 0;
220 out:
221 xc_dom_release(dom);
222 return ret == 0 ? 0 : ERROR_FAIL;
223 }
225 static int hvm_build_set_params(xc_interface *handle, uint32_t domid,
226 libxl_domain_build_info *info,
227 int store_evtchn, unsigned long *store_mfn,
228 int console_evtchn, unsigned long *console_mfn)
229 {
230 struct hvm_info_table *va_hvm;
231 uint8_t *va_map, sum;
232 int i;
234 va_map = xc_map_foreign_range(handle, domid,
235 XC_PAGE_SIZE, PROT_READ | PROT_WRITE,
236 HVM_INFO_PFN);
237 if (va_map == NULL)
238 return -1;
240 va_hvm = (struct hvm_info_table *)(va_map + HVM_INFO_OFFSET);
241 va_hvm->acpi_enabled = info->u.hvm.acpi;
242 va_hvm->apic_mode = info->u.hvm.apic;
243 va_hvm->nr_vcpus = info->max_vcpus;
244 memcpy(va_hvm->vcpu_online, &info->cur_vcpus, sizeof(info->cur_vcpus));
245 for (i = 0, sum = 0; i < va_hvm->length; i++)
246 sum += ((uint8_t *) va_hvm)[i];
247 va_hvm->checksum -= sum;
248 munmap(va_map, XC_PAGE_SIZE);
250 xc_get_hvm_param(handle, domid, HVM_PARAM_STORE_PFN, store_mfn);
251 xc_get_hvm_param(handle, domid, HVM_PARAM_CONSOLE_PFN, console_mfn);
252 xc_set_hvm_param(handle, domid, HVM_PARAM_PAE_ENABLED, info->u.hvm.pae);
253 #if defined(__i386__) || defined(__x86_64__)
254 xc_set_hvm_param(handle, domid, HVM_PARAM_VIRIDIAN, info->u.hvm.viridian);
255 xc_set_hvm_param(handle, domid, HVM_PARAM_HPET_ENABLED, (unsigned long) info->u.hvm.hpet);
256 #endif
257 xc_set_hvm_param(handle, domid, HVM_PARAM_TIMER_MODE, (unsigned long) info->u.hvm.timer_mode);
258 xc_set_hvm_param(handle, domid, HVM_PARAM_VPT_ALIGN, (unsigned long) info->u.hvm.vpt_align);
259 xc_set_hvm_param(handle, domid, HVM_PARAM_STORE_EVTCHN, store_evtchn);
260 xc_set_hvm_param(handle, domid, HVM_PARAM_CONSOLE_EVTCHN, console_evtchn);
261 return 0;
262 }
264 int libxl__build_hvm(libxl_ctx *ctx, uint32_t domid,
265 libxl_domain_build_info *info, libxl_domain_build_state *state)
266 {
267 libxl__gc gc = LIBXL_INIT_GC(ctx);
268 int ret, rc = ERROR_INVAL;
270 if (info->kernel.mapped) {
271 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "libxl__build_hvm kernel cannot be mmapped");
272 goto out;
273 }
275 rc = ERROR_FAIL;
276 ret = xc_hvm_build_target_mem(
277 ctx->xch,
278 domid,
279 (info->max_memkb - info->video_memkb) / 1024,
280 (info->target_memkb - info->video_memkb) / 1024,
281 libxl__abs_path(&gc, (char *)info->kernel.path,
282 libxl_xenfirmwaredir_path()));
283 if (ret) {
284 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "hvm building failed");
285 goto out;
286 }
287 ret = hvm_build_set_params(ctx->xch, domid, info, state->store_port,
288 &state->store_mfn, state->console_port, &state->console_mfn);
289 if (ret) {
290 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "hvm build set params failed");
291 goto out;
292 }
293 rc = 0;
294 out:
295 libxl__free_all(&gc);
296 return 0;
297 }
299 int libxl__domain_restore_common(libxl_ctx *ctx, uint32_t domid,
300 libxl_domain_build_info *info, libxl_domain_build_state *state,
301 int fd)
302 {
303 /* read signature */
304 int rc;
305 rc = xc_domain_restore(ctx->xch, fd, domid,
306 state->store_port, &state->store_mfn,
307 state->console_port, &state->console_mfn,
308 info->hvm, info->u.hvm.pae, 0);
309 if ( rc ) {
310 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "restoring domain");
311 return ERROR_FAIL;
312 }
313 return 0;
314 }
316 struct suspendinfo {
317 libxl__gc *gc;
318 xc_evtchn *xce; /* event channel handle */
319 int suspend_eventchn;
320 int domid;
321 int hvm;
322 unsigned int flags;
323 };
325 static int libxl__domain_suspend_common_switch_qemu_logdirty(int domid, unsigned int enable, void *data)
326 {
327 struct suspendinfo *si = data;
328 libxl_ctx *ctx = libxl__gc_owner(si->gc);
329 char *path;
330 bool rc;
332 path = libxl__sprintf(si->gc, "/local/domain/0/device-model/%u/logdirty/cmd", domid);
333 if (!path)
334 return 1;
336 if (enable)
337 rc = xs_write(ctx->xsh, XBT_NULL, path, "enable", strlen("enable"));
338 else
339 rc = xs_write(ctx->xsh, XBT_NULL, path, "disable", strlen("disable"));
341 return rc ? 0 : 1;
342 }
344 static int libxl__domain_suspend_common_callback(void *data)
345 {
346 struct suspendinfo *si = data;
347 unsigned long s_state = 0;
348 int ret;
349 char *path, *state = "suspend";
350 int watchdog = 60;
351 libxl_ctx *ctx = libxl__gc_owner(si->gc);
353 if (si->hvm)
354 xc_get_hvm_param(ctx->xch, si->domid, HVM_PARAM_ACPI_S_STATE, &s_state);
355 if ((s_state == 0) && (si->suspend_eventchn >= 0)) {
356 ret = xc_evtchn_notify(si->xce, si->suspend_eventchn);
357 if (ret < 0) {
358 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "xc_evtchn_notify failed ret=%d", ret);
359 return 0;
360 }
361 ret = xc_await_suspend(ctx->xch, si->xce, si->suspend_eventchn);
362 if (ret < 0) {
363 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "xc_await_suspend failed ret=%d", ret);
364 return 0;
365 }
366 return 1;
367 }
368 path = libxl__sprintf(si->gc, "%s/control/shutdown", libxl__xs_get_dompath(si->gc, si->domid));
369 libxl__xs_write(si->gc, XBT_NULL, path, "suspend");
370 if (si->hvm) {
371 unsigned long hvm_pvdrv, hvm_s_state;
372 xc_get_hvm_param(ctx->xch, si->domid, HVM_PARAM_CALLBACK_IRQ, &hvm_pvdrv);
373 xc_get_hvm_param(ctx->xch, si->domid, HVM_PARAM_ACPI_S_STATE, &hvm_s_state);
374 if (!hvm_pvdrv || hvm_s_state) {
375 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Calling xc_domain_shutdown on the domain");
376 xc_domain_shutdown(ctx->xch, si->domid, SHUTDOWN_suspend);
377 }
378 }
379 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "wait for the guest to suspend");
380 while (!strcmp(state, "suspend") && watchdog > 0) {
381 xc_domaininfo_t info;
383 usleep(100000);
384 ret = xc_domain_getinfolist(ctx->xch, si->domid, 1, &info);
385 if (ret == 1 && info.domain == si->domid && info.flags & XEN_DOMINF_shutdown) {
386 int shutdown_reason;
388 shutdown_reason = (info.flags >> XEN_DOMINF_shutdownshift) & XEN_DOMINF_shutdownmask;
389 if (shutdown_reason == SHUTDOWN_suspend)
390 return 1;
391 }
392 state = libxl__xs_read(si->gc, XBT_NULL, path);
393 watchdog--;
394 }
395 if (!strcmp(state, "suspend")) {
396 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "guest didn't suspend in time");
397 libxl__xs_write(si->gc, XBT_NULL, path, "");
398 }
399 return 1;
400 }
402 int libxl__domain_suspend_common(libxl_ctx *ctx, uint32_t domid, int fd,
403 int hvm, int live, int debug)
404 {
405 libxl__gc gc = LIBXL_INIT_GC(ctx);
406 int flags;
407 int port;
408 struct save_callbacks callbacks;
409 struct suspendinfo si;
410 int rc = ERROR_FAIL;
412 flags = (live) ? XCFLAGS_LIVE : 0
413 | (debug) ? XCFLAGS_DEBUG : 0
414 | (hvm) ? XCFLAGS_HVM : 0;
416 si.domid = domid;
417 si.flags = flags;
418 si.hvm = hvm;
419 si.gc = &gc;
420 si.suspend_eventchn = -1;
422 si.xce = xc_evtchn_open(NULL, 0);
423 if (si.xce == NULL)
424 goto out;
425 else
426 {
427 port = xs_suspend_evtchn_port(si.domid);
429 if (port >= 0) {
430 si.suspend_eventchn = xc_suspend_evtchn_init(ctx->xch, si.xce, si.domid, port);
432 if (si.suspend_eventchn < 0)
433 LIBXL__LOG(ctx, LIBXL__LOG_WARNING, "Suspend event channel initialization failed");
434 }
435 }
437 memset(&callbacks, 0, sizeof(callbacks));
438 callbacks.suspend = libxl__domain_suspend_common_callback;
439 callbacks.switch_qemu_logdirty = libxl__domain_suspend_common_switch_qemu_logdirty;
440 callbacks.data = &si;
442 rc = xc_domain_save(ctx->xch, fd, domid, 0, 0, flags, &callbacks, hvm);
443 if ( rc ) {
444 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "saving domain");
445 rc = ERROR_FAIL;
446 }
448 if (si.suspend_eventchn > 0)
449 xc_suspend_evtchn_release(ctx->xch, si.xce, domid, si.suspend_eventchn);
450 if (si.xce != NULL)
451 xc_evtchn_close(si.xce);
453 out:
454 libxl__free_all(&gc);
455 return rc;
456 }
458 int libxl__domain_save_device_model(libxl_ctx *ctx, uint32_t domid, int fd)
459 {
460 libxl__gc gc = LIBXL_INIT_GC(ctx);
461 int fd2, c;
462 char buf[1024];
463 char *filename = libxl__sprintf(&gc, "/var/lib/xen/qemu-save.%d", domid);
464 struct stat st;
465 uint32_t qemu_state_len;
467 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Saving device model state to %s", filename);
468 libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/0/device-model/%d/command", domid), "save");
469 libxl__wait_for_device_model(ctx, domid, "paused", NULL, NULL);
471 if (stat(filename, &st) < 0)
472 {
473 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Unable to stat qemu save file\n");
474 libxl__free_all(&gc);
475 return ERROR_FAIL;
476 }
478 qemu_state_len = st.st_size;
479 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Qemu state is %d bytes\n", qemu_state_len);
481 c = libxl_write_exactly(ctx, fd, QEMU_SIGNATURE, strlen(QEMU_SIGNATURE),
482 "saved-state file", "qemu signature");
483 if (c) {
484 libxl__free_all(&gc);
485 return c;
486 }
488 c = libxl_write_exactly(ctx, fd, &qemu_state_len, sizeof(qemu_state_len),
489 "saved-state file", "saved-state length");
490 if (c) {
491 libxl__free_all(&gc);
492 return c;
493 }
495 fd2 = open(filename, O_RDONLY);
496 while ((c = read(fd2, buf, sizeof(buf))) != 0) {
497 if (c < 0) {
498 if (errno == EINTR)
499 continue;
500 libxl__free_all(&gc);
501 return errno;
502 }
503 c = libxl_write_exactly(
504 ctx, fd, buf, c, "saved-state file", "qemu state");
505 if (c) {
506 libxl__free_all(&gc);
507 return c;
508 }
509 }
510 close(fd2);
511 unlink(filename);
512 libxl__free_all(&gc);
513 return 0;
514 }
516 char *libxl__uuid2string(libxl__gc *gc, const libxl_uuid uuid)
517 {
518 char *s = libxl__sprintf(gc, LIBXL_UUID_FMT, LIBXL_UUID_BYTES(uuid));
519 if (!s)
520 LIBXL__LOG(libxl__gc_owner(gc), LIBXL__LOG_ERROR, "cannot allocate for uuid");
521 return s;
522 }
524 static const char *userdata_path(libxl__gc *gc, uint32_t domid,
525 const char *userdata_userid,
526 const char *wh)
527 {
528 libxl_ctx *ctx = libxl__gc_owner(gc);
529 char *path, *uuid_string;
530 libxl_dominfo info;
531 int rc;
533 rc = libxl_domain_info(ctx, &info, domid);
534 if (rc) {
535 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to find domain info"
536 " for domain %"PRIu32, domid);
537 return NULL;
538 }
539 uuid_string = libxl__sprintf(gc, LIBXL_UUID_FMT, LIBXL_UUID_BYTES(info.uuid));
541 path = libxl__sprintf(gc, "/var/lib/xen/"
542 "userdata-%s.%u.%s.%s",
543 wh, domid, uuid_string, userdata_userid);
544 if (!path)
545 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to allocate for"
546 " userdata path");
547 return path;
548 }
550 static int userdata_delete(libxl_ctx *ctx, const char *path) {
551 int r;
552 r = unlink(path);
553 if (r) {
554 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "remove failed for %s", path);
555 return errno;
556 }
557 return 0;
558 }
560 void libxl__userdata_destroyall(libxl_ctx *ctx, uint32_t domid)
561 {
562 libxl__gc gc = LIBXL_INIT_GC(ctx);
563 const char *pattern;
564 glob_t gl;
565 int r, i;
567 pattern = userdata_path(&gc, domid, "*", "?");
568 if (!pattern)
569 goto out;
571 gl.gl_pathc = 0;
572 gl.gl_pathv = 0;
573 gl.gl_offs = 0;
574 r = glob(pattern, GLOB_ERR|GLOB_NOSORT|GLOB_MARK, 0, &gl);
575 if (r == GLOB_NOMATCH)
576 goto out;
577 if (r)
578 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "glob failed for %s", pattern);
580 for (i=0; i<gl.gl_pathc; i++) {
581 userdata_delete(ctx, gl.gl_pathv[i]);
582 }
583 globfree(&gl);
584 out:
585 libxl__free_all(&gc);
586 }
588 int libxl_userdata_store(libxl_ctx *ctx, uint32_t domid,
589 const char *userdata_userid,
590 const uint8_t *data, int datalen)
591 {
592 libxl__gc gc = LIBXL_INIT_GC(ctx);
593 const char *filename;
594 const char *newfilename;
595 int e, rc;
596 int fd = -1;
597 FILE *f = NULL;
598 size_t rs;
600 filename = userdata_path(&gc, domid, userdata_userid, "d");
601 if (!filename) {
602 rc = ERROR_NOMEM;
603 goto out;
604 }
606 if (!datalen) {
607 rc = userdata_delete(ctx, filename);
608 goto out;
609 }
611 newfilename = userdata_path(&gc, domid, userdata_userid, "n");
612 if (!newfilename) {
613 rc = ERROR_NOMEM;
614 goto out;
615 }
617 rc = ERROR_FAIL;
619 fd= open(newfilename, O_RDWR|O_CREAT|O_TRUNC, 0600);
620 if (fd<0)
621 goto err;
623 f= fdopen(fd, "wb");
624 if (!f)
625 goto err;
626 fd = -1;
628 rs = fwrite(data, 1, datalen, f);
629 if (rs != datalen) {
630 assert(ferror(f));
631 goto err;
632 }
634 if (fclose(f))
635 goto err;
636 f = 0;
638 if (rename(newfilename,filename))
639 goto err;
641 rc = 0;
643 err:
644 e = errno;
645 if (f) fclose(f);
646 if (fd>=0) close(fd);
648 errno = e;
649 if ( rc )
650 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "cannot write %s for %s",
651 newfilename, filename);
652 out:
653 libxl__free_all(&gc);
654 return rc;
655 }
657 int libxl_userdata_retrieve(libxl_ctx *ctx, uint32_t domid,
658 const char *userdata_userid,
659 uint8_t **data_r, int *datalen_r)
660 {
661 libxl__gc gc = LIBXL_INIT_GC(ctx);
662 const char *filename;
663 int e, rc;
664 int datalen = 0;
665 void *data = 0;
667 filename = userdata_path(&gc, domid, userdata_userid, "d");
668 if (!filename) {
669 rc = ERROR_NOMEM;
670 goto out;
671 }
673 e = libxl_read_file_contents(ctx, filename, data_r ? &data : 0, &datalen);
675 if (!e && !datalen) {
676 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "userdata file %s is empty", filename);
677 if (data_r) assert(!*data_r);
678 rc = ERROR_FAIL;
679 goto out;
680 }
682 if (data_r) *data_r = data;
683 if (datalen_r) *datalen_r = datalen;
684 rc = 0;
685 out:
686 libxl__free_all(&gc);
687 return rc;
688 }