debuggers.hg

view tools/libxl/libxl_utils.c @ 21954:f6b91d2f9fa3

libxl: fix memory leak in libxl_name_to_domid

Found with "valgrind xl destroy ...":
==16272== 53,248 bytes in 1 blocks are definitely lost in loss record 6 of 6
==16272== at 0x4022249: calloc (vg_replace_malloc.c:467)
==16272== by 0x403FD4A: libxl_list_domain (libxl.c:490)
==16272== by 0x404B901: libxl_name_to_domid (libxl_utils.c:65)
==16272== by 0x804B4D2: domain_qualifier_to_domid (xl_cmdimpl.c:181)
==16272== by 0x804B50F: find_domain (xl_cmdimpl.c:198)
==16272== by 0x804D70C: destroy_domain (xl_cmdimpl.c:2104)
==16272== by 0x8054E4C: main_destroy (xl_cmdimpl.c:2912)
==16272== by 0x804B2FB: main (xl.c:76)

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
author Ian Campbell <ian.campbell@citrix.com>
date Tue Aug 03 18:09:21 2010 +0100 (2010-08-03)
parents bf4d0eb3643d
children baaa4b9d385f
line source
1 /*
2 * Copyright (C) 2009 Citrix Ltd.
3 * Author Stefano Stabellini <stefano.stabellini@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 <stdlib.h>
20 #include <stdint.h>
21 #include <string.h>
22 #include <xs.h>
23 #include <xenctrl.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <assert.h>
31 #include "libxl_utils.h"
32 #include "libxl_internal.h"
35 unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned int smp_cpus)
36 {
37 /* 256 pages (1MB) per vcpu,
38 plus 1 page per MiB of RAM for the P2M map,
39 plus 1 page per MiB of RAM to shadow the resident processes.
40 This is higher than the minimum that Xen would allocate if no value
41 were given (but the Xen minimum is for safety, not performance).
42 */
43 return 4 * (256 * smp_cpus + 2 * (maxmem_kb / 1024));
44 }
46 char *libxl_domid_to_name(libxl_ctx *ctx, uint32_t domid)
47 {
48 unsigned int len;
49 char path[strlen("/local/domain") + 12];
50 char *s;
52 snprintf(path, sizeof(path), "/local/domain/%d/name", domid);
53 s = xs_read(ctx->xsh, XBT_NULL, path, &len);
54 libxl_ptr_add(ctx, s);
55 return s;
56 }
58 int libxl_name_to_domid(libxl_ctx *ctx, const char *name,
59 uint32_t *domid)
60 {
61 int i, nb_domains;
62 char *domname;
63 libxl_dominfo *dominfo;
64 int ret = -1;
66 dominfo = libxl_list_domain(ctx, &nb_domains);
67 if (!dominfo)
68 return ERROR_NOMEM;
70 for (i = 0; i < nb_domains; i++) {
71 domname = libxl_domid_to_name(ctx, dominfo[i].domid);
72 if (!domname)
73 continue;
74 if (strcmp(domname, name) == 0) {
75 *domid = dominfo[i].domid;
76 ret = 0;
77 break;
78 }
79 }
80 free(dominfo);
81 return ret;
82 }
84 char *libxl_poolid_to_name(libxl_ctx *ctx, uint32_t poolid)
85 {
86 unsigned int len;
87 char path[strlen("/local/pool") + 12];
88 char *s;
90 if (poolid == 0)
91 return "Pool-0";
92 snprintf(path, sizeof(path), "/local/pool/%d/name", poolid);
93 s = xs_read(ctx->xsh, XBT_NULL, path, &len);
94 libxl_ptr_add(ctx, s);
95 return s;
96 }
98 int libxl_name_to_poolid(libxl_ctx *ctx, const char *name,
99 uint32_t *poolid)
100 {
101 int i, nb_pools;
102 char *poolname;
103 libxl_poolinfo *poolinfo;
105 poolinfo = libxl_list_pool(ctx, &nb_pools);
106 if (!poolinfo)
107 return ERROR_NOMEM;
109 for (i = 0; i < nb_pools; i++) {
110 poolname = libxl_poolid_to_name(ctx, poolinfo[i].poolid);
111 if (!poolname)
112 continue;
113 if (strcmp(poolname, name) == 0) {
114 *poolid = poolinfo[i].poolid;
115 return 0;
116 }
117 }
118 return -1;
119 }
121 int libxl_get_stubdom_id(libxl_ctx *ctx, int guest_domid)
122 {
123 char * stubdom_id_s = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/image/device-model-domid", libxl_xs_get_dompath(ctx, guest_domid)));
124 if (stubdom_id_s)
125 return atoi(stubdom_id_s);
126 else
127 return 0;
128 }
130 int libxl_is_stubdom(libxl_ctx *ctx, uint32_t domid, uint32_t *target_domid)
131 {
132 char *target, *endptr;
133 uint32_t value;
135 target = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/target", libxl_xs_get_dompath(ctx, domid)));
136 if (!target)
137 return 0;
138 value = strtol(target, &endptr, 10);
139 if (*endptr != '\0')
140 return 0;
141 if (target_domid)
142 *target_domid = value;
143 return 1;
144 }
146 static int logrename(libxl_ctx *ctx, const char *old, const char *new) {
147 int r;
149 r = rename(old, new);
150 if (r) {
151 if (errno == ENOENT) return 0; /* ok */
153 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to rotate logfile - could not"
154 " rename %s to %s", old, new);
155 return ERROR_FAIL;
156 }
157 return 0;
158 }
160 int libxl_create_logfile(libxl_ctx *ctx, char *name, char **full_name)
161 {
162 struct stat stat_buf;
163 char *logfile, *logfile_new;
164 int i, rc;
166 logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log", name);
167 if (stat(logfile, &stat_buf) == 0) {
168 /* file exists, rotate */
169 logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log.10", name);
170 unlink(logfile);
171 for (i = 9; i > 0; i--) {
172 logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log.%d", name, i);
173 logfile_new = libxl_sprintf(ctx, "/var/log/xen/%s.log.%d", name, i + 1);
174 rc = logrename(ctx, logfile, logfile_new);
175 if (rc) return rc;
176 }
177 logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log", name);
178 logfile_new = libxl_sprintf(ctx, "/var/log/xen/%s.log.1", name);
180 rc = logrename(ctx, logfile, logfile_new);
181 if (rc) return rc;
182 } else {
183 if (errno != ENOENT)
184 XL_LOG_ERRNO(ctx, XL_LOG_WARNING, "problem checking existence of"
185 " logfile %s, which might have needed to be rotated",
186 name);
187 }
188 *full_name = strdup(logfile);
189 return 0;
190 }
192 int libxl_string_to_phystype(libxl_ctx *ctx, char *s, libxl_disk_phystype *phystype)
193 {
194 char *p;
195 int rc = 0;
197 if (!strcmp(s, "phy")) {
198 *phystype = PHYSTYPE_PHY;
199 } else if (!strcmp(s, "file")) {
200 *phystype = PHYSTYPE_FILE;
201 } else if (!strcmp(s, "tap")) {
202 p = strchr(s, ':');
203 if (!p) {
204 rc = -1;
205 goto out;
206 }
207 p++;
208 if (!strcmp(p, "aio")) {
209 *phystype = PHYSTYPE_AIO;
210 } else if (!strcmp(p, "vhd")) {
211 *phystype = PHYSTYPE_VHD;
212 } else if (!strcmp(p, "qcow")) {
213 *phystype = PHYSTYPE_QCOW;
214 } else if (!strcmp(p, "qcow2")) {
215 *phystype = PHYSTYPE_QCOW2;
216 }
217 }
218 out:
219 return rc;
220 }
222 int libxl_read_file_contents(libxl_ctx *ctx, const char *filename,
223 void **data_r, int *datalen_r) {
224 FILE *f = 0;
225 uint8_t *data = 0;
226 int datalen = 0;
227 int e;
228 struct stat stab;
229 ssize_t rs;
231 f = fopen(filename, "r");
232 if (!f) {
233 if (errno == ENOENT) return ENOENT;
234 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to open %s", filename);
235 goto xe;
236 }
238 if (fstat(fileno(f), &stab)) {
239 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to fstat %s", filename);
240 goto xe;
241 }
243 if (!S_ISREG(stab.st_mode)) {
244 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "%s is not a plain file", filename);
245 errno = ENOTTY;
246 goto xe;
247 }
249 if (stab.st_size > INT_MAX) {
250 XL_LOG(ctx, XL_LOG_ERROR, "file %s is far too large", filename);
251 errno = EFBIG;
252 goto xe;
253 }
255 datalen = stab.st_size;
257 if (stab.st_size && data_r) {
258 data = malloc(datalen);
259 if (!data) goto xe;
261 rs = fread(data, 1, datalen, f);
262 if (rs != datalen) {
263 if (ferror(f))
264 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to read %s", filename);
265 else if (feof(f))
266 XL_LOG(ctx, XL_LOG_ERROR, "%s changed size while we"
267 " were reading it", filename);
268 else
269 abort();
270 goto xe;
271 }
272 }
274 if (fclose(f)) {
275 f = 0;
276 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to close %s", filename);
277 goto xe;
278 }
280 if (data_r) *data_r = data;
281 if (datalen_r) *datalen_r = datalen;
283 return 0;
285 xe:
286 e = errno;
287 assert(e != ENOENT);
288 if (f) fclose(f);
289 if (data) free(data);
290 return e;
291 }
293 #define READ_WRITE_EXACTLY(rw, zero_is_eof, constdata) \
294 \
295 int libxl_##rw##_exactly(libxl_ctx *ctx, int fd, \
296 constdata void *data, ssize_t sz, \
297 const char *filename, const char *what) { \
298 ssize_t got; \
299 \
300 while (sz > 0) { \
301 got = rw(fd, data, sz); \
302 if (got == -1) { \
303 if (errno == EINTR) continue; \
304 if (!ctx) return errno; \
305 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to " #rw " %s%s%s", \
306 what?what:"", what?" from ":"", filename); \
307 return errno; \
308 } \
309 if (got == 0) { \
310 if (!ctx) return EPROTO; \
311 XL_LOG(ctx, XL_LOG_ERROR, \
312 zero_is_eof \
313 ? "file/stream truncated reading %s%s%s" \
314 : "file/stream write returned 0! writing %s%s%s", \
315 what?what:"", what?" from ":"", filename); \
316 return EPROTO; \
317 } \
318 sz -= got; \
319 data = (char*)data + got; \
320 } \
321 return 0; \
322 }
324 READ_WRITE_EXACTLY(read, 1, /* */)
325 READ_WRITE_EXACTLY(write, 0, const)
328 int libxl_ctx_postfork(libxl_ctx *ctx) {
329 if (ctx->xsh) xs_daemon_destroy_postfork(ctx->xsh);
330 ctx->xsh = xs_daemon_open();
331 if (!ctx->xsh) return ERROR_FAIL;
332 return 0;
333 }
335 pid_t libxl_fork(libxl_ctx *ctx)
336 {
337 pid_t pid;
339 pid = fork();
340 if (pid == -1) {
341 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "fork failed");
342 return -1;
343 }
345 if (!pid) {
346 if (ctx->xsh) xs_daemon_destroy_postfork(ctx->xsh);
347 ctx->xsh = 0;
348 /* This ensures that anyone who forks but doesn't exec,
349 * and doesn't reinitialise the libxl_ctx, is OK.
350 * It also means they can safely call libxl_ctx_free. */
351 }
353 return pid;
354 }
356 int libxl_pipe(libxl_ctx *ctx, int pipes[2])
357 {
358 if (pipe(pipes) < 0) {
359 XL_LOG(ctx, XL_LOG_ERROR, "Failed to create a pipe");
360 return -1;
361 }
362 return 0;
363 }
365 int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
366 const char *mac, libxl_device_nic *nic)
367 {
368 libxl_nicinfo *nics;
369 unsigned int nb, i;
370 uint8_t mac_n[6];
371 uint8_t *a, *b;
372 const char *tok;
373 char *endptr;
375 nics = libxl_list_nics(ctx, domid, &nb);
376 if (!nics) {
377 return ERROR_FAIL;
378 }
380 for (i = 0, tok = mac; *tok && (i < 6); ++i, tok += 3) {
381 mac_n[i] = strtol(tok, &endptr, 16);
382 if (endptr != (tok + 2)) {
383 return ERROR_INVAL;
384 }
385 }
386 memset(nic, 0, sizeof (libxl_device_nic));
387 for (; nb; --nb, ++nics) {
388 for (i = 0, a = nics->mac, b = mac_n;
389 (b < mac_n + 6) && (*a == *b); ++a, ++b)
390 ;
391 if ((b >= mac_n + 6) && (*a == *b)) {
392 nic->backend_domid = nics->backend_id;
393 nic->domid = nics->frontend_id;
394 nic->devid = nics->devid;
395 memcpy(nic->mac, nics->mac, sizeof (nic->mac));
396 nic->script = nics->script;
397 libxl_free(ctx, nics);
398 return 0;
399 }
400 }
402 libxl_free(ctx, nics);
403 return 0;
404 }
406 int libxl_devid_to_device_nic(libxl_ctx *ctx, uint32_t domid,
407 const char *devid, libxl_device_nic *nic)
408 {
409 char *tok, *val;
410 char *dompath, *nic_path_fe, *nic_path_be;
411 unsigned int i;
413 memset(nic, 0, sizeof (libxl_device_nic));
414 dompath = libxl_xs_get_dompath(ctx, domid);
415 if (!dompath) {
416 return ERROR_FAIL;
417 }
418 nic_path_fe = libxl_sprintf(ctx, "%s/device/vif/%s", dompath, devid);
419 nic_path_be = libxl_xs_read(ctx, XBT_NULL,
420 libxl_sprintf(ctx, "%s/backend", nic_path_fe));
421 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend-id", nic_path_fe));
422 nic->backend_domid = strtoul(val, NULL, 10);
423 nic->devid = strtoul(devid, NULL, 10);
424 libxl_free(ctx, val);
426 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/mac", nic_path_fe));
427 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
428 ++i, tok = strtok(NULL, ":")) {
429 nic->mac[i] = strtoul(tok, NULL, 16);
430 }
431 libxl_free(ctx, val);
432 nic->script = libxl_xs_read(ctx, XBT_NULL,
433 libxl_sprintf(ctx, "%s/script", nic_path_be));
434 libxl_free(ctx, nic_path_fe);
435 libxl_free(ctx, nic_path_be);
436 return 0;
437 }
439 int libxl_devid_to_device_disk(libxl_ctx *ctx, uint32_t domid,
440 const char *devid, libxl_device_disk *disk)
441 {
442 char *endptr, *val;
443 char *dompath, *diskpath, *be_path;
444 unsigned int devid_n;
446 devid_n = strtoul(devid, &endptr, 10);
447 if (devid == endptr) {
448 return ERROR_INVAL;
449 }
450 dompath = libxl_xs_get_dompath(ctx, domid);
451 diskpath = libxl_sprintf(ctx, "%s/device/vbd/%s", dompath, devid);
452 if (!diskpath) {
453 return ERROR_FAIL;
454 }
456 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend-id", diskpath));
457 if (!val)
458 return ERROR_FAIL;
459 disk->backend_domid = strtoul(val, NULL, 10);
460 disk->domid = domid;
461 be_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend", diskpath));
462 disk->physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/params", be_path));
463 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/type", be_path));
464 libxl_string_to_phystype(ctx, val, &(disk->phystype));
465 disk->virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev", be_path));
466 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/removable", be_path));
467 disk->unpluggable = !strcmp(val, "1");
468 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/mode", be_path));
469 disk->readwrite = !!strcmp(val, "w");
470 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/device-type", diskpath));
471 disk->is_cdrom = !strcmp(val, "cdrom");
473 return 0;
474 }
476 int libxl_devid_to_device_net2(libxl_ctx *ctx, uint32_t domid,
477 const char *devid, libxl_device_net2 *net2)
478 {
479 char *tok, *endptr, *val;
480 char *dompath, *net2path, *be_path;
481 unsigned int devid_n, i;
483 devid_n = strtoul(devid, &endptr, 10);
484 if (devid == endptr) {
485 return ERROR_INVAL;
486 }
487 dompath = libxl_xs_get_dompath(ctx, domid);
488 net2path = libxl_sprintf(ctx, "%s/device/vif2/%s", dompath, devid);
489 if (!net2path) {
490 return ERROR_FAIL;
491 }
492 memset(net2, 0, sizeof (libxl_device_net2));
493 be_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend", net2path));
495 net2->devid = devid_n;
496 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/mac", net2path));
497 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
498 ++i, tok = strtok(NULL, ":")) {
499 net2->front_mac[i] = strtoul(tok, NULL, 16);
500 }
501 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/remote-mac", net2path));
502 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
503 ++i, tok = strtok(NULL, ":")) {
504 net2->back_mac[i] = strtoul(tok, NULL, 16);
505 }
506 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend-id", net2path));
507 net2->backend_domid = strtoul(val, NULL, 10);
509 net2->domid = domid;
510 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/remote-trusted", be_path));
511 net2->trusted = strtoul(val, NULL, 10);
512 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/local-trusted", be_path));
513 net2->back_trusted = strtoul(val, NULL, 10);
514 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/filter-mac", be_path));
515 net2->filter_mac = strtoul(val, NULL, 10);
516 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/filter-mac", net2path));
517 net2->front_filter_mac = strtoul(val, NULL, 10);
518 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/max-bypasses", be_path));
519 net2->max_bypasses = strtoul(val, NULL, 10);
521 return 0;
522 }
524 int libxl_strtomac(const char *mac_s, uint8_t *mac)
525 {
526 const char *end = mac_s + 17;
527 char val, *endptr;
529 for (; mac_s < end; mac_s += 3, ++mac) {
530 val = strtoul(mac_s, &endptr, 16);
531 if (endptr != (mac_s + 2)) {
532 return ERROR_INVAL;
533 }
534 *mac = val;
535 }
536 return 0;
537 }