debuggers.hg

view tools/xenstore/xenstore_client.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 f46d49257da5
children
line source
1 /*
2 * This file is subject to the terms and conditions of the GNU General
3 * Public License. See the file "COPYING" in the main directory of
4 * this archive for more details.
5 *
6 * Copyright (C) 2005 by Christian Limpach
7 * Copyright (C) 2005 XenSource Ltd.
8 *
9 */
11 #include <err.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <getopt.h>
15 #include <stdarg.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <termios.h>
20 #include <unistd.h>
21 #include <xs.h>
23 #include <sys/ioctl.h>
25 #define PATH_SEP '/'
26 #define MAX_PATH_LEN 256
28 #define MAX_PERMS 16
30 enum mode {
31 MODE_unknown,
32 MODE_chmod,
33 MODE_exists,
34 MODE_list,
35 MODE_ls,
36 MODE_read,
37 MODE_rm,
38 MODE_write,
39 MODE_watch,
40 };
42 static char *output_buf = NULL;
43 static int output_pos = 0;
45 static int output_size = 0;
47 static void
48 output(const char *fmt, ...) {
49 va_list ap;
50 int len;
51 char buf[1];
53 va_start(ap, fmt);
54 len = vsnprintf(buf, 1, fmt, ap);
55 if (len < 0)
56 err(1, "output");
57 va_end(ap);
58 if (len + 1 + output_pos > output_size) {
59 output_size += len + 1024;
60 output_buf = realloc(output_buf, output_size);
61 if (output_buf == NULL)
62 err(1, "malloc");
63 }
64 va_start(ap, fmt);
65 if (vsnprintf(&output_buf[output_pos], len + 1, fmt, ap) != len)
66 err(1, "output");
67 va_end(ap);
68 output_pos += len;
69 }
71 static void
72 usage(enum mode mode, int incl_mode, const char *progname)
73 {
74 const char *mstr = NULL;
76 switch (mode) {
77 case MODE_unknown:
78 errx(1, "Usage: %s <mode> [-h] [...]", progname);
79 case MODE_read:
80 mstr = incl_mode ? "read " : "";
81 errx(1, "Usage: %s %s[-h] [-p] [-s] key [...]", progname, mstr);
82 case MODE_write:
83 mstr = incl_mode ? "write " : "";
84 errx(1, "Usage: %s %s[-h] [-s] key value [...]", progname, mstr);
85 case MODE_rm:
86 mstr = incl_mode ? "rm " : "";
87 errx(1, "Usage: %s %s[-h] [-s] [-t] key [...]", progname, mstr);
88 case MODE_exists:
89 mstr = incl_mode ? "exists " : "";
90 case MODE_list:
91 mstr = mstr ? : incl_mode ? "list " : "";
92 errx(1, "Usage: %s %s[-h] [-p] [-s] key [...]", progname, mstr);
93 case MODE_ls:
94 mstr = mstr ? : incl_mode ? "ls " : "";
95 errx(1, "Usage: %s %s[-h] [-f] [-p] [-s] [path]", progname, mstr);
96 case MODE_chmod:
97 mstr = incl_mode ? "chmod " : "";
98 errx(1, "Usage: %s %s[-h] [-u] [-r] [-s] key <mode [modes...]>", progname, mstr);
99 case MODE_watch:
100 mstr = incl_mode ? "watch " : "";
101 errx(1, "Usage: %s %s[-h] [-n NR] key", progname, mstr);
102 }
103 }
106 static int
107 do_rm(char *path, struct xs_handle *xsh, xs_transaction_t xth)
108 {
109 if (xs_rm(xsh, xth, path)) {
110 return 0;
111 }
112 else {
113 warnx("could not remove path %s", path);
114 return 1;
115 }
116 }
118 #define STRING_MAX XENSTORE_ABS_PATH_MAX+1024
119 static int max_width = 80;
120 static int desired_width = 60;
121 static int show_whole_path = 0;
123 #define TAG " = \"...\""
124 #define TAG_LEN strlen(TAG)
126 #define MIN(a, b) (((a) < (b))? (a) : (b))
128 static void do_ls(struct xs_handle *h, char *path, int cur_depth, int show_perms)
129 {
130 static struct expanding_buffer ebuf;
131 char **e;
132 char newpath[STRING_MAX], *val;
133 int newpath_len;
134 int i;
135 unsigned int num, len;
137 e = xs_directory(h, XBT_NULL, path, &num);
138 if (e == NULL)
139 err(1, "xs_directory (%s)", path);
141 for (i = 0; i<num; i++) {
142 char buf[MAX_STRLEN(unsigned int)+1];
143 struct xs_permissions *perms;
144 unsigned int nperms;
145 int linewid;
147 /* Compose fullpath */
148 newpath_len = snprintf(newpath, sizeof(newpath), "%s%s%s", path,
149 path[strlen(path)-1] == '/' ? "" : "/",
150 e[i]);
152 /* Print indent and path basename */
153 linewid = 0;
154 if (show_whole_path) {
155 fputs(newpath, stdout);
156 } else {
157 for (; linewid<cur_depth; linewid++) {
158 putchar(' ');
159 }
160 linewid += printf("%.*s",
161 (int) (max_width - TAG_LEN - linewid), e[i]);
162 }
164 /* Fetch value */
165 if ( newpath_len < sizeof(newpath) ) {
166 val = xs_read(h, XBT_NULL, newpath, &len);
167 }
168 else {
169 /* Path was truncated and thus invalid */
170 val = NULL;
171 len = 0;
172 }
174 /* Print value */
175 if (val == NULL) {
176 printf(":\n");
177 }
178 else {
179 if (max_width < (linewid + len + TAG_LEN)) {
180 printf(" = \"%.*s\\...\"",
181 (int)(max_width - TAG_LEN - linewid),
182 sanitise_value(&ebuf, val, len));
183 }
184 else {
185 linewid += printf(" = \"%s\"",
186 sanitise_value(&ebuf, val, len));
187 if (show_perms) {
188 putchar(' ');
189 for (linewid++;
190 linewid < MIN(desired_width, max_width);
191 linewid++)
192 putchar((linewid & 1)? '.' : ' ');
193 }
194 }
195 }
196 free(val);
198 if (show_perms) {
199 perms = xs_get_permissions(h, XBT_NULL, newpath, &nperms);
200 if (perms == NULL) {
201 warn("\ncould not access permissions for %s", e[i]);
202 }
203 else {
204 int i;
205 fputs(" (", stdout);
206 for (i = 0; i < nperms; i++) {
207 if (i)
208 putchar(',');
209 xs_perm_to_string(perms+i, buf, sizeof(buf));
210 fputs(buf, stdout);
211 }
212 putchar(')');
213 }
214 }
216 putchar('\n');
218 do_ls(h, newpath, cur_depth+1, show_perms);
219 }
220 free(e);
221 }
223 static void
224 do_chmod(char *path, struct xs_permissions *perms, int nperms, int upto,
225 int recurse, struct xs_handle *xsh, xs_transaction_t xth)
226 {
227 int ret;
229 if (!path[0])
230 return;
232 ret = xs_set_permissions(xsh, xth, path, perms, nperms);
233 if (!ret)
234 err(1, "Error occurred setting permissions on '%s'", path);
236 if (upto) {
237 /* apply same permissions to all parent entries: */
238 char *path_sep_ptr = strrchr(path, PATH_SEP);
239 if (!path_sep_ptr)
240 errx(1, "Unable to locate path separator '%c' in '%s'",
241 PATH_SEP, path);
243 *path_sep_ptr = '\0'; /* truncate path */
245 do_chmod(path, perms, nperms, 1, 0, xsh, xth);
247 *path_sep_ptr = PATH_SEP;
248 }
250 if (recurse) {
251 char buf[MAX_PATH_LEN];
253 /* apply same permissions to all child entries: */
254 unsigned int xsval_n;
255 char **xsval = xs_directory(xsh, xth, path, &xsval_n);
257 if (xsval) {
258 int i;
259 for (i = 0; i < xsval_n; i++) {
260 snprintf(buf, MAX_PATH_LEN, "%s/%s", path, xsval[i]);
262 do_chmod(buf, perms, nperms, 0, 1, xsh, xth);
263 }
265 free(xsval);
266 }
267 }
268 }
270 static void
271 do_watch(struct xs_handle *xsh, int max_events)
272 {
273 int count = 0;
274 char **vec = NULL;
276 for ( count = 0; max_events == -1 || count < max_events; count++ ) {
277 unsigned int num;
279 vec = xs_read_watch(xsh, &num);
280 if (vec == NULL)
281 continue;
283 printf("%s\n", vec[XS_WATCH_PATH]);
284 fflush(stdout);
285 free(vec);
286 }
287 }
289 static int
290 perform(enum mode mode, int optind, int argc, char **argv, struct xs_handle *xsh,
291 xs_transaction_t xth, int prefix, int tidy, int upto, int recurse, int nr_watches)
292 {
293 switch (mode) {
294 case MODE_ls:
295 if (optind == argc)
296 {
297 optind=0;
298 argc=1;
299 argv[0] = "/";
300 }
301 break;
302 default:
303 break;
304 }
306 while (optind < argc) {
307 switch (mode) {
308 case MODE_unknown:
309 /* CANNOT BE REACHED */
310 errx(1, "invalid mode %d", mode);
311 case MODE_read: {
312 static struct expanding_buffer ebuf;
313 unsigned len;
314 char *val = xs_read(xsh, xth, argv[optind], &len);
315 if (val == NULL) {
316 warnx("couldn't read path %s", argv[optind]);
317 return 1;
318 }
319 if (prefix)
320 output("%s: ", argv[optind]);
321 output("%s\n", sanitise_value(&ebuf, val, len));
322 free(val);
323 optind++;
324 break;
325 }
326 case MODE_write: {
327 static struct expanding_buffer ebuf;
328 char *val_spec = argv[optind + 1];
329 unsigned len;
330 expanding_buffer_ensure(&ebuf, strlen(val_spec)+1);
331 unsanitise_value(ebuf.buf, &len, val_spec);
332 if (!xs_write(xsh, xth, argv[optind], ebuf.buf, len)) {
333 warnx("could not write path %s", argv[optind]);
334 return 1;
335 }
336 optind += 2;
337 } break;
338 case MODE_rm: {
339 /* Remove the specified path. If the tidy flag is set, then also
340 remove any containing directories that are both empty and have no
341 value attached, and repeat, recursing all the way up to the root if
342 necessary.
343 */
345 char *slash, *path = argv[optind];
347 if (tidy) {
348 /* Copy path, because we can't modify argv because we will need it
349 again if xs_transaction_end gives us EAGAIN. */
350 char *p = malloc(strlen(path) + 1);
351 strcpy(p, path);
352 path = p;
354 again:
355 if (do_rm(path, xsh, xth)) {
356 return 1;
357 }
359 slash = strrchr(p, '/');
360 if (slash) {
361 char *val;
362 unsigned len;
363 *slash = '\0';
364 val = xs_read(xsh, xth, p, &len);
365 if (val && len == 0) {
366 unsigned int num;
367 char ** list = xs_directory(xsh, xth, p, &num);
369 if (list) {
370 free(list);
371 if (num == 0)
372 goto again;
373 }
374 }
375 }
377 free(path);
378 }
379 else {
380 if (do_rm(path, xsh, xth)) {
381 return 1;
382 }
383 }
385 optind++;
386 break;
387 }
388 case MODE_exists: {
389 char *val = xs_read(xsh, xth, argv[optind], NULL);
390 if (val == NULL) {
391 return 1;
392 }
393 free(val);
394 optind++;
395 break;
396 }
397 case MODE_list: {
398 unsigned int i, num;
399 char **list = xs_directory(xsh, xth, argv[optind], &num);
400 if (list == NULL) {
401 warnx("could not list path %s", argv[optind]);
402 return 1;
403 }
404 for (i = 0; i < num; i++) {
405 if (prefix)
406 output("%s/", argv[optind]);
407 output("%s\n", list[i]);
408 }
409 free(list);
410 optind++;
411 break;
412 }
413 case MODE_ls: {
414 do_ls(xsh, argv[optind], 0, prefix);
415 optind++;
416 break;
417 }
418 case MODE_chmod: {
419 struct xs_permissions perms[MAX_PERMS];
420 int nperms = 0;
421 /* save path pointer: */
422 char *path = argv[optind++];
423 for (; argv[optind]; optind++, nperms++)
424 {
425 if (MAX_PERMS <= nperms)
426 errx(1, "Too many permissions specified. "
427 "Maximum per invocation is %d.", MAX_PERMS);
429 perms[nperms].id = atoi(argv[optind]+1);
431 switch (argv[optind][0])
432 {
433 case 'n':
434 perms[nperms].perms = XS_PERM_NONE;
435 break;
436 case 'r':
437 perms[nperms].perms = XS_PERM_READ;
438 break;
439 case 'w':
440 perms[nperms].perms = XS_PERM_WRITE;
441 break;
442 case 'b':
443 perms[nperms].perms = XS_PERM_READ | XS_PERM_WRITE;
444 break;
445 default:
446 errx(1, "Invalid permission specification: '%c'",
447 argv[optind][0]);
448 }
449 }
451 do_chmod(path, perms, nperms, upto, recurse, xsh, xth);
452 break;
453 }
454 case MODE_watch: {
455 for (; argv[optind]; optind++) {
456 const char *w = argv[optind];
458 if (!xs_watch(xsh, w, w))
459 errx(1, "Unable to add watch on %s\n", w);
460 }
461 do_watch(xsh, nr_watches);
462 }
463 }
464 }
466 return 0;
467 }
469 static enum mode lookup_mode(const char *m)
470 {
471 if (strcmp(m, "read") == 0)
472 return MODE_read;
473 else if (strcmp(m, "chmod") == 0)
474 return MODE_chmod;
475 else if (strcmp(m, "exists") == 0)
476 return MODE_exists;
477 else if (strcmp(m, "list") == 0)
478 return MODE_list;
479 else if (strcmp(m, "ls") == 0)
480 return MODE_ls;
481 else if (strcmp(m, "rm") == 0)
482 return MODE_rm;
483 else if (strcmp(m, "write") == 0)
484 return MODE_write;
485 else if (strcmp(m, "read") == 0)
486 return MODE_read;
487 else if (strcmp(m, "watch") == 0)
488 return MODE_watch;
490 errx(1, "unknown mode %s\n", m);
491 return 0;
492 }
494 int
495 main(int argc, char **argv)
496 {
497 struct xs_handle *xsh;
498 xs_transaction_t xth = XBT_NULL;
499 int ret = 0, socket = 0;
500 int prefix = 0;
501 int tidy = 0;
502 int upto = 0;
503 int recurse = 0;
504 int nr_watches = -1;
505 int transaction;
506 struct winsize ws;
507 enum mode mode;
509 const char *_command = strrchr(argv[0], '/');
510 const char *command = _command ? &_command[1] : argv[0];
511 int switch_argv = -1; /* which element of argv did we switch on */
513 if (strncmp(command, "xenstore-", strlen("xenstore-")) == 0)
514 {
515 switch_argv = 0;
516 command = command + strlen("xenstore-");
517 }
518 else if (argc < 2)
519 usage(MODE_unknown, 0, argv[0]);
520 else
521 {
522 command = argv[1];
523 switch_argv = 1;
524 }
526 mode = lookup_mode(command);
528 while (1) {
529 int c, index = 0;
530 static struct option long_options[] = {
531 {"help", 0, 0, 'h'},
532 {"flat", 0, 0, 'f'}, /* MODE_ls */
533 {"socket", 0, 0, 's'},
534 {"prefix", 0, 0, 'p'}, /* MODE_read || MODE_list || MODE_ls */
535 {"tidy", 0, 0, 't'}, /* MODE_rm */
536 {"upto", 0, 0, 'u'}, /* MODE_chmod */
537 {"recurse", 0, 0, 'r'}, /* MODE_chmod */
538 {"number", 1, 0, 'n'}, /* MODE_watch */
539 {0, 0, 0, 0}
540 };
542 c = getopt_long(argc - switch_argv, argv + switch_argv, "hfspturn:",
543 long_options, &index);
544 if (c == -1)
545 break;
547 switch (c) {
548 case 'h':
549 usage(mode, switch_argv, argv[0]);
550 /* NOTREACHED */
551 case 'f':
552 if ( mode == MODE_ls ) {
553 max_width = INT_MAX/2;
554 desired_width = 0;
555 show_whole_path = 1;
556 } else {
557 usage(mode, switch_argv, argv[0]);
558 }
559 break;
560 case 's':
561 socket = 1;
562 break;
563 case 'p':
564 if ( mode == MODE_read || mode == MODE_list || mode == MODE_ls )
565 prefix = 1;
566 else
567 usage(mode, switch_argv, argv[0]);
568 break;
569 case 't':
570 if ( mode == MODE_rm )
571 tidy = 1;
572 else
573 usage(mode, switch_argv, argv[0]);
574 break;
575 case 'u':
576 if ( mode == MODE_chmod )
577 upto = 1;
578 else
579 usage(mode, switch_argv, argv[0]);
580 break;
581 case 'r':
582 if ( mode == MODE_chmod )
583 recurse = 1;
584 else
585 usage(mode, switch_argv, argv[0]);
586 break;
587 case 'n':
588 if ( mode == MODE_watch )
589 nr_watches = atoi(optarg);
590 else
591 usage(mode, switch_argv, argv[0]);
592 break;
593 }
594 }
596 switch (mode) {
597 case MODE_ls:
598 break;
599 case MODE_write:
600 if ((argc - switch_argv - optind) % 2 == 1) {
601 usage(mode, switch_argv, argv[0]);
602 /* NOTREACHED */
603 }
604 /* DROP-THRU */
605 default:
606 if (optind == argc - switch_argv) {
607 usage(mode, switch_argv, argv[0]);
608 /* NOTREACHED */
609 }
610 }
612 switch (mode) {
613 case MODE_read:
614 transaction = (argc - switch_argv - optind) > 1;
615 break;
616 case MODE_write:
617 transaction = (argc - switch_argv - optind) > 2;
618 break;
619 case MODE_ls:
620 case MODE_watch:
621 transaction = 0;
622 break;
623 default:
624 transaction = 1;
625 break;
626 }
628 if ( mode == MODE_ls )
629 {
630 memset(&ws, 0, sizeof(ws));
631 ret = ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
632 if (!ret)
633 max_width = ws.ws_col - 2;
634 }
636 xsh = xs_open(socket ? XS_OPEN_SOCKETONLY : 0);
637 if (xsh == NULL) err(1, "xs_open");
639 again:
640 if (transaction) {
641 xth = xs_transaction_start(xsh);
642 if (xth == XBT_NULL)
643 errx(1, "couldn't start transaction");
644 }
646 ret = perform(mode, optind, argc - switch_argv, argv + switch_argv, xsh, xth, prefix, tidy, upto, recurse, nr_watches);
648 if (transaction && !xs_transaction_end(xsh, xth, ret)) {
649 if (ret == 0 && errno == EAGAIN) {
650 output_pos = 0;
651 goto again;
652 }
653 errx(1, "couldn't end transaction");
654 }
656 if (output_pos)
657 printf("%s", output_buf);
659 return ret;
660 }