debuggers.hg

view tools/blktap2/control/tap-ctl-list.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents 266df0bf4a0d
children
line source
1 /*
2 * Copyright (c) 2008, XenSource Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of XenSource Inc. nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
29 #include <stdio.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <glob.h>
36 #include "tap-ctl.h"
37 #include "blktap2.h"
38 #include "list.h"
40 static void
41 free_list(tap_list_t *entry)
42 {
43 if (entry->type) {
44 free(entry->type);
45 entry->type = NULL;
46 }
48 if (entry->path) {
49 free(entry->path);
50 entry->path = NULL;
51 }
53 free(entry);
54 }
56 int
57 _parse_params(const char *params, char **type, char **path)
58 {
59 char *ptr;
60 size_t len;
62 ptr = strchr(params, ':');
63 if (!ptr)
64 return -EINVAL;
66 len = ptr - params;
68 *type = strndup(params, len);
69 *path = strdup(params + len + 1);
71 if (!*type || !*path) {
72 free(*type);
73 *type = NULL;
75 free(*path);
76 *path = NULL;
78 return -errno;
79 }
81 return 0;
82 }
84 static int
85 init_list(tap_list_t *entry,
86 int tap_id, pid_t tap_pid, int vbd_minor, int vbd_state,
87 const char *params)
88 {
89 int err = 0;
91 entry->id = tap_id;
92 entry->pid = tap_pid;
93 entry->minor = vbd_minor;
94 entry->state = vbd_state;
96 if (params)
97 err = _parse_params(params, &entry->type, &entry->path);
99 return err;
100 }
102 void
103 tap_ctl_free_list(tap_list_t **list)
104 {
105 tap_list_t **_entry;
107 for (_entry = list; *_entry != NULL; ++_entry)
108 free_list(*_entry);
110 free(list);
111 }
113 static tap_list_t**
114 tap_ctl_alloc_list(int n)
115 {
116 tap_list_t **list, *entry;
117 size_t size;
118 int i;
120 size = sizeof(tap_list_t*) * (n+1);
121 list = malloc(size);
122 if (!list)
123 goto fail;
125 memset(list, 0, size);
127 for (i = 0; i < n; ++i) {
128 tap_list_t *entry;
130 entry = malloc(sizeof(tap_list_t));
131 if (!entry)
132 goto fail;
134 memset(entry, 0, sizeof(tap_list_t));
136 list[i] = entry;
137 }
139 return list;
141 fail:
142 if (list)
143 tap_ctl_free_list(list);
145 return NULL;
146 }
148 static int
149 tap_ctl_list_length(const tap_list_t **list)
150 {
151 const tap_list_t **_entry;
152 int n;
154 n = 0;
155 for (_entry = list; *_entry != NULL; ++_entry)
156 n++;
158 return n;
159 }
161 static int
162 _tap_minor_cmp(const void *a, const void *b)
163 {
164 return *(int*)a - *(int*)b;
165 }
167 int
168 _tap_ctl_find_minors(int **_minorv)
169 {
170 glob_t glbuf = { 0 };
171 const char *pattern, *format;
172 int *minorv = NULL, n_minors = 0;
173 int err, i;
175 pattern = BLKTAP2_SYSFS_DIR"/blktap*";
176 format = BLKTAP2_SYSFS_DIR"/blktap%d";
178 n_minors = 0;
179 minorv = NULL;
181 err = glob(pattern, 0, NULL, &glbuf);
182 switch (err) {
183 case GLOB_NOMATCH:
184 goto done;
186 case GLOB_ABORTED:
187 case GLOB_NOSPACE:
188 err = -errno;
189 EPRINTF("%s: glob failed, err %d", pattern, err);
190 goto fail;
191 }
193 minorv = malloc(sizeof(int) * glbuf.gl_pathc);
194 if (!minorv) {
195 err = -errno;
196 goto fail;
197 }
199 for (i = 0; i < glbuf.gl_pathc; ++i) {
200 int n;
202 n = sscanf(glbuf.gl_pathv[i], format, &minorv[n_minors]);
203 if (n != 1)
204 continue;
206 n_minors++;
207 }
209 qsort(minorv, n_minors, sizeof(int), _tap_minor_cmp);
211 done:
212 *_minorv = minorv;
213 err = 0;
215 out:
216 if (glbuf.gl_pathv)
217 globfree(&glbuf);
219 return err ? : n_minors;
221 fail:
222 if (minorv)
223 free(minorv);
225 goto out;
226 }
228 struct tapdisk {
229 int id;
230 pid_t pid;
231 struct list_head list;
232 };
234 static int
235 _tap_tapdisk_cmp(const void *a, const void *b)
236 {
237 return ((struct tapdisk*)a)->id - ((struct tapdisk*)b)->id;
238 }
240 int
241 _tap_ctl_find_tapdisks(struct tapdisk **_tapv)
242 {
243 glob_t glbuf = { 0 };
244 const char *pattern, *format;
245 struct tapdisk *tapv = NULL;
246 int err, i, n_taps = 0;
248 pattern = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"*";
249 format = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"%d";
251 n_taps = 0;
252 tapv = NULL;
254 err = glob(pattern, 0, NULL, &glbuf);
255 switch (err) {
256 case GLOB_NOMATCH:
257 goto done;
259 case GLOB_ABORTED:
260 case GLOB_NOSPACE:
261 err = -errno;
262 EPRINTF("%s: glob failed, err %d", pattern, err);
263 goto fail;
264 }
266 tapv = malloc(sizeof(struct tapdisk) * glbuf.gl_pathc);
267 if (!tapv) {
268 err = -errno;
269 goto fail;
270 }
272 for (i = 0; i < glbuf.gl_pathc; ++i) {
273 struct tapdisk *tap;
274 int n;
276 tap = &tapv[n_taps];
278 err = sscanf(glbuf.gl_pathv[i], format, &tap->id);
279 if (err != 1)
280 continue;
282 tap->pid = tap_ctl_get_pid(tap->id);
283 if (tap->pid < 0)
284 continue;
286 n_taps++;
287 }
289 qsort(tapv, n_taps, sizeof(struct tapdisk), _tap_tapdisk_cmp);
291 for (i = 0; i < n_taps; ++i)
292 INIT_LIST_HEAD(&tapv[i].list);
294 done:
295 *_tapv = tapv;
296 err = 0;
298 out:
299 if (glbuf.gl_pathv)
300 globfree(&glbuf);
302 return err ? : n_taps;
304 fail:
305 if (tapv)
306 free(tapv);
308 goto out;
309 }
311 struct tapdisk_list {
312 int minor;
313 int state;
314 char *params;
315 struct list_head entry;
316 };
318 int
319 _tap_ctl_list_tapdisk(int id, struct list_head *_list)
320 {
321 tapdisk_message_t message;
322 struct list_head list;
323 struct tapdisk_list *tl, *next;
324 int err, sfd;
326 err = tap_ctl_connect_id(id, &sfd);
327 if (err)
328 return err;
330 memset(&message, 0, sizeof(message));
331 message.type = TAPDISK_MESSAGE_LIST;
332 message.cookie = -1;
334 err = tap_ctl_write_message(sfd, &message, 2);
335 if (err)
336 return err;
338 INIT_LIST_HEAD(&list);
339 do {
340 err = tap_ctl_read_message(sfd, &message, 2);
341 if (err) {
342 err = -EPROTO;
343 break;
344 }
346 if (message.u.list.count == 0)
347 break;
349 tl = malloc(sizeof(struct tapdisk_list));
350 if (!tl) {
351 err = -ENOMEM;
352 break;
353 }
355 tl->minor = message.u.list.minor;
356 tl->state = message.u.list.state;
357 if (message.u.list.path[0] != 0) {
358 tl->params = strndup(message.u.list.path,
359 sizeof(message.u.list.path));
360 if (!tl->params) {
361 err = -errno;
362 break;
363 }
364 } else
365 tl->params = NULL;
367 list_add(&tl->entry, &list);
368 } while (1);
370 if (err)
371 list_for_each_entry_safe(tl, next, &list, entry) {
372 list_del(&tl->entry);
373 free(tl->params);
374 free(tl);
375 }
377 close(sfd);
378 list_splice(&list, _list);
379 return err;
380 }
382 void
383 _tap_ctl_free_tapdisks(struct tapdisk *tapv, int n_taps)
384 {
385 struct tapdisk *tap;
387 for (tap = tapv; tap < &tapv[n_taps]; ++tap) {
388 struct tapdisk_list *tl, *next;
390 list_for_each_entry_safe(tl, next, &tap->list, entry) {
391 free(tl->params);
392 free(tl);
393 }
394 }
396 free(tapv);
397 }
399 int
400 _tap_list_join3(int n_minors, int *minorv, int n_taps, struct tapdisk *tapv,
401 tap_list_t ***_list)
402 {
403 tap_list_t **list, **_entry, *entry;
404 int i, _m, err;
406 list = tap_ctl_alloc_list(n_minors + n_taps);
407 if (!list) {
408 err = -ENOMEM;
409 goto fail;
410 }
412 _entry = list;
414 for (i = 0; i < n_taps; ++i) {
415 struct tapdisk *tap = &tapv[i];
416 struct tapdisk_list *tl;
418 /* orphaned tapdisk */
419 if (list_empty(&tap->list)) {
420 err = init_list(*_entry++, tap->id, tap->pid, -1, -1, NULL);
421 if (err)
422 goto fail;
423 continue;
424 }
426 list_for_each_entry(tl, &tap->list, entry) {
428 err = init_list(*_entry++,
429 tap->id, tap->pid,
430 tl->minor, tl->state, tl->params);
431 if (err)
432 goto fail;
434 if (tl->minor >= 0) {
435 /* clear minor */
436 for (_m = 0; _m < n_minors; ++_m) {
437 if (minorv[_m] == tl->minor) {
438 minorv[_m] = -1;
439 break;
440 }
441 }
442 }
443 }
444 }
446 /* orphaned minors */
447 for (_m = 0; _m < n_minors; ++_m) {
448 int minor = minorv[_m];
449 if (minor >= 0) {
450 err = init_list(*_entry++, -1, -1, minor, -1, NULL);
451 if (err)
452 goto fail;
453 }
454 }
456 /* free extraneous list entries */
457 for (; *_entry != NULL; ++entry) {
458 free_list(*_entry);
459 *_entry = NULL;
460 }
462 *_list = list;
464 return 0;
466 fail:
467 if (list)
468 tap_ctl_free_list(list);
470 return err;
471 }
473 int
474 tap_ctl_list(tap_list_t ***list)
475 {
476 int n_taps, n_minors, err, *minorv;
477 struct tapdisk *tapv, *tap;
479 n_taps = -1;
480 n_minors = -1;
482 err = n_minors = _tap_ctl_find_minors(&minorv);
483 if (err < 0)
484 goto out;
486 err = n_taps = _tap_ctl_find_tapdisks(&tapv);
487 if (err < 0)
488 goto out;
490 for (tap = tapv; tap < &tapv[n_taps]; ++tap) {
491 err = _tap_ctl_list_tapdisk(tap->id, &tap->list);
492 if (err)
493 goto out;
494 }
496 err = _tap_list_join3(n_minors, minorv, n_taps, tapv, list);
498 out:
499 if (n_taps > 0)
500 _tap_ctl_free_tapdisks(tapv, n_taps);
502 if (n_minors > 0)
503 free(minorv);
505 return err;
506 }
508 int
509 tap_ctl_find_minor(const char *type, const char *path)
510 {
511 tap_list_t **list, **_entry;
512 int minor, err;
514 err = tap_ctl_list(&list);
515 if (err)
516 return err;
518 minor = -1;
520 for (_entry = list; *_entry != NULL; ++_entry) {
521 tap_list_t *entry = *_entry;
523 if (type && (!entry->type || strcmp(entry->type, type)))
524 continue;
526 if (path && (!entry->path || strcmp(entry->path, path)))
527 continue;
529 minor = entry->minor;
530 break;
531 }
533 tap_ctl_free_list(list);
535 return minor >= 0 ? minor : -ENOENT;
536 }