ia64/xen-unstable

annotate tools/xenstore/xs_test.c @ 6823:c63529f3367d

Fix xenstored watch crash.
When a connection blocked waiting on a transaction, don't queue watch events.
Sure, they'd be ignored and re-transmitted, but it hits an assert that we don't
send data out blocked connections, and it's wasteful.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (authored)
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Wed Sep 14 08:41:49 2005 +0000 (2005-09-14)
parents 72e4e2aab342
children 9af349b055e5 3233e7ecfa9f
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@6039 20 #define _GNU_SOURCE
cl349@5357 21 #include <stdio.h>
cl349@5357 22 #include <stdlib.h>
cl349@5357 23 #include <sys/types.h>
cl349@5872 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@6058 31 #include <sys/mman.h>
kaf24@6039 32 #include <fnmatch.h>
kaf24@6039 33 #include <stdarg.h>
kaf24@6039 34 #include <string.h>
kaf24@6039 35 #include <getopt.h>
kaf24@6039 36 #include <ctype.h>
kaf24@6039 37 #include <sys/time.h>
cl349@5357 38 #include "utils.h"
cl349@5357 39 #include "xs_lib.h"
kaf24@6039 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@5872 45
cl349@6772 46 static unsigned int timeout_ms = 500;
kaf24@6039 47 static bool timeout_suppressed = true;
cl349@5872 48 static bool readonly = false;
kaf24@6039 49 static bool print_input = false;
kaf24@6039 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@5875 98 static int output_avail(struct ringbuf_head *out)
cl349@5875 99 {
cl349@5875 100 unsigned int avail;
cl349@5875 101
cl349@5875 102 get_output_chunk(out, out->buf, &avail);
cl349@5875 103 return avail != 0;
cl349@5875 104 }
cl349@5875 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@5875 125 int was_full;
cl349@5357 126
cl349@5357 127 if (!check_buffer(in))
cl349@5357 128 barf("Corrupt buffer");
cl349@5357 129
cl349@5875 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@5875 142 if (was_full)
cl349@5875 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@6039 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@5872 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@6039 211 " sleep <milliseconds>\n"
kaf24@6039 212 " expect <pattern>\n"
kaf24@6039 213 " notimeout\n"
kaf24@6039 214 " readonly\n"
kaf24@6039 215 " readwrite\n"
kaf24@6058 216 " noackwrite <path> <flags> <value>...\n"
kaf24@6058 217 " readack\n"
cl349@5357 218 " dump\n");
cl349@5357 219 }
cl349@5357 220
cl349@5872 221 static int argpos(const char *line, unsigned int num)
cl349@5872 222 {
cl349@5872 223 unsigned int i, len = 0, off = 0;
cl349@5872 224
cl349@5872 225 for (i = 0; i <= num; i++) {
cl349@5872 226 off += len;
cl349@5872 227 off += strspn(line + off, " \t\n");
cl349@5872 228 len = strcspn(line + off, " \t\n");
cl349@5872 229 if (!len)
cl349@5872 230 return off;
cl349@5872 231 }
cl349@5872 232 return off;
cl349@5872 233 }
cl349@5872 234
kaf24@6039 235 static char *arg(const char *line, unsigned int num)
cl349@5357 236 {
cl349@5357 237 static char *args[10];
cl349@5872 238 unsigned int off, len;
cl349@5357 239
cl349@5872 240 off = argpos(line, num);
cl349@5872 241 len = strcspn(line + off, " \t\n");
cl349@5872 242
cl349@5872 243 if (!len)
cl349@5872 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@5872 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@6039 253 struct expect
kaf24@6039 254 {
kaf24@6039 255 struct list_head list;
kaf24@6039 256 char *pattern;
kaf24@6039 257 };
kaf24@6039 258 static LIST_HEAD(expects);
kaf24@6039 259
cl349@5357 260 static char *command;
kaf24@6039 261
kaf24@6039 262 /* Trim leading and trailing whitespace */
kaf24@6039 263 static void trim(char *str)
kaf24@6039 264 {
kaf24@6039 265 while (isspace(str[0]))
kaf24@6039 266 memmove(str, str+1, strlen(str));
kaf24@6039 267
kaf24@6039 268 while (strlen(str) && isspace(str[strlen(str)-1]))
kaf24@6039 269 str[strlen(str)-1] = '\0';
kaf24@6039 270 }
kaf24@6039 271
kaf24@6039 272 static void output(const char *fmt, ...)
kaf24@6039 273 {
kaf24@6039 274 char *str;
kaf24@6039 275 struct expect *i;
kaf24@6039 276 va_list arglist;
kaf24@6039 277
kaf24@6039 278 va_start(arglist, fmt);
kaf24@6039 279 vasprintf(&str, fmt, arglist);
kaf24@6039 280 va_end(arglist);
kaf24@6039 281
kaf24@6039 282 printf("%s", str);
kaf24@6039 283 fflush(stdout);
kaf24@6039 284 trim(str);
kaf24@6039 285 list_for_each_entry(i, &expects, list) {
kaf24@6039 286 if (fnmatch(i->pattern, str, 0) == 0) {
kaf24@6039 287 list_del(&i->list);
kaf24@6039 288 free(i);
kaf24@6039 289 return;
kaf24@6039 290 }
kaf24@6039 291 }
kaf24@6039 292 barf("Unexpected output %s\n", str);
kaf24@6039 293 }
kaf24@6039 294
kaf24@6039 295 static void failed(int handle)
cl349@5357 296 {
cl349@5357 297 if (handle)
kaf24@6039 298 output("%i: %s failed: %s\n",
kaf24@6039 299 handle, command, strerror(errno));
kaf24@6039 300 else
kaf24@6039 301 output("%s failed: %s\n", command, strerror(errno));
kaf24@6039 302 }
kaf24@6039 303
kaf24@6039 304 static void expect(const char *line)
kaf24@6039 305 {
kaf24@6039 306 struct expect *e = malloc(sizeof(*e));
kaf24@6039 307
kaf24@6039 308 e->pattern = strdup(line + argpos(line, 1));
kaf24@6039 309 trim(e->pattern);
kaf24@6039 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@6039 319 if (!entries) {
cl349@5357 320 failed(handle);
kaf24@6039 321 return;
kaf24@6039 322 }
cl349@5357 323
cl349@5357 324 for (i = 0; i < num; i++)
cl349@5357 325 if (handle)
kaf24@6039 326 output("%i:%s\n", handle, entries[i]);
cl349@5357 327 else
kaf24@6039 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@6039 338 if (!value) {
cl349@5357 339 failed(handle);
kaf24@6039 340 return;
kaf24@6039 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@6039 346 output("%i:%.*s\n", handle, len, value);
cl349@5357 347 else
kaf24@6039 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@6058 370 static void do_noackwrite(unsigned int handle,
kaf24@6058 371 char *path, const char *flags, char *data)
kaf24@6058 372 {
kaf24@6058 373 struct xsd_sockmsg msg;
kaf24@6058 374
kaf24@6058 375 /* Format: Flags (as string), path, data. */
kaf24@6058 376 if (streq(flags, "none"))
kaf24@6058 377 flags = XS_WRITE_NONE;
kaf24@6058 378 else if (streq(flags, "create"))
kaf24@6058 379 flags = XS_WRITE_CREATE;
kaf24@6058 380 else if (streq(flags, "excl"))
kaf24@6058 381 flags = XS_WRITE_CREATE_EXCL;
kaf24@6058 382 else
kaf24@6058 383 barf("noackwrite flags 'none', 'create' or 'excl' only");
kaf24@6058 384
kaf24@6058 385 msg.len = strlen(path) + 1 + strlen(flags) + 1 + strlen(data);
kaf24@6058 386 msg.type = XS_WRITE;
kaf24@6058 387 if (!write_all_choice(handles[handle]->fd, &msg, sizeof(msg)))
kaf24@6058 388 failed(handle);
kaf24@6058 389 if (!write_all_choice(handles[handle]->fd, path, strlen(path) + 1))
kaf24@6058 390 failed(handle);
kaf24@6058 391 if (!write_all_choice(handles[handle]->fd, flags, strlen(flags) + 1))
kaf24@6058 392 failed(handle);
kaf24@6058 393 if (!write_all_choice(handles[handle]->fd, data, strlen(data)))
kaf24@6058 394 failed(handle);
kaf24@6058 395 /* Do not wait for ack. */
kaf24@6058 396 }
kaf24@6058 397
kaf24@6058 398 static void do_readack(unsigned int handle)
kaf24@6058 399 {
kaf24@6058 400 enum xsd_sockmsg_type type;
cl349@6823 401 char *ret = NULL;
kaf24@6058 402
cl349@6823 403 /* Watches can have fired before reply comes: daemon detects
cl349@6823 404 * and re-transmits, so we can ignore this. */
cl349@6823 405 do {
cl349@6823 406 free(ret);
cl349@6823 407 ret = read_reply(handles[handle]->fd, &type, NULL);
cl349@6823 408 if (!ret)
cl349@6823 409 failed(handle);
cl349@6823 410 } while (type == XS_WATCH_EVENT);
kaf24@6058 411 }
kaf24@6058 412
cl349@5357 413 static void do_setid(unsigned int handle, char *id)
cl349@5357 414 {
cl349@5357 415 if (!xs_bool(xs_debug_command(handles[handle], "setid", id,
cl349@5357 416 strlen(id)+1)))
cl349@5357 417 failed(handle);
cl349@5357 418 }
cl349@5357 419
cl349@5357 420 static void do_mkdir(unsigned int handle, char *path)
cl349@5357 421 {
cl349@5357 422 if (!xs_mkdir(handles[handle], path))
cl349@5357 423 failed(handle);
cl349@5357 424 }
cl349@5357 425
cl349@5357 426 static void do_rm(unsigned int handle, char *path)
cl349@5357 427 {
cl349@5357 428 if (!xs_rm(handles[handle], path))
cl349@5357 429 failed(handle);
cl349@5357 430 }
cl349@5357 431
cl349@5357 432 static void do_getperm(unsigned int handle, char *path)
cl349@5357 433 {
cl349@5357 434 unsigned int i, num;
cl349@5357 435 struct xs_permissions *perms;
cl349@5357 436
cl349@5357 437 perms = xs_get_permissions(handles[handle], path, &num);
kaf24@6039 438 if (!perms) {
cl349@5357 439 failed(handle);
kaf24@6039 440 return;
kaf24@6039 441 }
cl349@5357 442
cl349@5357 443 for (i = 0; i < num; i++) {
cl349@5357 444 char *permstring;
cl349@5357 445
cl349@5357 446 switch (perms[i].perms) {
cl349@5357 447 case XS_PERM_NONE:
cl349@5357 448 permstring = "NONE";
cl349@5357 449 break;
cl349@5357 450 case XS_PERM_WRITE:
cl349@5357 451 permstring = "WRITE";
cl349@5357 452 break;
cl349@5357 453 case XS_PERM_READ:
cl349@5357 454 permstring = "READ";
cl349@5357 455 break;
cl349@5357 456 case XS_PERM_READ|XS_PERM_WRITE:
cl349@5357 457 permstring = "READ/WRITE";
cl349@5357 458 break;
cl349@5357 459 default:
cl349@5357 460 barf("bad perm value %i", perms[i].perms);
cl349@5357 461 }
cl349@5357 462
cl349@5357 463 if (handle)
kaf24@6039 464 output("%i:%i %s\n", handle, perms[i].id, permstring);
cl349@5357 465 else
kaf24@6039 466 output("%i %s\n", perms[i].id, permstring);
cl349@5357 467 }
cl349@5357 468 free(perms);
cl349@5357 469 }
cl349@5357 470
cl349@5357 471 static void do_setperm(unsigned int handle, char *path, char *line)
cl349@5357 472 {
cl349@5357 473 unsigned int i;
cl349@5357 474 struct xs_permissions perms[100];
cl349@5357 475
cl349@5357 476 strtok(line, " \t\n");
cl349@5357 477 strtok(NULL, " \t\n");
cl349@5357 478 for (i = 0; ; i++) {
cl349@5357 479 char *arg = strtok(NULL, " \t\n");
cl349@5357 480 if (!arg)
cl349@5357 481 break;
cl349@5357 482 perms[i].id = atoi(arg);
cl349@5357 483 arg = strtok(NULL, " \t\n");
cl349@5357 484 if (!arg)
cl349@5357 485 break;
cl349@5357 486 if (streq(arg, "WRITE"))
cl349@5357 487 perms[i].perms = XS_PERM_WRITE;
cl349@5357 488 else if (streq(arg, "READ"))
cl349@5357 489 perms[i].perms = XS_PERM_READ;
cl349@5357 490 else if (streq(arg, "READ/WRITE"))
cl349@5357 491 perms[i].perms = XS_PERM_READ|XS_PERM_WRITE;
cl349@5357 492 else if (streq(arg, "NONE"))
cl349@5357 493 perms[i].perms = XS_PERM_NONE;
cl349@5357 494 else
cl349@5357 495 barf("bad flags %s\n", arg);
cl349@5357 496 }
cl349@5357 497
cl349@5357 498 if (!xs_set_permissions(handles[handle], path, perms, i))
cl349@5357 499 failed(handle);
cl349@5357 500 }
cl349@5357 501
cl349@5357 502 static void do_shutdown(unsigned int handle)
cl349@5357 503 {
cl349@5357 504 if (!xs_shutdown(handles[handle]))
cl349@5357 505 failed(handle);
cl349@5357 506 }
cl349@5357 507
cl349@5872 508 static void do_watch(unsigned int handle, const char *node, const char *token)
cl349@5357 509 {
cl349@5872 510 if (!xs_watch(handles[handle], node, token))
cl349@5357 511 failed(handle);
cl349@5357 512 }
cl349@5357 513
kaf24@6058 514 static void set_timeout(void)
kaf24@6058 515 {
kaf24@6058 516 struct itimerval timeout;
kaf24@6058 517
kaf24@6058 518 timeout.it_value.tv_sec = timeout_ms / 1000;
kaf24@6058 519 timeout.it_value.tv_usec = (timeout_ms * 1000) % 1000000;
kaf24@6058 520 timeout.it_interval.tv_sec = timeout.it_interval.tv_usec = 0;
kaf24@6058 521 setitimer(ITIMER_REAL, &timeout, NULL);
kaf24@6058 522 }
kaf24@6058 523
kaf24@6058 524 static void disarm_timeout(void)
kaf24@6058 525 {
kaf24@6058 526 struct itimerval timeout;
kaf24@6058 527
kaf24@6058 528 timeout.it_value.tv_sec = 0;
kaf24@6058 529 timeout.it_value.tv_usec = 0;
kaf24@6058 530 setitimer(ITIMER_REAL, &timeout, NULL);
kaf24@6058 531 }
kaf24@6058 532
cl349@5357 533 static void do_waitwatch(unsigned int handle)
cl349@5357 534 {
cl349@5478 535 char **vec;
kaf24@6039 536 struct timeval tv = {.tv_sec = timeout_ms/1000,
kaf24@6039 537 .tv_usec = (timeout_ms*1000)%1000000 };
kaf24@6039 538 fd_set set;
kaf24@6039 539
kaf24@6039 540 if (xs_fileno(handles[handle]) != -2) {
kaf24@6058 541 /* Manually select here so we can time out gracefully. */
kaf24@6039 542 FD_ZERO(&set);
kaf24@6039 543 FD_SET(xs_fileno(handles[handle]), &set);
kaf24@6058 544 disarm_timeout();
kaf24@6039 545 if (select(xs_fileno(handles[handle])+1, &set,
kaf24@6039 546 NULL, NULL, &tv) == 0) {
kaf24@6039 547 errno = ETIMEDOUT;
kaf24@6039 548 failed(handle);
kaf24@6039 549 return;
kaf24@6039 550 }
kaf24@6058 551 set_timeout();
kaf24@6039 552 }
cl349@5357 553
cl349@5478 554 vec = xs_read_watch(handles[handle]);
kaf24@6039 555 if (!vec) {
cl349@5357 556 failed(handle);
kaf24@6039 557 return;
kaf24@6039 558 }
cl349@5357 559
cl349@5357 560 if (handle)
kaf24@6039 561 output("%i:%s:%s\n", handle, vec[0], vec[1]);
cl349@5357 562 else
kaf24@6039 563 output("%s:%s\n", vec[0], vec[1]);
cl349@5478 564 free(vec);
cl349@5357 565 }
cl349@5357 566
cl349@5478 567 static void do_ackwatch(unsigned int handle, const char *token)
cl349@5357 568 {
cl349@5478 569 if (!xs_acknowledge_watch(handles[handle], token))
cl349@5357 570 failed(handle);
cl349@5357 571 }
cl349@5357 572
cl349@5478 573 static void do_unwatch(unsigned int handle, const char *node, const char *token)
cl349@5357 574 {
cl349@5478 575 if (!xs_unwatch(handles[handle], node, token))
cl349@5357 576 failed(handle);
cl349@5357 577 }
cl349@5357 578
cl349@5357 579 static void do_start(unsigned int handle, const char *node)
cl349@5357 580 {
cl349@5357 581 if (!xs_transaction_start(handles[handle], node))
cl349@5357 582 failed(handle);
cl349@5357 583 }
cl349@5357 584
cl349@5357 585 static void do_end(unsigned int handle, bool abort)
cl349@5357 586 {
cl349@5357 587 if (!xs_transaction_end(handles[handle], abort))
cl349@5357 588 failed(handle);
cl349@5357 589 }
cl349@5357 590
cl349@5357 591 static void do_introduce(unsigned int handle,
cl349@5357 592 const char *domid,
cl349@5357 593 const char *mfn,
cl349@5357 594 const char *eventchn,
cl349@5357 595 const char *path)
cl349@5357 596 {
cl349@5357 597 unsigned int i;
cl349@5357 598 int fd;
cl349@5357 599
kaf24@6058 600 /* This mechanism is v. slow w. valgrind running. */
kaf24@6058 601 timeout_ms = 5000;
kaf24@6058 602
cl349@5357 603 /* We poll, so ignore signal */
cl349@5357 604 signal(SIGUSR2, SIG_IGN);
cl349@5357 605 for (i = 0; i < ARRAY_SIZE(handles); i++)
cl349@5357 606 if (!handles[i])
cl349@5357 607 break;
cl349@5357 608
cl349@5357 609 fd = open("/tmp/xcmap", O_RDWR);
cl349@5357 610 /* Set in and out pointers. */
cl349@5357 611 out = mmap(NULL, getpagesize(), PROT_WRITE|PROT_READ, MAP_SHARED,fd,0);
cl349@5357 612 if (out == MAP_FAILED)
cl349@5357 613 barf_perror("Failed to map /tmp/xcmap page");
cl349@5357 614 in = (void *)out + getpagesize() / 2;
cl349@5357 615 close(fd);
cl349@5357 616
cl349@5357 617 /* Tell them the event channel and our PID. */
cl349@5357 618 *(int *)((void *)out + 32) = getpid();
cl349@5357 619 *(u16 *)((void *)out + 36) = atoi(eventchn);
cl349@5357 620
kaf24@6039 621 if (!xs_introduce_domain(handles[handle], atoi(domid),
kaf24@6039 622 atol(mfn), atoi(eventchn), path)) {
kaf24@6039 623 failed(handle);
kaf24@6039 624 munmap(out, getpagesize());
kaf24@6039 625 return;
kaf24@6039 626 }
kaf24@6039 627 output("handle is %i\n", i);
kaf24@6039 628
cl349@5357 629 /* Create new handle. */
cl349@5357 630 handles[i] = new(struct xs_handle);
cl349@5357 631 handles[i]->fd = -2;
cl349@5357 632
cl349@5357 633 /* Read in daemon pid. */
cl349@5357 634 daemon_pid = *(int *)((void *)out + 32);
cl349@5357 635 }
cl349@5357 636
cl349@5357 637 static void do_release(unsigned int handle, const char *domid)
cl349@5357 638 {
cl349@5357 639 if (!xs_release_domain(handles[handle], atoi(domid)))
cl349@5357 640 failed(handle);
cl349@5357 641 }
cl349@5357 642
cl349@5357 643 static int strptrcmp(const void *a, const void *b)
cl349@5357 644 {
cl349@5357 645 return strcmp(*(char **)a, *(char **)b);
cl349@5357 646 }
cl349@5357 647
cl349@5357 648 static void sort_dir(char **dir, unsigned int num)
cl349@5357 649 {
cl349@5357 650 qsort(dir, num, sizeof(char *), strptrcmp);
cl349@5357 651 }
cl349@5357 652
cl349@5357 653 static void dump_dir(unsigned int handle,
cl349@5357 654 const char *node,
cl349@5357 655 char **dir,
cl349@5357 656 unsigned int numdirs,
cl349@5357 657 unsigned int depth)
cl349@5357 658 {
cl349@5357 659 unsigned int i;
cl349@5357 660 char spacing[depth+1];
cl349@5357 661
cl349@5357 662 memset(spacing, ' ', depth);
cl349@5357 663 spacing[depth] = '\0';
cl349@5357 664
cl349@5357 665 sort_dir(dir, numdirs);
cl349@5357 666
cl349@5357 667 for (i = 0; i < numdirs; i++) {
cl349@5357 668 struct xs_permissions *perms;
cl349@5357 669 unsigned int j, numperms;
cl349@5357 670 unsigned int len;
cl349@5357 671 char *contents;
cl349@5357 672 unsigned int subnum;
cl349@5357 673 char **subdirs;
cl349@5357 674 char subnode[strlen(node) + 1 + strlen(dir[i]) + 1];
cl349@5357 675
cl349@5357 676 sprintf(subnode, "%s/%s", node, dir[i]);
cl349@5357 677
cl349@5357 678 perms = xs_get_permissions(handles[handle], subnode,&numperms);
kaf24@6039 679 if (!perms) {
cl349@5357 680 failed(handle);
kaf24@6039 681 return;
kaf24@6039 682 }
cl349@5357 683
kaf24@6039 684 output("%s%s: ", spacing, dir[i]);
cl349@5357 685 for (j = 0; j < numperms; j++) {
cl349@5357 686 char buffer[100];
kaf24@5423 687 if (!xs_perm_to_string(&perms[j], buffer))
cl349@5357 688 barf("perm to string");
kaf24@6039 689 output("%s ", buffer);
cl349@5357 690 }
cl349@5357 691 free(perms);
kaf24@6039 692 output("\n");
cl349@5357 693
cl349@5357 694 /* Even directories can have contents. */
cl349@5357 695 contents = xs_read(handles[handle], subnode, &len);
cl349@5357 696 if (!contents) {
cl349@5357 697 if (errno != EISDIR)
cl349@5357 698 failed(handle);
cl349@5357 699 } else {
kaf24@6039 700 output(" %s(%.*s)\n", spacing, len, contents);
cl349@5357 701 free(contents);
cl349@5357 702 }
cl349@5357 703
cl349@5357 704 /* Every node is a directory. */
cl349@5357 705 subdirs = xs_directory(handles[handle], subnode, &subnum);
kaf24@6039 706 if (!subdirs) {
cl349@5357 707 failed(handle);
kaf24@6039 708 return;
kaf24@6039 709 }
cl349@5357 710 dump_dir(handle, subnode, subdirs, subnum, depth+1);
cl349@5357 711 free(subdirs);
cl349@5357 712 }
cl349@5357 713 }
cl349@5357 714
cl349@5357 715 static void dump(int handle)
cl349@5357 716 {
cl349@5357 717 char **subdirs;
cl349@5357 718 unsigned int subnum;
cl349@5357 719
cl349@5357 720 subdirs = xs_directory(handles[handle], "/", &subnum);
kaf24@6039 721 if (!subdirs) {
cl349@5357 722 failed(handle);
kaf24@6039 723 return;
kaf24@6039 724 }
cl349@5357 725
cl349@5357 726 dump_dir(handle, "", subdirs, subnum, 0);
cl349@5357 727 free(subdirs);
cl349@5357 728 }
cl349@5357 729
cl349@5872 730 static int handle;
cl349@5872 731
cl349@5872 732 static void alarmed(int sig __attribute__((unused)))
cl349@5872 733 {
cl349@5872 734 if (handle) {
cl349@5872 735 char handlename[10];
cl349@5872 736 sprintf(handlename, "%u:", handle);
cl349@5872 737 write(STDOUT_FILENO, handlename, strlen(handlename));
cl349@5872 738 }
cl349@5872 739 write(STDOUT_FILENO, command, strlen(command));
cl349@5872 740 write(STDOUT_FILENO, " timeout\n", strlen(" timeout\n"));
cl349@5872 741 exit(1);
cl349@5872 742 }
cl349@5872 743
cl349@5872 744 static void do_command(unsigned int default_handle, char *line)
cl349@5872 745 {
cl349@5872 746 char *endp;
cl349@5872 747
kaf24@6039 748 if (print_input)
kaf24@6039 749 printf("%i> %s", ++linenum, line);
kaf24@6039 750
cl349@5872 751 if (strspn(line, " \n") == strlen(line))
cl349@5872 752 return;
cl349@5872 753 if (strstarts(line, "#"))
cl349@5872 754 return;
cl349@5872 755
cl349@5872 756 handle = strtoul(line, &endp, 10);
cl349@5872 757 if (endp != line)
cl349@5872 758 memmove(line, endp+1, strlen(endp));
cl349@5872 759 else
cl349@5872 760 handle = default_handle;
cl349@5872 761
kaf24@6039 762 command = arg(line, 0);
cl349@5872 763 if (!handles[handle]) {
cl349@5872 764 if (readonly)
cl349@5872 765 handles[handle] = xs_daemon_open_readonly();
cl349@5872 766 else
cl349@5872 767 handles[handle] = xs_daemon_open();
cl349@5872 768 if (!handles[handle])
cl349@5872 769 barf_perror("Opening connection to daemon");
cl349@5872 770 }
cl349@5872 771
kaf24@6039 772 if (!timeout_suppressed)
kaf24@6039 773 set_timeout();
kaf24@6039 774 timeout_suppressed = false;
cl349@5872 775
cl349@5872 776 if (streq(command, "dir"))
cl349@5872 777 do_dir(handle, arg(line, 1));
cl349@5872 778 else if (streq(command, "read"))
cl349@5872 779 do_read(handle, arg(line, 1));
cl349@5872 780 else if (streq(command, "write"))
cl349@5872 781 do_write(handle,
cl349@5872 782 arg(line, 1), arg(line, 2), arg(line, 3));
cl349@5872 783 else if (streq(command, "setid"))
cl349@5872 784 do_setid(handle, arg(line, 1));
cl349@5872 785 else if (streq(command, "mkdir"))
cl349@5872 786 do_mkdir(handle, arg(line, 1));
cl349@5872 787 else if (streq(command, "rm"))
cl349@5872 788 do_rm(handle, arg(line, 1));
cl349@5872 789 else if (streq(command, "getperm"))
cl349@5872 790 do_getperm(handle, arg(line, 1));
cl349@5872 791 else if (streq(command, "setperm"))
cl349@5872 792 do_setperm(handle, arg(line, 1), line);
cl349@5872 793 else if (streq(command, "shutdown"))
cl349@5872 794 do_shutdown(handle);
cl349@5872 795 else if (streq(command, "watch"))
cl349@5872 796 do_watch(handle, arg(line, 1), arg(line, 2));
cl349@5872 797 else if (streq(command, "waitwatch"))
cl349@5872 798 do_waitwatch(handle);
cl349@5872 799 else if (streq(command, "ackwatch"))
cl349@5872 800 do_ackwatch(handle, arg(line, 1));
cl349@5872 801 else if (streq(command, "unwatch"))
cl349@5872 802 do_unwatch(handle, arg(line, 1), arg(line, 2));
cl349@5872 803 else if (streq(command, "close")) {
cl349@5872 804 xs_daemon_close(handles[handle]);
cl349@5872 805 handles[handle] = NULL;
cl349@5872 806 } else if (streq(command, "start"))
cl349@5872 807 do_start(handle, arg(line, 1));
cl349@5872 808 else if (streq(command, "commit"))
cl349@5872 809 do_end(handle, false);
cl349@5872 810 else if (streq(command, "abort"))
cl349@5872 811 do_end(handle, true);
cl349@5872 812 else if (streq(command, "introduce"))
cl349@5872 813 do_introduce(handle, arg(line, 1), arg(line, 2),
cl349@5872 814 arg(line, 3), arg(line, 4));
cl349@5872 815 else if (streq(command, "release"))
cl349@5872 816 do_release(handle, arg(line, 1));
cl349@5872 817 else if (streq(command, "dump"))
cl349@5872 818 dump(handle);
kaf24@6039 819 else if (streq(command, "sleep")) {
kaf24@6039 820 disarm_timeout();
kaf24@6039 821 usleep(atoi(arg(line, 1)) * 1000);
kaf24@6039 822 } else if (streq(command, "expect"))
kaf24@6039 823 expect(line);
kaf24@6039 824 else if (streq(command, "notimeout"))
kaf24@6039 825 timeout_suppressed = true;
kaf24@6039 826 else if (streq(command, "readonly")) {
kaf24@6039 827 readonly = true;
kaf24@6039 828 xs_daemon_close(handles[handle]);
kaf24@6039 829 handles[handle] = NULL;
kaf24@6039 830 } else if (streq(command, "readwrite")) {
kaf24@6039 831 readonly = false;
kaf24@6039 832 xs_daemon_close(handles[handle]);
kaf24@6039 833 handles[handle] = NULL;
kaf24@6058 834 } else if (streq(command, "noackwrite"))
kaf24@6058 835 do_noackwrite(handle, arg(line,1), arg(line,2), arg(line,3));
kaf24@6058 836 else if (streq(command, "readack"))
kaf24@6058 837 do_readack(handle);
kaf24@6058 838 else
cl349@5872 839 barf("Unknown command %s", command);
cl349@5872 840 fflush(stdout);
kaf24@6039 841 disarm_timeout();
kaf24@6039 842
kaf24@6039 843 /* Check expectations. */
kaf24@6039 844 if (!streq(command, "expect")) {
kaf24@6039 845 struct expect *i = list_top(&expects, struct expect, list);
kaf24@6039 846
kaf24@6039 847 if (i)
kaf24@6039 848 barf("Expected '%s', didn't happen\n", i->pattern);
kaf24@6039 849 }
cl349@5872 850 }
cl349@5872 851
kaf24@6039 852 static struct option options[] = { { "readonly", 0, NULL, 'r' },
kaf24@6039 853 { "no-timeout", 0, NULL, 't' },
kaf24@6039 854 { NULL, 0, NULL, 0 } };
kaf24@6039 855
cl349@5357 856 int main(int argc, char *argv[])
cl349@5357 857 {
kaf24@6039 858 int opt;
cl349@5357 859 char line[1024];
cl349@5357 860
kaf24@6039 861 while ((opt = getopt_long(argc, argv, "xrt", options, NULL)) != -1) {
kaf24@6039 862 switch (opt) {
kaf24@6039 863 case 'r':
kaf24@6039 864 readonly = true;
kaf24@6039 865 break;
kaf24@6039 866 case 't':
kaf24@6039 867 timeout_ms = 0;
kaf24@6039 868 break;
kaf24@6039 869 case 'x':
kaf24@6039 870 print_input = true;
kaf24@6039 871 break;
kaf24@6039 872 }
cl349@5357 873 }
cl349@5357 874
kaf24@6039 875 if (optind + 1 == argc) {
kaf24@6039 876 int fd = open(argv[optind], O_RDONLY);
kaf24@6039 877 if (!fd)
kaf24@6039 878 barf_perror("Opening %s", argv[optind]);
kaf24@6039 879 dup2(fd, STDIN_FILENO);
kaf24@6039 880 } else if (optind != argc)
cl349@5357 881 usage();
kaf24@6039 882
cl349@5357 883
cl349@5357 884 /* The size of the ringbuffer: half a page minus head structure. */
cl349@5357 885 ringbuf_datasize = getpagesize() / 2 - sizeof(struct ringbuf_head);
cl349@5357 886
cl349@5357 887 signal(SIGALRM, alarmed);
cl349@5872 888 while (fgets(line, sizeof(line), stdin))
cl349@5872 889 do_command(0, line);
cl349@5357 890
cl349@5357 891 return 0;
cl349@5357 892 }