xen-vtx-unstable

annotate tools/xenstore/xs_test.c @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents f804b28871ba dd668f7527cb
children e7c7196fa329 8ca0f98ba8e2
rev   line source
cl349@5357 1 /*
cl349@5357 2 Xen Store Daemon Test tool
cl349@5357 3 Copyright (C) 2005 Rusty Russell IBM Corporation
cl349@5357 4
cl349@5357 5 This program is free software; you can redistribute it and/or modify
cl349@5357 6 it under the terms of the GNU General Public License as published by
cl349@5357 7 the Free Software Foundation; either version 2 of the License, or
cl349@5357 8 (at your option) any later version.
cl349@5357 9
cl349@5357 10 This program is distributed in the hope that it will be useful,
cl349@5357 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
cl349@5357 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
cl349@5357 13 GNU General Public License for more details.
cl349@5357 14
cl349@5357 15 You should have received a copy of the GNU General Public License
cl349@5357 16 along with this program; if not, write to the Free Software
cl349@5357 17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
cl349@5357 18 */
cl349@5357 19
kaf24@6024 20 #define _GNU_SOURCE
cl349@5357 21 #include <stdio.h>
cl349@5357 22 #include <stdlib.h>
cl349@5357 23 #include <sys/types.h>
cl349@5856 24 #include <sys/wait.h>
cl349@5357 25 #include <sys/stat.h>
cl349@5357 26 #include <fcntl.h>
cl349@5357 27 #include <signal.h>
cl349@5357 28 #include <stdint.h>
cl349@5357 29 #include <stdbool.h>
cl349@5357 30 #include <stdlib.h>
kaf24@6043 31 #include <sys/mman.h>
kaf24@6024 32 #include <fnmatch.h>
kaf24@6024 33 #include <stdarg.h>
kaf24@6024 34 #include <string.h>
kaf24@6024 35 #include <getopt.h>
kaf24@6024 36 #include <ctype.h>
kaf24@6024 37 #include <sys/time.h>
cl349@5357 38 #include "utils.h"
cl349@5357 39 #include "xs_lib.h"
kaf24@6024 40 #include "list.h"
cl349@5357 41
cl349@5357 42 #define XSTEST
cl349@5357 43
cl349@5357 44 static struct xs_handle *handles[10] = { NULL };
cl349@5856 45
cl349@6752 46 static unsigned int timeout_ms = 500;
kaf24@6024 47 static bool timeout_suppressed = true;
cl349@5856 48 static bool readonly = false;
kaf24@6024 49 static bool print_input = false;
kaf24@6024 50 static unsigned int linenum = 0;
cl349@5357 51
cl349@5357 52 struct ringbuf_head
cl349@5357 53 {
cl349@5357 54 uint32_t write; /* Next place to write to */
cl349@5357 55 uint32_t read; /* Next place to read from */
cl349@5357 56 uint8_t flags;
cl349@5357 57 char buf[0];
cl349@5357 58 } __attribute__((packed));
cl349@5357 59
cl349@5357 60 static struct ringbuf_head *out, *in;
cl349@5357 61 static unsigned int ringbuf_datasize;
cl349@5357 62 static int daemon_pid;
cl349@5357 63
cl349@5357 64 /* FIXME: Mark connection as broken (close it?) when this happens. */
cl349@5357 65 static bool check_buffer(const struct ringbuf_head *h)
cl349@5357 66 {
cl349@5357 67 return (h->write < ringbuf_datasize && h->read < ringbuf_datasize);
cl349@5357 68 }
cl349@5357 69
cl349@5357 70 /* We can't fill last byte: would look like empty buffer. */
cl349@5357 71 static void *get_output_chunk(const struct ringbuf_head *h,
cl349@5357 72 void *buf, uint32_t *len)
cl349@5357 73 {
cl349@5357 74 uint32_t read_mark;
cl349@5357 75
cl349@5357 76 if (h->read == 0)
cl349@5357 77 read_mark = ringbuf_datasize - 1;
cl349@5357 78 else
cl349@5357 79 read_mark = h->read - 1;
cl349@5357 80
cl349@5357 81 /* Here to the end of buffer, unless they haven't read some out. */
cl349@5357 82 *len = ringbuf_datasize - h->write;
cl349@5357 83 if (read_mark >= h->write)
cl349@5357 84 *len = read_mark - h->write;
cl349@5357 85 return buf + h->write;
cl349@5357 86 }
cl349@5357 87
cl349@5357 88 static const void *get_input_chunk(const struct ringbuf_head *h,
cl349@5357 89 const void *buf, uint32_t *len)
cl349@5357 90 {
cl349@5357 91 /* Here to the end of buffer, unless they haven't written some. */
cl349@5357 92 *len = ringbuf_datasize - h->read;
cl349@5357 93 if (h->write >= h->read)
cl349@5357 94 *len = h->write - h->read;
cl349@5357 95 return buf + h->read;
cl349@5357 96 }
cl349@5357 97
cl349@5859 98 static int output_avail(struct ringbuf_head *out)
cl349@5859 99 {
cl349@5859 100 unsigned int avail;
cl349@5859 101
cl349@5859 102 get_output_chunk(out, out->buf, &avail);
cl349@5859 103 return avail != 0;
cl349@5859 104 }
cl349@5859 105
cl349@5357 106 static void update_output_chunk(struct ringbuf_head *h, uint32_t len)
cl349@5357 107 {
cl349@5357 108 h->write += len;
cl349@5357 109 if (h->write == ringbuf_datasize)
cl349@5357 110 h->write = 0;
cl349@5357 111 }
cl349@5357 112
cl349@5357 113 static void update_input_chunk(struct ringbuf_head *h, uint32_t len)
cl349@5357 114 {
cl349@5357 115 h->read += len;
cl349@5357 116 if (h->read == ringbuf_datasize)
cl349@5357 117 h->read = 0;
cl349@5357 118 }
cl349@5357 119
cl349@5357 120 /* FIXME: We spin, and we're sloppy. */
cl349@5357 121 static bool read_all_shmem(int fd __attribute__((unused)),
cl349@5357 122 void *data, unsigned int len)
cl349@5357 123 {
cl349@5357 124 unsigned int avail;
cl349@5859 125 int was_full;
cl349@5357 126
cl349@5357 127 if (!check_buffer(in))
cl349@5357 128 barf("Corrupt buffer");
cl349@5357 129
cl349@5859 130 was_full = !output_avail(in);
cl349@5357 131 while (len) {
cl349@5357 132 const void *src = get_input_chunk(in, in->buf, &avail);
cl349@5357 133 if (avail > len)
cl349@5357 134 avail = len;
cl349@5357 135 memcpy(data, src, avail);
cl349@5357 136 data += avail;
cl349@5357 137 len -= avail;
cl349@5357 138 update_input_chunk(in, avail);
cl349@5357 139 }
cl349@5357 140
cl349@5357 141 /* Tell other end we read something. */
cl349@5859 142 if (was_full)
cl349@5859 143 kill(daemon_pid, SIGUSR2);
cl349@5357 144 return true;
cl349@5357 145 }
cl349@5357 146
cl349@5357 147 static bool write_all_shmem(int fd __attribute__((unused)),
cl349@5357 148 const void *data, unsigned int len)
cl349@5357 149 {
cl349@5357 150 uint32_t avail;
cl349@5357 151
cl349@5357 152 if (!check_buffer(out))
cl349@5357 153 barf("Corrupt buffer");
cl349@5357 154
cl349@5357 155 while (len) {
cl349@5357 156 void *dst = get_output_chunk(out, out->buf, &avail);
cl349@5357 157 if (avail > len)
cl349@5357 158 avail = len;
cl349@5357 159 memcpy(dst, data, avail);
cl349@5357 160 data += avail;
cl349@5357 161 len -= avail;
cl349@5357 162 update_output_chunk(out, avail);
cl349@5357 163 }
cl349@5357 164
cl349@5357 165 /* Tell other end we wrote something. */
cl349@5357 166 kill(daemon_pid, SIGUSR2);
cl349@5357 167 return true;
cl349@5357 168 }
cl349@5357 169
cl349@5357 170 static bool read_all(int fd, void *data, unsigned int len);
cl349@5357 171 static bool read_all_choice(int fd, void *data, unsigned int len)
cl349@5357 172 {
cl349@5357 173 if (fd == -2)
cl349@5357 174 return read_all_shmem(fd, data, len);
cl349@5357 175 return read_all(fd, data, len);
cl349@5357 176 }
cl349@5357 177
cl349@5357 178 static bool write_all_choice(int fd, const void *data, unsigned int len)
cl349@5357 179 {
cl349@5357 180 if (fd == -2)
cl349@5357 181 return write_all_shmem(fd, data, len);
kaf24@5423 182 return xs_write_all(fd, data, len);
cl349@5357 183 }
cl349@5357 184
cl349@5357 185 /* We want access to internal functions. */
cl349@5357 186 #include "xs.c"
cl349@5357 187
cl349@5357 188 static void __attribute__((noreturn)) usage(void)
cl349@5357 189 {
cl349@5357 190 barf("Usage:\n"
kaf24@6024 191 " xs_test [--readonly] [--no-timeout] [-x]\n"
cl349@5357 192 "Reads commands from stdin, one per line:"
cl349@5357 193 " dir <path>\n"
cl349@5357 194 " read <path>\n"
cl349@5357 195 " write <path> <flags> <value>...\n"
cl349@5357 196 " setid <id>\n"
cl349@5357 197 " mkdir <path>\n"
cl349@5357 198 " rm <path>\n"
cl349@5357 199 " getperm <path>\n"
cl349@5357 200 " setperm <path> <id> <flags> ...\n"
cl349@5357 201 " shutdown\n"
cl349@5856 202 " watch <path> <token>\n"
cl349@5357 203 " waitwatch\n"
cl349@5478 204 " ackwatch <token>\n"
kaf24@5426 205 " unwatch <path> <token>\n"
cl349@5357 206 " close\n"
cl349@5357 207 " start <node>\n"
cl349@5357 208 " abort\n"
kaf24@5426 209 " introduce <domid> <mfn> <eventchn> <path>\n"
cl349@5357 210 " commit\n"
kaf24@6024 211 " sleep <milliseconds>\n"
kaf24@6024 212 " expect <pattern>\n"
kaf24@6024 213 " notimeout\n"
kaf24@6024 214 " readonly\n"
kaf24@6024 215 " readwrite\n"
kaf24@6043 216 " noackwrite <path> <flags> <value>...\n"
kaf24@6043 217 " readack\n"
cl349@5357 218 " dump\n");
cl349@5357 219 }
cl349@5357 220
cl349@5856 221 static int argpos(const char *line, unsigned int num)
cl349@5856 222 {
cl349@5856 223 unsigned int i, len = 0, off = 0;
cl349@5856 224
cl349@5856 225 for (i = 0; i <= num; i++) {
cl349@5856 226 off += len;
cl349@5856 227 off += strspn(line + off, " \t\n");
cl349@5856 228 len = strcspn(line + off, " \t\n");
cl349@5856 229 if (!len)
cl349@5856 230 return off;
cl349@5856 231 }
cl349@5856 232 return off;
cl349@5856 233 }
cl349@5856 234
kaf24@6024 235 static char *arg(const char *line, unsigned int num)
cl349@5357 236 {
cl349@5357 237 static char *args[10];
cl349@5856 238 unsigned int off, len;
cl349@5357 239
cl349@5856 240 off = argpos(line, num);
cl349@5856 241 len = strcspn(line + off, " \t\n");
cl349@5856 242
cl349@5856 243 if (!len)
cl349@5856 244 barf("Can't get arg %u", num);
cl349@5357 245
cl349@5357 246 free(args[num]);
cl349@5357 247 args[num] = malloc(len + 1);
cl349@5856 248 memcpy(args[num], line+off, len);
cl349@5357 249 args[num][len] = '\0';
cl349@5357 250 return args[num];
cl349@5357 251 }
cl349@5357 252
kaf24@6024 253 struct expect
kaf24@6024 254 {
kaf24@6024 255 struct list_head list;
kaf24@6024 256 char *pattern;
kaf24@6024 257 };
kaf24@6024 258 static LIST_HEAD(expects);
kaf24@6024 259
cl349@5357 260 static char *command;
kaf24@6024 261
kaf24@6024 262 /* Trim leading and trailing whitespace */
kaf24@6024 263 static void trim(char *str)
kaf24@6024 264 {
kaf24@6024 265 while (isspace(str[0]))
kaf24@6024 266 memmove(str, str+1, strlen(str));
kaf24@6024 267
kaf24@6024 268 while (strlen(str) && isspace(str[strlen(str)-1]))
kaf24@6024 269 str[strlen(str)-1] = '\0';
kaf24@6024 270 }
kaf24@6024 271
kaf24@6024 272 static void output(const char *fmt, ...)
kaf24@6024 273 {
kaf24@6024 274 char *str;
kaf24@6024 275 struct expect *i;
kaf24@6024 276 va_list arglist;
kaf24@6024 277
kaf24@6024 278 va_start(arglist, fmt);
kaf24@6024 279 vasprintf(&str, fmt, arglist);
kaf24@6024 280 va_end(arglist);
kaf24@6024 281
kaf24@6024 282 printf("%s", str);
kaf24@6024 283 fflush(stdout);
kaf24@6024 284 trim(str);
kaf24@6024 285 list_for_each_entry(i, &expects, list) {
kaf24@6024 286 if (fnmatch(i->pattern, str, 0) == 0) {
kaf24@6024 287 list_del(&i->list);
kaf24@6024 288 free(i);
kaf24@6024 289 return;
kaf24@6024 290 }
kaf24@6024 291 }
kaf24@6024 292 barf("Unexpected output %s\n", str);
kaf24@6024 293 }
kaf24@6024 294
kaf24@6024 295 static void failed(int handle)
cl349@5357 296 {
cl349@5357 297 if (handle)
kaf24@6024 298 output("%i: %s failed: %s\n",
kaf24@6024 299 handle, command, strerror(errno));
kaf24@6024 300 else
kaf24@6024 301 output("%s failed: %s\n", command, strerror(errno));
kaf24@6024 302 }
kaf24@6024 303
kaf24@6024 304 static void expect(const char *line)
kaf24@6024 305 {
kaf24@6024 306 struct expect *e = malloc(sizeof(*e));
kaf24@6024 307
kaf24@6024 308 e->pattern = strdup(line + argpos(line, 1));
kaf24@6024 309 trim(e->pattern);
kaf24@6024 310 list_add(&e->list, &expects);
cl349@5357 311 }
cl349@5357 312
cl349@5357 313 static void do_dir(unsigned int handle, char *path)
cl349@5357 314 {
cl349@5357 315 char **entries;
cl349@5357 316 unsigned int i, num;
cl349@5357 317
cl349@5357 318 entries = xs_directory(handles[handle], path, &num);
kaf24@6024 319 if (!entries) {
cl349@5357 320 failed(handle);
kaf24@6024 321 return;
kaf24@6024 322 }
cl349@5357 323
cl349@5357 324 for (i = 0; i < num; i++)
cl349@5357 325 if (handle)
kaf24@6024 326 output("%i:%s\n", handle, entries[i]);
cl349@5357 327 else
kaf24@6024 328 output("%s\n", entries[i]);
cl349@5357 329 free(entries);
cl349@5357 330 }
cl349@5357 331
cl349@5357 332 static void do_read(unsigned int handle, char *path)
cl349@5357 333 {
cl349@5357 334 char *value;
cl349@5357 335 unsigned int len;
cl349@5357 336
cl349@5357 337 value = xs_read(handles[handle], path, &len);
kaf24@6024 338 if (!value) {
cl349@5357 339 failed(handle);
kaf24@6024 340 return;
kaf24@6024 341 }
cl349@5357 342
cl349@5522 343 /* It's supposed to nul terminate for us. */
cl349@5522 344 assert(value[len] == '\0');
cl349@5357 345 if (handle)
kaf24@6024 346 output("%i:%.*s\n", handle, len, value);
cl349@5357 347 else
kaf24@6024 348 output("%.*s\n", len, value);
cl349@5357 349 }
cl349@5357 350
cl349@5357 351 static void do_write(unsigned int handle, char *path, char *flags, char *data)
cl349@5357 352 {
cl349@5357 353 int f;
cl349@5357 354
cl349@5357 355 if (streq(flags, "none"))
cl349@5357 356 f = 0;
cl349@5357 357 else if (streq(flags, "create"))
cl349@5357 358 f = O_CREAT;
cl349@5357 359 else if (streq(flags, "excl"))
cl349@5357 360 f = O_CREAT | O_EXCL;
cl349@5357 361 else if (streq(flags, "crap"))
cl349@5357 362 f = 100;
cl349@5357 363 else
cl349@5357 364 barf("write flags 'none', 'create' or 'excl' only");
cl349@5357 365
cl349@5522 366 if (!xs_write(handles[handle], path, data, strlen(data), f))
cl349@5357 367 failed(handle);
cl349@5357 368 }
cl349@5357 369
kaf24@6043 370 static void do_noackwrite(unsigned int handle,
kaf24@6043 371 char *path, const char *flags, char *data)
kaf24@6043 372 {
kaf24@6043 373 struct xsd_sockmsg msg;
kaf24@6043 374
kaf24@6043 375 /* Format: Flags (as string), path, data. */
kaf24@6043 376 if (streq(flags, "none"))
kaf24@6043 377 flags = XS_WRITE_NONE;
kaf24@6043 378 else if (streq(flags, "create"))
kaf24@6043 379 flags = XS_WRITE_CREATE;
kaf24@6043 380 else if (streq(flags, "excl"))
kaf24@6043 381 flags = XS_WRITE_CREATE_EXCL;
kaf24@6043 382 else
kaf24@6043 383 barf("noackwrite flags 'none', 'create' or 'excl' only");
kaf24@6043 384
kaf24@6043 385 msg.len = strlen(path) + 1 + strlen(flags) + 1 + strlen(data);
kaf24@6043 386 msg.type = XS_WRITE;
kaf24@6043 387 if (!write_all_choice(handles[handle]->fd, &msg, sizeof(msg)))
kaf24@6043 388 failed(handle);
kaf24@6043 389 if (!write_all_choice(handles[handle]->fd, path, strlen(path) + 1))
kaf24@6043 390 failed(handle);
kaf24@6043 391 if (!write_all_choice(handles[handle]->fd, flags, strlen(flags) + 1))
kaf24@6043 392 failed(handle);
kaf24@6043 393 if (!write_all_choice(handles[handle]->fd, data, strlen(data)))
kaf24@6043 394 failed(handle);
kaf24@6043 395 /* Do not wait for ack. */
kaf24@6043 396 }
kaf24@6043 397
kaf24@6043 398 static void do_readack(unsigned int handle)
kaf24@6043 399 {
kaf24@6043 400 enum xsd_sockmsg_type type;
kaf24@6043 401 char *ret;
kaf24@6043 402
kaf24@6043 403 ret = read_reply(handles[handle]->fd, &type, NULL);
kaf24@6043 404 if (!ret)
kaf24@6043 405 failed(handle);
kaf24@6043 406 free(ret);
kaf24@6043 407 }
kaf24@6043 408
cl349@5357 409 static void do_setid(unsigned int handle, char *id)
cl349@5357 410 {
cl349@5357 411 if (!xs_bool(xs_debug_command(handles[handle], "setid", id,
cl349@5357 412 strlen(id)+1)))
cl349@5357 413 failed(handle);
cl349@5357 414 }
cl349@5357 415
cl349@5357 416 static void do_mkdir(unsigned int handle, char *path)
cl349@5357 417 {
cl349@5357 418 if (!xs_mkdir(handles[handle], path))
cl349@5357 419 failed(handle);
cl349@5357 420 }
cl349@5357 421
cl349@5357 422 static void do_rm(unsigned int handle, char *path)
cl349@5357 423 {
cl349@5357 424 if (!xs_rm(handles[handle], path))
cl349@5357 425 failed(handle);
cl349@5357 426 }
cl349@5357 427
cl349@5357 428 static void do_getperm(unsigned int handle, char *path)
cl349@5357 429 {
cl349@5357 430 unsigned int i, num;
cl349@5357 431 struct xs_permissions *perms;
cl349@5357 432
cl349@5357 433 perms = xs_get_permissions(handles[handle], path, &num);
kaf24@6024 434 if (!perms) {
cl349@5357 435 failed(handle);
kaf24@6024 436 return;
kaf24@6024 437 }
cl349@5357 438
cl349@5357 439 for (i = 0; i < num; i++) {
cl349@5357 440 char *permstring;
cl349@5357 441
cl349@5357 442 switch (perms[i].perms) {
cl349@5357 443 case XS_PERM_NONE:
cl349@5357 444 permstring = "NONE";
cl349@5357 445 break;
cl349@5357 446 case XS_PERM_WRITE:
cl349@5357 447 permstring = "WRITE";
cl349@5357 448 break;
cl349@5357 449 case XS_PERM_READ:
cl349@5357 450 permstring = "READ";
cl349@5357 451 break;
cl349@5357 452 case XS_PERM_READ|XS_PERM_WRITE:
cl349@5357 453 permstring = "READ/WRITE";
cl349@5357 454 break;
cl349@5357 455 default:
cl349@5357 456 barf("bad perm value %i", perms[i].perms);
cl349@5357 457 }
cl349@5357 458
cl349@5357 459 if (handle)
kaf24@6024 460 output("%i:%i %s\n", handle, perms[i].id, permstring);
cl349@5357 461 else
kaf24@6024 462 output("%i %s\n", perms[i].id, permstring);
cl349@5357 463 }
cl349@5357 464 free(perms);
cl349@5357 465 }
cl349@5357 466
cl349@5357 467 static void do_setperm(unsigned int handle, char *path, char *line)
cl349@5357 468 {
cl349@5357 469 unsigned int i;
cl349@5357 470 struct xs_permissions perms[100];
cl349@5357 471
cl349@5357 472 strtok(line, " \t\n");
cl349@5357 473 strtok(NULL, " \t\n");
cl349@5357 474 for (i = 0; ; i++) {
cl349@5357 475 char *arg = strtok(NULL, " \t\n");
cl349@5357 476 if (!arg)
cl349@5357 477 break;
cl349@5357 478 perms[i].id = atoi(arg);
cl349@5357 479 arg = strtok(NULL, " \t\n");
cl349@5357 480 if (!arg)
cl349@5357 481 break;
cl349@5357 482 if (streq(arg, "WRITE"))
cl349@5357 483 perms[i].perms = XS_PERM_WRITE;
cl349@5357 484 else if (streq(arg, "READ"))
cl349@5357 485 perms[i].perms = XS_PERM_READ;
cl349@5357 486 else if (streq(arg, "READ/WRITE"))
cl349@5357 487 perms[i].perms = XS_PERM_READ|XS_PERM_WRITE;
cl349@5357 488 else if (streq(arg, "NONE"))
cl349@5357 489 perms[i].perms = XS_PERM_NONE;
cl349@5357 490 else
cl349@5357 491 barf("bad flags %s\n", arg);
cl349@5357 492 }
cl349@5357 493
cl349@5357 494 if (!xs_set_permissions(handles[handle], path, perms, i))
cl349@5357 495 failed(handle);
cl349@5357 496 }
cl349@5357 497
cl349@5357 498 static void do_shutdown(unsigned int handle)
cl349@5357 499 {
cl349@5357 500 if (!xs_shutdown(handles[handle]))
cl349@5357 501 failed(handle);
cl349@5357 502 }
cl349@5357 503
cl349@5856 504 static void do_watch(unsigned int handle, const char *node, const char *token)
cl349@5357 505 {
cl349@5856 506 if (!xs_watch(handles[handle], node, token))
cl349@5357 507 failed(handle);
cl349@5357 508 }
cl349@5357 509
kaf24@6043 510 static void set_timeout(void)
kaf24@6043 511 {
kaf24@6043 512 struct itimerval timeout;
kaf24@6043 513
kaf24@6043 514 timeout.it_value.tv_sec = timeout_ms / 1000;
kaf24@6043 515 timeout.it_value.tv_usec = (timeout_ms * 1000) % 1000000;
kaf24@6043 516 timeout.it_interval.tv_sec = timeout.it_interval.tv_usec = 0;
kaf24@6043 517 setitimer(ITIMER_REAL, &timeout, NULL);
kaf24@6043 518 }
kaf24@6043 519
kaf24@6043 520 static void disarm_timeout(void)
kaf24@6043 521 {
kaf24@6043 522 struct itimerval timeout;
kaf24@6043 523
kaf24@6043 524 timeout.it_value.tv_sec = 0;
kaf24@6043 525 timeout.it_value.tv_usec = 0;
kaf24@6043 526 setitimer(ITIMER_REAL, &timeout, NULL);
kaf24@6043 527 }
kaf24@6043 528
cl349@5357 529 static void do_waitwatch(unsigned int handle)
cl349@5357 530 {
cl349@5478 531 char **vec;
kaf24@6024 532 struct timeval tv = {.tv_sec = timeout_ms/1000,
kaf24@6024 533 .tv_usec = (timeout_ms*1000)%1000000 };
kaf24@6024 534 fd_set set;
kaf24@6024 535
kaf24@6024 536 if (xs_fileno(handles[handle]) != -2) {
kaf24@6043 537 /* Manually select here so we can time out gracefully. */
kaf24@6024 538 FD_ZERO(&set);
kaf24@6024 539 FD_SET(xs_fileno(handles[handle]), &set);
kaf24@6043 540 disarm_timeout();
kaf24@6024 541 if (select(xs_fileno(handles[handle])+1, &set,
kaf24@6024 542 NULL, NULL, &tv) == 0) {
kaf24@6024 543 errno = ETIMEDOUT;
kaf24@6024 544 failed(handle);
kaf24@6024 545 return;
kaf24@6024 546 }
kaf24@6043 547 set_timeout();
kaf24@6024 548 }
cl349@5357 549
cl349@5478 550 vec = xs_read_watch(handles[handle]);
kaf24@6024 551 if (!vec) {
cl349@5357 552 failed(handle);
kaf24@6024 553 return;
kaf24@6024 554 }
cl349@5357 555
cl349@5357 556 if (handle)
kaf24@6024 557 output("%i:%s:%s\n", handle, vec[0], vec[1]);
cl349@5357 558 else
kaf24@6024 559 output("%s:%s\n", vec[0], vec[1]);
cl349@5478 560 free(vec);
cl349@5357 561 }
cl349@5357 562
cl349@5478 563 static void do_ackwatch(unsigned int handle, const char *token)
cl349@5357 564 {
cl349@5478 565 if (!xs_acknowledge_watch(handles[handle], token))
cl349@5357 566 failed(handle);
cl349@5357 567 }
cl349@5357 568
cl349@5478 569 static void do_unwatch(unsigned int handle, const char *node, const char *token)
cl349@5357 570 {
cl349@5478 571 if (!xs_unwatch(handles[handle], node, token))
cl349@5357 572 failed(handle);
cl349@5357 573 }
cl349@5357 574
cl349@5357 575 static void do_start(unsigned int handle, const char *node)
cl349@5357 576 {
cl349@5357 577 if (!xs_transaction_start(handles[handle], node))
cl349@5357 578 failed(handle);
cl349@5357 579 }
cl349@5357 580
cl349@5357 581 static void do_end(unsigned int handle, bool abort)
cl349@5357 582 {
cl349@5357 583 if (!xs_transaction_end(handles[handle], abort))
cl349@5357 584 failed(handle);
cl349@5357 585 }
cl349@5357 586
cl349@5357 587 static void do_introduce(unsigned int handle,
cl349@5357 588 const char *domid,
cl349@5357 589 const char *mfn,
cl349@5357 590 const char *eventchn,
cl349@5357 591 const char *path)
cl349@5357 592 {
cl349@5357 593 unsigned int i;
cl349@5357 594 int fd;
cl349@5357 595
kaf24@6043 596 /* This mechanism is v. slow w. valgrind running. */
kaf24@6043 597 timeout_ms = 5000;
kaf24@6043 598
cl349@5357 599 /* We poll, so ignore signal */
cl349@5357 600 signal(SIGUSR2, SIG_IGN);
cl349@5357 601 for (i = 0; i < ARRAY_SIZE(handles); i++)
cl349@5357 602 if (!handles[i])
cl349@5357 603 break;
cl349@5357 604
cl349@5357 605 fd = open("/tmp/xcmap", O_RDWR);
cl349@5357 606 /* Set in and out pointers. */
cl349@5357 607 out = mmap(NULL, getpagesize(), PROT_WRITE|PROT_READ, MAP_SHARED,fd,0);
cl349@5357 608 if (out == MAP_FAILED)
cl349@5357 609 barf_perror("Failed to map /tmp/xcmap page");
cl349@5357 610 in = (void *)out + getpagesize() / 2;
cl349@5357 611 close(fd);
cl349@5357 612
cl349@5357 613 /* Tell them the event channel and our PID. */
cl349@5357 614 *(int *)((void *)out + 32) = getpid();
cl349@5357 615 *(u16 *)((void *)out + 36) = atoi(eventchn);
cl349@5357 616
kaf24@6024 617 if (!xs_introduce_domain(handles[handle], atoi(domid),
kaf24@6024 618 atol(mfn), atoi(eventchn), path)) {
kaf24@6024 619 failed(handle);
kaf24@6024 620 munmap(out, getpagesize());
kaf24@6024 621 return;
kaf24@6024 622 }
kaf24@6024 623 output("handle is %i\n", i);
kaf24@6024 624
cl349@5357 625 /* Create new handle. */
cl349@5357 626 handles[i] = new(struct xs_handle);
cl349@5357 627 handles[i]->fd = -2;
cl349@5357 628
cl349@5357 629 /* Read in daemon pid. */
cl349@5357 630 daemon_pid = *(int *)((void *)out + 32);
cl349@5357 631 }
cl349@5357 632
cl349@5357 633 static void do_release(unsigned int handle, const char *domid)
cl349@5357 634 {
cl349@5357 635 if (!xs_release_domain(handles[handle], atoi(domid)))
cl349@5357 636 failed(handle);
cl349@5357 637 }
cl349@5357 638
cl349@5357 639 static int strptrcmp(const void *a, const void *b)
cl349@5357 640 {
cl349@5357 641 return strcmp(*(char **)a, *(char **)b);
cl349@5357 642 }
cl349@5357 643
cl349@5357 644 static void sort_dir(char **dir, unsigned int num)
cl349@5357 645 {
cl349@5357 646 qsort(dir, num, sizeof(char *), strptrcmp);
cl349@5357 647 }
cl349@5357 648
cl349@5357 649 static void dump_dir(unsigned int handle,
cl349@5357 650 const char *node,
cl349@5357 651 char **dir,
cl349@5357 652 unsigned int numdirs,
cl349@5357 653 unsigned int depth)
cl349@5357 654 {
cl349@5357 655 unsigned int i;
cl349@5357 656 char spacing[depth+1];
cl349@5357 657
cl349@5357 658 memset(spacing, ' ', depth);
cl349@5357 659 spacing[depth] = '\0';
cl349@5357 660
cl349@5357 661 sort_dir(dir, numdirs);
cl349@5357 662
cl349@5357 663 for (i = 0; i < numdirs; i++) {
cl349@5357 664 struct xs_permissions *perms;
cl349@5357 665 unsigned int j, numperms;
cl349@5357 666 unsigned int len;
cl349@5357 667 char *contents;
cl349@5357 668 unsigned int subnum;
cl349@5357 669 char **subdirs;
cl349@5357 670 char subnode[strlen(node) + 1 + strlen(dir[i]) + 1];
cl349@5357 671
cl349@5357 672 sprintf(subnode, "%s/%s", node, dir[i]);
cl349@5357 673
cl349@5357 674 perms = xs_get_permissions(handles[handle], subnode,&numperms);
kaf24@6024 675 if (!perms) {
cl349@5357 676 failed(handle);
kaf24@6024 677 return;
kaf24@6024 678 }
cl349@5357 679
kaf24@6024 680 output("%s%s: ", spacing, dir[i]);
cl349@5357 681 for (j = 0; j < numperms; j++) {
cl349@5357 682 char buffer[100];
kaf24@5423 683 if (!xs_perm_to_string(&perms[j], buffer))
cl349@5357 684 barf("perm to string");
kaf24@6024 685 output("%s ", buffer);
cl349@5357 686 }
cl349@5357 687 free(perms);
kaf24@6024 688 output("\n");
cl349@5357 689
cl349@5357 690 /* Even directories can have contents. */
cl349@5357 691 contents = xs_read(handles[handle], subnode, &len);
cl349@5357 692 if (!contents) {
cl349@5357 693 if (errno != EISDIR)
cl349@5357 694 failed(handle);
cl349@5357 695 } else {
kaf24@6024 696 output(" %s(%.*s)\n", spacing, len, contents);
cl349@5357 697 free(contents);
cl349@5357 698 }
cl349@5357 699
cl349@5357 700 /* Every node is a directory. */
cl349@5357 701 subdirs = xs_directory(handles[handle], subnode, &subnum);
kaf24@6024 702 if (!subdirs) {
cl349@5357 703 failed(handle);
kaf24@6024 704 return;
kaf24@6024 705 }
cl349@5357 706 dump_dir(handle, subnode, subdirs, subnum, depth+1);
cl349@5357 707 free(subdirs);
cl349@5357 708 }
cl349@5357 709 }
cl349@5357 710
cl349@5357 711 static void dump(int handle)
cl349@5357 712 {
cl349@5357 713 char **subdirs;
cl349@5357 714 unsigned int subnum;
cl349@5357 715
cl349@5357 716 subdirs = xs_directory(handles[handle], "/", &subnum);
kaf24@6024 717 if (!subdirs) {
cl349@5357 718 failed(handle);
kaf24@6024 719 return;
kaf24@6024 720 }
cl349@5357 721
cl349@5357 722 dump_dir(handle, "", subdirs, subnum, 0);
cl349@5357 723 free(subdirs);
cl349@5357 724 }
cl349@5357 725
cl349@5856 726 static int handle;
cl349@5856 727
cl349@5856 728 static void alarmed(int sig __attribute__((unused)))
cl349@5856 729 {
cl349@5856 730 if (handle) {
cl349@5856 731 char handlename[10];
cl349@5856 732 sprintf(handlename, "%u:", handle);
cl349@5856 733 write(STDOUT_FILENO, handlename, strlen(handlename));
cl349@5856 734 }
cl349@5856 735 write(STDOUT_FILENO, command, strlen(command));
cl349@5856 736 write(STDOUT_FILENO, " timeout\n", strlen(" timeout\n"));
cl349@5856 737 exit(1);
cl349@5856 738 }
cl349@5856 739
cl349@5856 740 static void do_command(unsigned int default_handle, char *line)
cl349@5856 741 {
cl349@5856 742 char *endp;
cl349@5856 743
kaf24@6024 744 if (print_input)
kaf24@6024 745 printf("%i> %s", ++linenum, line);
kaf24@6024 746
cl349@5856 747 if (strspn(line, " \n") == strlen(line))
cl349@5856 748 return;
cl349@5856 749 if (strstarts(line, "#"))
cl349@5856 750 return;
cl349@5856 751
cl349@5856 752 handle = strtoul(line, &endp, 10);
cl349@5856 753 if (endp != line)
cl349@5856 754 memmove(line, endp+1, strlen(endp));
cl349@5856 755 else
cl349@5856 756 handle = default_handle;
cl349@5856 757
kaf24@6024 758 command = arg(line, 0);
cl349@5856 759 if (!handles[handle]) {
cl349@5856 760 if (readonly)
cl349@5856 761 handles[handle] = xs_daemon_open_readonly();
cl349@5856 762 else
cl349@5856 763 handles[handle] = xs_daemon_open();
cl349@5856 764 if (!handles[handle])
cl349@5856 765 barf_perror("Opening connection to daemon");
cl349@5856 766 }
cl349@5856 767
kaf24@6024 768 if (!timeout_suppressed)
kaf24@6024 769 set_timeout();
kaf24@6024 770 timeout_suppressed = false;
cl349@5856 771
cl349@5856 772 if (streq(command, "dir"))
cl349@5856 773 do_dir(handle, arg(line, 1));
cl349@5856 774 else if (streq(command, "read"))
cl349@5856 775 do_read(handle, arg(line, 1));
cl349@5856 776 else if (streq(command, "write"))
cl349@5856 777 do_write(handle,
cl349@5856 778 arg(line, 1), arg(line, 2), arg(line, 3));
cl349@5856 779 else if (streq(command, "setid"))
cl349@5856 780 do_setid(handle, arg(line, 1));
cl349@5856 781 else if (streq(command, "mkdir"))
cl349@5856 782 do_mkdir(handle, arg(line, 1));
cl349@5856 783 else if (streq(command, "rm"))
cl349@5856 784 do_rm(handle, arg(line, 1));
cl349@5856 785 else if (streq(command, "getperm"))
cl349@5856 786 do_getperm(handle, arg(line, 1));
cl349@5856 787 else if (streq(command, "setperm"))
cl349@5856 788 do_setperm(handle, arg(line, 1), line);
cl349@5856 789 else if (streq(command, "shutdown"))
cl349@5856 790 do_shutdown(handle);
cl349@5856 791 else if (streq(command, "watch"))
cl349@5856 792 do_watch(handle, arg(line, 1), arg(line, 2));
cl349@5856 793 else if (streq(command, "waitwatch"))
cl349@5856 794 do_waitwatch(handle);
cl349@5856 795 else if (streq(command, "ackwatch"))
cl349@5856 796 do_ackwatch(handle, arg(line, 1));
cl349@5856 797 else if (streq(command, "unwatch"))
cl349@5856 798 do_unwatch(handle, arg(line, 1), arg(line, 2));
cl349@5856 799 else if (streq(command, "close")) {
cl349@5856 800 xs_daemon_close(handles[handle]);
cl349@5856 801 handles[handle] = NULL;
cl349@5856 802 } else if (streq(command, "start"))
cl349@5856 803 do_start(handle, arg(line, 1));
cl349@5856 804 else if (streq(command, "commit"))
cl349@5856 805 do_end(handle, false);
cl349@5856 806 else if (streq(command, "abort"))
cl349@5856 807 do_end(handle, true);
cl349@5856 808 else if (streq(command, "introduce"))
cl349@5856 809 do_introduce(handle, arg(line, 1), arg(line, 2),
cl349@5856 810 arg(line, 3), arg(line, 4));
cl349@5856 811 else if (streq(command, "release"))
cl349@5856 812 do_release(handle, arg(line, 1));
cl349@5856 813 else if (streq(command, "dump"))
cl349@5856 814 dump(handle);
kaf24@6024 815 else if (streq(command, "sleep")) {
kaf24@6024 816 disarm_timeout();
kaf24@6024 817 usleep(atoi(arg(line, 1)) * 1000);
kaf24@6024 818 } else if (streq(command, "expect"))
kaf24@6024 819 expect(line);
kaf24@6024 820 else if (streq(command, "notimeout"))
kaf24@6024 821 timeout_suppressed = true;
kaf24@6024 822 else if (streq(command, "readonly")) {
kaf24@6024 823 readonly = true;
kaf24@6024 824 xs_daemon_close(handles[handle]);
kaf24@6024 825 handles[handle] = NULL;
kaf24@6024 826 } else if (streq(command, "readwrite")) {
kaf24@6024 827 readonly = false;
kaf24@6024 828 xs_daemon_close(handles[handle]);
kaf24@6024 829 handles[handle] = NULL;
kaf24@6043 830 } else if (streq(command, "noackwrite"))
kaf24@6043 831 do_noackwrite(handle, arg(line,1), arg(line,2), arg(line,3));
kaf24@6043 832 else if (streq(command, "readack"))
kaf24@6043 833 do_readack(handle);
kaf24@6043 834 else
cl349@5856 835 barf("Unknown command %s", command);
cl349@5856 836 fflush(stdout);
kaf24@6024 837 disarm_timeout();
kaf24@6024 838
kaf24@6024 839 /* Check expectations. */
kaf24@6024 840 if (!streq(command, "expect")) {
kaf24@6024 841 struct expect *i = list_top(&expects, struct expect, list);
kaf24@6024 842
kaf24@6024 843 if (i)
kaf24@6024 844 barf("Expected '%s', didn't happen\n", i->pattern);
kaf24@6024 845 }
cl349@5856 846 }
cl349@5856 847
kaf24@6024 848 static struct option options[] = { { "readonly", 0, NULL, 'r' },
kaf24@6024 849 { "no-timeout", 0, NULL, 't' },
kaf24@6024 850 { NULL, 0, NULL, 0 } };
kaf24@6024 851
cl349@5357 852 int main(int argc, char *argv[])
cl349@5357 853 {
kaf24@6024 854 int opt;
cl349@5357 855 char line[1024];
cl349@5357 856
kaf24@6024 857 while ((opt = getopt_long(argc, argv, "xrt", options, NULL)) != -1) {
kaf24@6024 858 switch (opt) {
kaf24@6024 859 case 'r':
kaf24@6024 860 readonly = true;
kaf24@6024 861 break;
kaf24@6024 862 case 't':
kaf24@6024 863 timeout_ms = 0;
kaf24@6024 864 break;
kaf24@6024 865 case 'x':
kaf24@6024 866 print_input = true;
kaf24@6024 867 break;
kaf24@6024 868 }
cl349@5357 869 }
cl349@5357 870
kaf24@6024 871 if (optind + 1 == argc) {
kaf24@6024 872 int fd = open(argv[optind], O_RDONLY);
kaf24@6024 873 if (!fd)
kaf24@6024 874 barf_perror("Opening %s", argv[optind]);
kaf24@6024 875 dup2(fd, STDIN_FILENO);
kaf24@6024 876 } else if (optind != argc)
cl349@5357 877 usage();
kaf24@6024 878
cl349@5357 879
cl349@5357 880 /* The size of the ringbuffer: half a page minus head structure. */
cl349@5357 881 ringbuf_datasize = getpagesize() / 2 - sizeof(struct ringbuf_head);
cl349@5357 882
cl349@5357 883 signal(SIGALRM, alarmed);
cl349@5856 884 while (fgets(line, sizeof(line), stdin))
cl349@5856 885 do_command(0, line);
cl349@5357 886
cl349@5357 887 return 0;
cl349@5357 888 }