ia64/xen-unstable

view tools/xenstore/xs_test.c @ 8556:c886f74b54a4

make xs_test in xenstore compile.

Signed-off-by: Vincent Hanquez <vincent@xensource.com>
author vhanquez@kneesa.uk.xensource.com
date Wed Jan 11 12:02:54 2006 +0000 (2006-01-11)
parents f226284e5c1a
children
line source
1 /*
2 Xen Store Daemon Test tool
3 Copyright (C) 2005 Rusty Russell IBM Corporation
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
20 #define _GNU_SOURCE
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 #include <stdint.h>
29 #include <stdbool.h>
30 #include <stdlib.h>
31 #include <sys/mman.h>
32 #include <fnmatch.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <getopt.h>
36 #include <ctype.h>
37 #include <sys/time.h>
38 #include "utils.h"
39 #include "xs_lib.h"
40 #include "xs.h"
41 #include "list.h"
43 #define XSTEST
45 static struct xs_handle *handles[10] = { NULL };
46 static xs_transaction_t txh[10] = { XBT_NULL };
48 static unsigned int timeout_ms = 500;
49 static bool timeout_suppressed = true;
50 static bool readonly = false;
51 static bool print_input = false;
52 static unsigned int linenum = 0;
54 static int daemon_pid;
55 static struct xenstore_domain_interface *interface;
57 /* FIXME: Mark connection as broken (close it?) when this happens. */
58 static bool check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
59 {
60 return ((prod - cons) <= XENSTORE_RING_SIZE);
61 }
63 static void *get_output_chunk(XENSTORE_RING_IDX cons,
64 XENSTORE_RING_IDX prod,
65 char *buf, uint32_t *len)
66 {
67 *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
68 if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
69 *len = XENSTORE_RING_SIZE - (prod - cons);
70 return buf + MASK_XENSTORE_IDX(prod);
71 }
73 static const void *get_input_chunk(XENSTORE_RING_IDX cons,
74 XENSTORE_RING_IDX prod,
75 const char *buf, uint32_t *len)
76 {
77 *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
78 if ((prod - cons) < *len)
79 *len = prod - cons;
80 return buf + MASK_XENSTORE_IDX(cons);
81 }
83 /* FIXME: We spin, and we're sloppy. */
84 static bool read_all_shmem(int fd __attribute__((unused)),
85 void *data, unsigned int len)
86 {
87 unsigned int avail;
88 struct xenstore_domain_interface *intf = interface;
89 XENSTORE_RING_IDX cons, prod;
90 const void *src;
92 while (len) {
93 cons = intf->rsp_cons;
94 prod = intf->rsp_prod;
95 if (!check_indexes(cons, prod))
96 barf("Corrupt buffer");
98 src = get_input_chunk(cons, prod, intf->rsp, &avail);
99 if (avail > len)
100 avail = len;
101 memcpy(data, src, avail);
102 data += avail;
103 len -= avail;
104 intf->rsp_cons += avail;
105 }
107 /* Tell other end we read something. */
108 kill(daemon_pid, SIGUSR2);
110 return true;
111 }
113 static bool write_all_shmem(int fd __attribute__((unused)),
114 const void *data, unsigned int len)
115 {
116 uint32_t avail;
117 struct xenstore_domain_interface *intf = interface;
118 XENSTORE_RING_IDX cons, prod;
119 void *dst;
121 while (len) {
122 cons = intf->req_cons;
123 prod = intf->req_prod;
124 if (!check_indexes(cons, prod))
125 barf("Corrupt buffer");
127 dst = get_output_chunk(cons, prod, intf->req, &avail);
128 if (avail > len)
129 avail = len;
130 memcpy(dst, data, avail);
131 data += avail;
132 len -= avail;
133 intf->req_prod += avail;
134 }
136 /* Tell other end we wrote something. */
137 kill(daemon_pid, SIGUSR2);
139 return true;
140 }
142 static bool read_all(int fd, void *data, unsigned int len);
143 static bool read_all_choice(int fd, void *data, unsigned int len)
144 {
145 if (fd == -2)
146 return read_all_shmem(fd, data, len);
147 return read_all(fd, data, len);
148 }
150 static bool write_all_choice(int fd, const void *data, unsigned int len)
151 {
152 if (fd == -2)
153 return write_all_shmem(fd, data, len);
154 return xs_write_all(fd, data, len);
155 }
157 /* We want access to internal functions. */
158 #include "xs.c"
160 static void __attribute__((noreturn)) usage(void)
161 {
162 barf("Usage:\n"
163 " xs_test [--readonly] [--no-timeout] [-x]\n"
164 "Reads commands from stdin, one per line:"
165 " dir <path>\n"
166 " read <path>\n"
167 " write <path> <value>...\n"
168 " setid <id>\n"
169 " mkdir <path>\n"
170 " rm <path>\n"
171 " getperm <path>\n"
172 " setperm <path> <id> <flags> ...\n"
173 " watch <path> <token>\n"
174 " watchnoack <path> <token>\n"
175 " waitwatch\n"
176 " unwatch <path> <token>\n"
177 " close\n"
178 " start <node>\n"
179 " abort\n"
180 " introduce <domid> <mfn> <eventchn> <path>\n"
181 " commit\n"
182 " sleep <milliseconds>\n"
183 " expect <pattern>\n"
184 " notimeout\n"
185 " readonly\n"
186 " readwrite\n"
187 " dump\n");
188 }
190 static int argpos(const char *line, unsigned int num)
191 {
192 unsigned int i, len = 0, off = 0;
194 for (i = 0; i <= num; i++) {
195 off += len;
196 off += strspn(line + off, " \t\n");
197 len = strcspn(line + off, " \t\n");
198 if (!len)
199 return off;
200 }
201 return off;
202 }
204 static char *arg(const char *line, unsigned int num)
205 {
206 static char *args[10];
207 unsigned int off, len;
209 off = argpos(line, num);
210 len = strcspn(line + off, " \t\n");
212 if (!len)
213 barf("Can't get arg %u", num);
215 free(args[num]);
216 args[num] = malloc(len + 1);
217 memcpy(args[num], line+off, len);
218 args[num][len] = '\0';
219 return args[num];
220 }
222 struct expect
223 {
224 struct list_head list;
225 char *pattern;
226 };
227 static LIST_HEAD(expects);
229 static char *command;
231 /* Trim leading and trailing whitespace */
232 static void trim(char *str)
233 {
234 while (isspace(str[0]))
235 memmove(str, str+1, strlen(str));
237 while (strlen(str) && isspace(str[strlen(str)-1]))
238 str[strlen(str)-1] = '\0';
239 }
241 static void output(const char *fmt, ...)
242 {
243 char *str;
244 struct expect *i;
245 va_list arglist;
247 va_start(arglist, fmt);
248 vasprintf(&str, fmt, arglist);
249 va_end(arglist);
251 printf("%s", str);
252 fflush(stdout);
253 trim(str);
254 list_for_each_entry(i, &expects, list) {
255 if (fnmatch(i->pattern, str, 0) == 0) {
256 list_del(&i->list);
257 free(i);
258 return;
259 }
260 }
261 barf("Unexpected output %s\n", str);
262 }
264 static void failed(int handle)
265 {
266 if (handle)
267 output("%i: %s failed: %s\n",
268 handle, command, strerror(errno));
269 else
270 output("%s failed: %s\n", command, strerror(errno));
271 }
273 static void expect(const char *line)
274 {
275 struct expect *e = malloc(sizeof(*e));
277 e->pattern = strdup(line + argpos(line, 1));
278 trim(e->pattern);
279 list_add(&e->list, &expects);
280 }
282 static void do_dir(unsigned int handle, char *path)
283 {
284 char **entries;
285 unsigned int i, num;
287 entries = xs_directory(handles[handle], txh[handle], path, &num);
288 if (!entries) {
289 failed(handle);
290 return;
291 }
293 for (i = 0; i < num; i++)
294 if (handle)
295 output("%i:%s\n", handle, entries[i]);
296 else
297 output("%s\n", entries[i]);
298 free(entries);
299 }
301 static void do_read(unsigned int handle, char *path)
302 {
303 char *value;
304 unsigned int len;
306 value = xs_read(handles[handle], txh[handle], path, &len);
307 if (!value) {
308 failed(handle);
309 return;
310 }
312 /* It's supposed to nul terminate for us. */
313 assert(value[len] == '\0');
314 if (handle)
315 output("%i:%.*s\n", handle, len, value);
316 else
317 output("%.*s\n", len, value);
318 }
320 static void do_write(unsigned int handle, char *path, char *data)
321 {
322 if (!xs_write(handles[handle], txh[handle], path, data, strlen(data)))
323 failed(handle);
324 }
326 static void do_setid(unsigned int handle, char *id)
327 {
328 if (!xs_bool(xs_debug_command(handles[handle], "setid", id,
329 strlen(id)+1)))
330 failed(handle);
331 }
333 static void do_mkdir(unsigned int handle, char *path)
334 {
335 if (!xs_mkdir(handles[handle], txh[handle], path))
336 failed(handle);
337 }
339 static void do_rm(unsigned int handle, char *path)
340 {
341 if (!xs_rm(handles[handle], txh[handle], path))
342 failed(handle);
343 }
345 static void do_getperm(unsigned int handle, char *path)
346 {
347 unsigned int i, num;
348 struct xs_permissions *perms;
350 perms = xs_get_permissions(handles[handle], txh[handle], path, &num);
351 if (!perms) {
352 failed(handle);
353 return;
354 }
356 for (i = 0; i < num; i++) {
357 char *permstring;
359 switch (perms[i].perms) {
360 case XS_PERM_NONE:
361 permstring = "NONE";
362 break;
363 case XS_PERM_WRITE:
364 permstring = "WRITE";
365 break;
366 case XS_PERM_READ:
367 permstring = "READ";
368 break;
369 case XS_PERM_READ|XS_PERM_WRITE:
370 permstring = "READ/WRITE";
371 break;
372 default:
373 barf("bad perm value %i", perms[i].perms);
374 }
376 if (handle)
377 output("%i:%i %s\n", handle, perms[i].id, permstring);
378 else
379 output("%i %s\n", perms[i].id, permstring);
380 }
381 free(perms);
382 }
384 static void do_setperm(unsigned int handle, char *path, char *line)
385 {
386 unsigned int i;
387 struct xs_permissions perms[100];
389 strtok(line, " \t\n");
390 strtok(NULL, " \t\n");
391 for (i = 0; ; i++) {
392 char *arg = strtok(NULL, " \t\n");
393 if (!arg)
394 break;
395 perms[i].id = atoi(arg);
396 arg = strtok(NULL, " \t\n");
397 if (!arg)
398 break;
399 if (streq(arg, "WRITE"))
400 perms[i].perms = XS_PERM_WRITE;
401 else if (streq(arg, "READ"))
402 perms[i].perms = XS_PERM_READ;
403 else if (streq(arg, "READ/WRITE"))
404 perms[i].perms = XS_PERM_READ|XS_PERM_WRITE;
405 else if (streq(arg, "NONE"))
406 perms[i].perms = XS_PERM_NONE;
407 else
408 barf("bad flags %s\n", arg);
409 }
411 if (!xs_set_permissions(handles[handle], txh[handle], path, perms, i))
412 failed(handle);
413 }
415 static void do_watch(unsigned int handle, const char *node, const char *token,
416 bool swallow_event)
417 {
418 if (!xs_watch(handles[handle], node, token))
419 failed(handle);
421 /* Convenient for testing... */
422 if (swallow_event) {
423 unsigned int num;
424 char **vec = xs_read_watch(handles[handle], &num);
425 if (!vec ||
426 !streq(vec[XS_WATCH_PATH], node) ||
427 !streq(vec[XS_WATCH_TOKEN], token))
428 failed(handle);
429 }
430 }
432 static void set_timeout(void)
433 {
434 struct itimerval timeout;
436 timeout.it_value.tv_sec = timeout_ms / 1000;
437 timeout.it_value.tv_usec = (timeout_ms * 1000) % 1000000;
438 timeout.it_interval.tv_sec = timeout.it_interval.tv_usec = 0;
439 setitimer(ITIMER_REAL, &timeout, NULL);
440 }
442 static void disarm_timeout(void)
443 {
444 struct itimerval timeout;
446 timeout.it_value.tv_sec = 0;
447 timeout.it_value.tv_usec = 0;
448 setitimer(ITIMER_REAL, &timeout, NULL);
449 }
451 static void do_waitwatch(unsigned int handle)
452 {
453 char **vec;
454 struct timeval tv = {.tv_sec = timeout_ms/1000,
455 .tv_usec = (timeout_ms*1000)%1000000 };
456 fd_set set;
457 unsigned int num;
459 if (xs_fileno(handles[handle]) != -2) {
460 /* Manually select here so we can time out gracefully. */
461 FD_ZERO(&set);
462 FD_SET(xs_fileno(handles[handle]), &set);
463 disarm_timeout();
464 if (select(xs_fileno(handles[handle])+1, &set,
465 NULL, NULL, &tv) == 0) {
466 errno = ETIMEDOUT;
467 failed(handle);
468 return;
469 }
470 set_timeout();
471 }
473 vec = xs_read_watch(handles[handle], &num);
474 if (!vec) {
475 failed(handle);
476 return;
477 }
479 if (handle)
480 output("%i:%s:%s\n", handle,
481 vec[XS_WATCH_PATH], vec[XS_WATCH_TOKEN]);
482 else
483 output("%s:%s\n", vec[XS_WATCH_PATH], vec[XS_WATCH_TOKEN]);
484 free(vec);
485 }
487 static void do_unwatch(unsigned int handle, const char *node, const char *token)
488 {
489 if (!xs_unwatch(handles[handle], node, token))
490 failed(handle);
491 }
493 static void do_start(unsigned int handle)
494 {
495 txh[handle] = xs_transaction_start(handles[handle]);
496 if (txh[handle] == XBT_NULL)
497 failed(handle);
498 }
500 static void do_end(unsigned int handle, bool abort)
501 {
502 if (!xs_transaction_end(handles[handle], txh[handle], abort))
503 failed(handle);
504 txh[handle] = XBT_NULL;
505 }
507 static void do_introduce(unsigned int handle,
508 const char *domid,
509 const char *mfn,
510 const char *eventchn,
511 const char *path)
512 {
513 unsigned int i;
514 int fd;
516 /* This mechanism is v. slow w. valgrind running. */
517 timeout_ms = 5000;
519 /* We poll, so ignore signal */
520 signal(SIGUSR2, SIG_IGN);
521 for (i = 0; i < ARRAY_SIZE(handles); i++)
522 if (!handles[i])
523 break;
525 fd = open("/tmp/xcmap", O_RDWR);
526 /* Set shared comms page. */
527 interface = mmap(NULL, getpagesize(), PROT_WRITE|PROT_READ,
528 MAP_SHARED,fd,0);
529 if (interface == MAP_FAILED)
530 barf_perror("Failed to map /tmp/xcmap page");
531 close(fd);
533 /* Tell them the event channel and our PID. */
534 *(int *)((void *)interface + 32) = getpid();
535 *(uint16_t *)((void *)interface + 36) = atoi(eventchn);
537 if (!xs_introduce_domain(handles[handle], atoi(domid),
538 atol(mfn), atoi(eventchn))) {
539 failed(handle);
540 munmap(interface, getpagesize());
541 return;
542 }
543 output("handle is %i\n", i);
545 /* Create new handle. */
546 handles[i] = new(struct xs_handle);
547 handles[i]->fd = -2;
549 /* Read in daemon pid. */
550 daemon_pid = *(int *)((void *)interface + 32);
551 }
553 static void do_release(unsigned int handle, const char *domid)
554 {
555 if (!xs_release_domain(handles[handle], atoi(domid)))
556 failed(handle);
557 }
559 static int strptrcmp(const void *a, const void *b)
560 {
561 return strcmp(*(char **)a, *(char **)b);
562 }
564 static void sort_dir(char **dir, unsigned int num)
565 {
566 qsort(dir, num, sizeof(char *), strptrcmp);
567 }
569 static void dump_dir(unsigned int handle,
570 const char *node,
571 char **dir,
572 unsigned int numdirs,
573 unsigned int depth)
574 {
575 unsigned int i;
576 char spacing[depth+1];
578 memset(spacing, ' ', depth);
579 spacing[depth] = '\0';
581 sort_dir(dir, numdirs);
583 for (i = 0; i < numdirs; i++) {
584 struct xs_permissions *perms;
585 unsigned int j, numperms;
586 unsigned int len;
587 char *contents;
588 unsigned int subnum;
589 char **subdirs;
590 char subnode[strlen(node) + 1 + strlen(dir[i]) + 1];
592 sprintf(subnode, "%s/%s", node, dir[i]);
594 perms = xs_get_permissions(handles[handle], txh[handle],
595 subnode,&numperms);
596 if (!perms) {
597 failed(handle);
598 return;
599 }
601 output("%s%s: ", spacing, dir[i]);
602 for (j = 0; j < numperms; j++) {
603 char buffer[100];
604 if (!xs_perm_to_string(&perms[j], buffer))
605 barf("perm to string");
606 output("%s ", buffer);
607 }
608 free(perms);
609 output("\n");
611 /* Even directories can have contents. */
612 contents = xs_read(handles[handle], txh[handle],
613 subnode, &len);
614 if (!contents) {
615 if (errno != EISDIR)
616 failed(handle);
617 } else {
618 output(" %s(%.*s)\n", spacing, len, contents);
619 free(contents);
620 }
622 /* Every node is a directory. */
623 subdirs = xs_directory(handles[handle], txh[handle],
624 subnode, &subnum);
625 if (!subdirs) {
626 failed(handle);
627 return;
628 }
629 dump_dir(handle, subnode, subdirs, subnum, depth+1);
630 free(subdirs);
631 }
632 }
634 static void dump(int handle)
635 {
636 char **subdirs;
637 unsigned int subnum;
639 subdirs = xs_directory(handles[handle], txh[handle], "/", &subnum);
640 if (!subdirs) {
641 failed(handle);
642 return;
643 }
645 dump_dir(handle, "", subdirs, subnum, 0);
646 free(subdirs);
647 }
649 static int handle;
651 static void alarmed(int sig __attribute__((unused)))
652 {
653 if (handle) {
654 char handlename[10];
655 sprintf(handlename, "%u:", handle);
656 write(STDOUT_FILENO, handlename, strlen(handlename));
657 }
658 write(STDOUT_FILENO, command, strlen(command));
659 write(STDOUT_FILENO, " timeout\n", strlen(" timeout\n"));
660 exit(1);
661 }
663 static void do_command(unsigned int default_handle, char *line)
664 {
665 char *endp;
667 if (print_input)
668 printf("%i> %s", ++linenum, line);
670 if (strspn(line, " \n") == strlen(line))
671 return;
672 if (strstarts(line, "#"))
673 return;
675 handle = strtoul(line, &endp, 10);
676 if (endp != line)
677 memmove(line, endp+1, strlen(endp));
678 else
679 handle = default_handle;
681 command = arg(line, 0);
682 if (!handles[handle]) {
683 if (readonly)
684 handles[handle] = xs_daemon_open_readonly();
685 else
686 handles[handle] = xs_daemon_open();
687 if (!handles[handle])
688 barf_perror("Opening connection to daemon");
689 }
691 if (!timeout_suppressed)
692 set_timeout();
693 timeout_suppressed = false;
695 if (streq(command, "dir"))
696 do_dir(handle, arg(line, 1));
697 else if (streq(command, "read"))
698 do_read(handle, arg(line, 1));
699 else if (streq(command, "write"))
700 do_write(handle, arg(line, 1), arg(line, 2));
701 else if (streq(command, "setid"))
702 do_setid(handle, arg(line, 1));
703 else if (streq(command, "mkdir"))
704 do_mkdir(handle, arg(line, 1));
705 else if (streq(command, "rm"))
706 do_rm(handle, arg(line, 1));
707 else if (streq(command, "getperm"))
708 do_getperm(handle, arg(line, 1));
709 else if (streq(command, "setperm"))
710 do_setperm(handle, arg(line, 1), line);
711 else if (streq(command, "watch"))
712 do_watch(handle, arg(line, 1), arg(line, 2), true);
713 else if (streq(command, "watchnoack"))
714 do_watch(handle, arg(line, 1), arg(line, 2), false);
715 else if (streq(command, "waitwatch"))
716 do_waitwatch(handle);
717 else if (streq(command, "unwatch"))
718 do_unwatch(handle, arg(line, 1), arg(line, 2));
719 else if (streq(command, "close")) {
720 xs_daemon_close(handles[handle]);
721 handles[handle] = NULL;
722 txh[handle] = XBT_NULL;
723 } else if (streq(command, "start"))
724 do_start(handle);
725 else if (streq(command, "commit"))
726 do_end(handle, false);
727 else if (streq(command, "abort"))
728 do_end(handle, true);
729 else if (streq(command, "introduce"))
730 do_introduce(handle, arg(line, 1), arg(line, 2),
731 arg(line, 3), arg(line, 4));
732 else if (streq(command, "release"))
733 do_release(handle, arg(line, 1));
734 else if (streq(command, "dump"))
735 dump(handle);
736 else if (streq(command, "sleep")) {
737 disarm_timeout();
738 usleep(atoi(arg(line, 1)) * 1000);
739 } else if (streq(command, "expect"))
740 expect(line);
741 else if (streq(command, "notimeout"))
742 timeout_suppressed = true;
743 else if (streq(command, "readonly")) {
744 readonly = true;
745 xs_daemon_close(handles[handle]);
746 handles[handle] = NULL;
747 } else if (streq(command, "readwrite")) {
748 readonly = false;
749 xs_daemon_close(handles[handle]);
750 handles[handle] = NULL;
751 } else
752 barf("Unknown command %s", command);
753 fflush(stdout);
754 disarm_timeout();
756 /* Check expectations. */
757 if (!streq(command, "expect")) {
758 struct expect *i = list_top(&expects, struct expect, list);
760 if (i)
761 barf("Expected '%s', didn't happen\n", i->pattern);
762 }
763 }
765 static struct option options[] = { { "readonly", 0, NULL, 'r' },
766 { "no-timeout", 0, NULL, 't' },
767 { NULL, 0, NULL, 0 } };
769 int main(int argc, char *argv[])
770 {
771 int opt;
772 char line[1024];
774 while ((opt = getopt_long(argc, argv, "xrt", options, NULL)) != -1) {
775 switch (opt) {
776 case 'r':
777 readonly = true;
778 break;
779 case 't':
780 timeout_ms = 0;
781 break;
782 case 'x':
783 print_input = true;
784 break;
785 }
786 }
788 if (optind + 1 == argc) {
789 int fd = open(argv[optind], O_RDONLY);
790 if (!fd)
791 barf_perror("Opening %s", argv[optind]);
792 dup2(fd, STDIN_FILENO);
793 } else if (optind != argc)
794 usage();
797 signal(SIGALRM, alarmed);
798 while (fgets(line, sizeof(line), stdin))
799 do_command(0, line);
801 return 0;
802 }
804 /*
805 * Local variables:
806 * c-file-style: "linux"
807 * indent-tabs-mode: t
808 * c-indent-level: 8
809 * c-basic-offset: 8
810 * tab-width: 8
811 * End:
812 */