debuggers.hg

view tools/libxl/libxl_dom.c @ 22855:1d1eec7e1fb4

xl: Perform minimal validation of virtual disk file while parsing config file

This patch performs some very basic validation on the virtual disk
file passed through the config file. This validation ensures that we
don't go too far with the initialization like spawn qemu and more
while there could be some potentially fundamental issues.

[ Patch fixed up to work with PHYSTYPE_EMPTY 22808:6ec61438713a -iwj ]

Signed-off-by: Kamala Narasimhan <kamala.narasimhan@citrix.com>
Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Committed-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Kamala Narasimhan <kamala.narasimhan@gmail.com>
date Tue Jan 25 18:09:49 2011 +0000 (2011-01-25)
parents 60782cefa154
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 }