debuggers.hg

view tools/xenstore/xenstore_client.c @ 21067:b4a1832a916f

Update Xen version to 4.0.0-rc6
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 09 18:18:05 2010 +0000 (2010-03-09)
parents 1f315181731a
children bfb3c97ef507
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 };
41 static char *output_buf = NULL;
42 static int output_pos = 0;
44 static int output_size = 0;
46 static void
47 output(const char *fmt, ...) {
48 va_list ap;
49 int len;
50 char buf[1];
52 va_start(ap, fmt);
53 len = vsnprintf(buf, 1, fmt, ap);
54 if (len < 0)
55 err(1, "output");
56 va_end(ap);
57 if (len + 1 + output_pos > output_size) {
58 output_size += len + 1024;
59 output_buf = realloc(output_buf, output_size);
60 if (output_buf == NULL)
61 err(1, "malloc");
62 }
63 va_start(ap, fmt);
64 if (vsnprintf(&output_buf[output_pos], len + 1, fmt, ap) != len)
65 err(1, "output");
66 va_end(ap);
67 output_pos += len;
68 }
70 static void
71 usage(enum mode mode, int incl_mode, const char *progname)
72 {
73 const char *mstr = NULL;
75 switch (mode) {
76 case MODE_unknown:
77 errx(1, "Usage: %s <mode> [-h] [...]", progname);
78 case MODE_read:
79 mstr = incl_mode ? "read " : "";
80 errx(1, "Usage: %s %s[-h] [-p] [-s] key [...]", progname, mstr);
81 case MODE_write:
82 mstr = incl_mode ? "write " : "";
83 errx(1, "Usage: %s %s[-h] [-s] key value [...]", progname, mstr);
84 case MODE_rm:
85 mstr = incl_mode ? "rm " : "";
86 errx(1, "Usage: %s %s[-h] [-s] [-t] key [...]", progname, mstr);
87 case MODE_exists:
88 mstr = incl_mode ? "exists " : "";
89 case MODE_list:
90 mstr = mstr ? : incl_mode ? "list " : "";
91 errx(1, "Usage: %s %s[-h] [-p] [-s] key [...]", progname, mstr);
92 case MODE_ls:
93 mstr = mstr ? : incl_mode ? "ls " : "";
94 errx(1, "Usage: %s %s[-h] [-f] [-p] [-s] [path]", progname, mstr);
95 case MODE_chmod:
96 mstr = incl_mode ? "chmod " : "";
97 errx(1, "Usage: %s %s[-h] [-u] [-r] [-s] key <mode [modes...]>", progname, mstr);
98 }
99 }
102 static int
103 do_rm(char *path, struct xs_handle *xsh, xs_transaction_t xth)
104 {
105 if (xs_rm(xsh, xth, path)) {
106 return 0;
107 }
108 else {
109 warnx("could not remove path %s", path);
110 return 1;
111 }
112 }
114 #define STRING_MAX XENSTORE_ABS_PATH_MAX+1024
115 static int max_width = 80;
116 static int desired_width = 60;
117 static int show_whole_path = 0;
119 #define TAG " = \"...\""
120 #define TAG_LEN strlen(TAG)
122 #define MIN(a, b) (((a) < (b))? (a) : (b))
124 static void do_ls(struct xs_handle *h, char *path, int cur_depth, int show_perms)
125 {
126 static struct expanding_buffer ebuf;
127 char **e;
128 char newpath[STRING_MAX], *val;
129 int newpath_len;
130 int i;
131 unsigned int num, len;
133 e = xs_directory(h, XBT_NULL, path, &num);
134 if (e == NULL)
135 err(1, "xs_directory (%s)", path);
137 for (i = 0; i<num; i++) {
138 char buf[MAX_STRLEN(unsigned int)+1];
139 struct xs_permissions *perms;
140 unsigned int nperms;
141 int linewid;
143 /* Compose fullpath */
144 newpath_len = snprintf(newpath, sizeof(newpath), "%s%s%s", path,
145 path[strlen(path)-1] == '/' ? "" : "/",
146 e[i]);
148 /* Print indent and path basename */
149 linewid = 0;
150 if (show_whole_path) {
151 fputs(newpath, stdout);
152 } else {
153 for (; linewid<cur_depth; linewid++) {
154 putchar(' ');
155 }
156 linewid += printf("%.*s",
157 (int) (max_width - TAG_LEN - linewid), e[i]);
158 }
160 /* Fetch value */
161 if ( newpath_len < sizeof(newpath) ) {
162 val = xs_read(h, XBT_NULL, newpath, &len);
163 }
164 else {
165 /* Path was truncated and thus invalid */
166 val = NULL;
167 len = 0;
168 }
170 /* Print value */
171 if (val == NULL) {
172 printf(":\n");
173 }
174 else {
175 if (max_width < (linewid + len + TAG_LEN)) {
176 printf(" = \"%.*s\\...\"",
177 (int)(max_width - TAG_LEN - linewid),
178 sanitise_value(&ebuf, val, len));
179 }
180 else {
181 linewid += printf(" = \"%s\"",
182 sanitise_value(&ebuf, val, len));
183 if (show_perms) {
184 putchar(' ');
185 for (linewid++;
186 linewid < MIN(desired_width, max_width);
187 linewid++)
188 putchar((linewid & 1)? '.' : ' ');
189 }
190 }
191 }
192 free(val);
194 if (show_perms) {
195 perms = xs_get_permissions(h, XBT_NULL, newpath, &nperms);
196 if (perms == NULL) {
197 warn("\ncould not access permissions for %s", e[i]);
198 }
199 else {
200 int i;
201 fputs(" (", stdout);
202 for (i = 0; i < nperms; i++) {
203 if (i)
204 putchar(',');
205 xs_perm_to_string(perms+i, buf, sizeof(buf));
206 fputs(buf, stdout);
207 }
208 putchar(')');
209 }
210 }
212 putchar('\n');
214 do_ls(h, newpath, cur_depth+1, show_perms);
215 }
216 free(e);
217 }
219 static void
220 do_chmod(char *path, struct xs_permissions *perms, int nperms, int upto,
221 int recurse, struct xs_handle *xsh, xs_transaction_t xth)
222 {
223 int ret;
225 if (!path[0])
226 return;
228 ret = xs_set_permissions(xsh, xth, path, perms, nperms);
229 if (!ret)
230 err(1, "Error occurred setting permissions on '%s'", path);
232 if (upto) {
233 /* apply same permissions to all parent entries: */
234 char *path_sep_ptr = strrchr(path, PATH_SEP);
235 if (!path_sep_ptr)
236 errx(1, "Unable to locate path separator '%c' in '%s'",
237 PATH_SEP, path);
239 *path_sep_ptr = '\0'; /* truncate path */
241 do_chmod(path, perms, nperms, 1, 0, xsh, xth);
243 *path_sep_ptr = PATH_SEP;
244 }
246 if (recurse) {
247 char buf[MAX_PATH_LEN];
249 /* apply same permissions to all child entries: */
250 unsigned int xsval_n;
251 char **xsval = xs_directory(xsh, xth, path, &xsval_n);
253 if (xsval) {
254 int i;
255 for (i = 0; i < xsval_n; i++) {
256 snprintf(buf, MAX_PATH_LEN, "%s/%s", path, xsval[i]);
258 do_chmod(buf, perms, nperms, 0, 1, xsh, xth);
259 }
261 free(xsval);
262 }
263 }
264 }
266 static int
267 perform(enum mode mode, int optind, int argc, char **argv, struct xs_handle *xsh,
268 xs_transaction_t xth, int prefix, int tidy, int upto, int recurse)
269 {
270 switch (mode) {
271 case MODE_ls:
272 if (optind == argc)
273 {
274 optind=0;
275 argc=1;
276 argv[0] = "/";
277 }
278 break;
279 default:
280 break;
281 }
283 while (optind < argc) {
284 switch (mode) {
285 case MODE_unknown:
286 /* CANNOT BE REACHED */
287 errx(1, "invalid mode %d", mode);
288 case MODE_read: {
289 static struct expanding_buffer ebuf;
290 unsigned len;
291 char *val = xs_read(xsh, xth, argv[optind], &len);
292 if (val == NULL) {
293 warnx("couldn't read path %s", argv[optind]);
294 return 1;
295 }
296 if (prefix)
297 output("%s: ", argv[optind]);
298 output("%s\n", sanitise_value(&ebuf, val, len));
299 free(val);
300 optind++;
301 break;
302 }
303 case MODE_write: {
304 static struct expanding_buffer ebuf;
305 char *val_spec = argv[optind + 1];
306 unsigned len;
307 expanding_buffer_ensure(&ebuf, strlen(val_spec)+1);
308 unsanitise_value(ebuf.buf, &len, val_spec);
309 if (!xs_write(xsh, xth, argv[optind], ebuf.buf, len)) {
310 warnx("could not write path %s", argv[optind]);
311 return 1;
312 }
313 optind += 2;
314 } break;
315 case MODE_rm: {
316 /* Remove the specified path. If the tidy flag is set, then also
317 remove any containing directories that are both empty and have no
318 value attached, and repeat, recursing all the way up to the root if
319 necessary.
320 */
322 char *slash, *path = argv[optind];
324 if (tidy) {
325 /* Copy path, because we can't modify argv because we will need it
326 again if xs_transaction_end gives us EAGAIN. */
327 char *p = malloc(strlen(path) + 1);
328 strcpy(p, path);
329 path = p;
331 again:
332 if (do_rm(path, xsh, xth)) {
333 return 1;
334 }
336 slash = strrchr(p, '/');
337 if (slash) {
338 char *val;
339 unsigned len;
340 *slash = '\0';
341 val = xs_read(xsh, xth, p, &len);
342 if (val && len == 0) {
343 unsigned int num;
344 char ** list = xs_directory(xsh, xth, p, &num);
346 if (list) {
347 free(list);
348 if (num == 0)
349 goto again;
350 }
351 }
352 }
354 free(path);
355 }
356 else {
357 if (do_rm(path, xsh, xth)) {
358 return 1;
359 }
360 }
362 optind++;
363 break;
364 }
365 case MODE_exists: {
366 char *val = xs_read(xsh, xth, argv[optind], NULL);
367 if (val == NULL) {
368 return 1;
369 }
370 free(val);
371 optind++;
372 break;
373 }
374 case MODE_list: {
375 unsigned int i, num;
376 char **list = xs_directory(xsh, xth, argv[optind], &num);
377 if (list == NULL) {
378 warnx("could not list path %s", argv[optind]);
379 return 1;
380 }
381 for (i = 0; i < num; i++) {
382 if (prefix)
383 output("%s/", argv[optind]);
384 output("%s\n", list[i]);
385 }
386 free(list);
387 optind++;
388 break;
389 }
390 case MODE_ls: {
391 do_ls(xsh, argv[optind], 0, prefix);
392 optind++;
393 break;
394 }
395 case MODE_chmod: {
396 struct xs_permissions perms[MAX_PERMS];
397 int nperms = 0;
398 /* save path pointer: */
399 char *path = argv[optind++];
400 for (; argv[optind]; optind++, nperms++)
401 {
402 if (MAX_PERMS <= nperms)
403 errx(1, "Too many permissions specified. "
404 "Maximum per invocation is %d.", MAX_PERMS);
406 perms[nperms].id = atoi(argv[optind]+1);
408 switch (argv[optind][0])
409 {
410 case 'n':
411 perms[nperms].perms = XS_PERM_NONE;
412 break;
413 case 'r':
414 perms[nperms].perms = XS_PERM_READ;
415 break;
416 case 'w':
417 perms[nperms].perms = XS_PERM_WRITE;
418 break;
419 case 'b':
420 perms[nperms].perms = XS_PERM_READ | XS_PERM_WRITE;
421 break;
422 default:
423 errx(1, "Invalid permission specification: '%c'",
424 argv[optind][0]);
425 }
426 }
428 do_chmod(path, perms, nperms, upto, recurse, xsh, xth);
429 break;
430 }
431 }
432 }
434 return 0;
435 }
437 static enum mode lookup_mode(const char *m)
438 {
439 if (strcmp(m, "read") == 0)
440 return MODE_read;
441 else if (strcmp(m, "chmod") == 0)
442 return MODE_chmod;
443 else if (strcmp(m, "exists") == 0)
444 return MODE_exists;
445 else if (strcmp(m, "list") == 0)
446 return MODE_list;
447 else if (strcmp(m, "ls") == 0)
448 return MODE_ls;
449 else if (strcmp(m, "rm") == 0)
450 return MODE_rm;
451 else if (strcmp(m, "write") == 0)
452 return MODE_write;
453 else if (strcmp(m, "read") == 0)
454 return MODE_read;
456 errx(1, "unknown mode %s\n", m);
457 return 0;
458 }
460 int
461 main(int argc, char **argv)
462 {
463 struct xs_handle *xsh;
464 xs_transaction_t xth = XBT_NULL;
465 int ret = 0, socket = 0;
466 int prefix = 0;
467 int tidy = 0;
468 int upto = 0;
469 int recurse = 0;
470 int transaction;
471 struct winsize ws;
472 enum mode mode;
474 const char *_command = strrchr(argv[0], '/');
475 const char *command = _command ? &_command[1] : argv[0];
476 int switch_argv = -1; /* which element of argv did we switch on */
478 if (strncmp(command, "xenstore-", strlen("xenstore-")) == 0)
479 {
480 switch_argv = 0;
481 command = command + strlen("xenstore-");
482 }
483 else if (argc < 2)
484 usage(MODE_unknown, 0, argv[0]);
485 else
486 {
487 command = argv[1];
488 switch_argv = 1;
489 }
491 mode = lookup_mode(command);
493 while (1) {
494 int c, index = 0;
495 static struct option long_options[] = {
496 {"help", 0, 0, 'h'},
497 {"flat", 0, 0, 'f'}, /* MODE_ls */
498 {"socket", 0, 0, 's'},
499 {"prefix", 0, 0, 'p'}, /* MODE_read || MODE_list || MODE_ls */
500 {"tidy", 0, 0, 't'}, /* MODE_rm */
501 {"upto", 0, 0, 'u'}, /* MODE_chmod */
502 {"recurse", 0, 0, 'r'}, /* MODE_chmod */
503 {0, 0, 0, 0}
504 };
506 c = getopt_long(argc - switch_argv, argv + switch_argv, "hfsptur",
507 long_options, &index);
508 if (c == -1)
509 break;
511 switch (c) {
512 case 'h':
513 usage(mode, switch_argv, argv[0]);
514 /* NOTREACHED */
515 case 'f':
516 if ( mode == MODE_ls ) {
517 max_width = INT_MAX/2;
518 desired_width = 0;
519 show_whole_path = 1;
520 } else {
521 usage(mode, switch_argv, argv[0]);
522 }
523 break;
524 case 's':
525 socket = 1;
526 break;
527 case 'p':
528 if ( mode == MODE_read || mode == MODE_list || mode == MODE_ls )
529 prefix = 1;
530 else
531 usage(mode, switch_argv, argv[0]);
532 break;
533 case 't':
534 if ( mode == MODE_rm )
535 tidy = 1;
536 else
537 usage(mode, switch_argv, argv[0]);
538 break;
539 case 'u':
540 if ( mode == MODE_chmod )
541 upto = 1;
542 else
543 usage(mode, switch_argv, argv[0]);
544 break;
545 case 'r':
546 if ( mode == MODE_chmod )
547 recurse = 1;
548 else
549 usage(mode, switch_argv, argv[0]);
550 break;
551 }
552 }
554 switch (mode) {
555 case MODE_ls:
556 break;
557 case MODE_write:
558 if ((argc - switch_argv - optind) % 2 == 1) {
559 usage(mode, switch_argv, argv[0]);
560 /* NOTREACHED */
561 }
562 /* DROP-THRU */
563 default:
564 if (optind == argc - switch_argv) {
565 usage(mode, switch_argv, argv[0]);
566 /* NOTREACHED */
567 }
568 }
570 switch (mode) {
571 case MODE_read:
572 transaction = (argc - switch_argv - optind) > 1;
573 break;
574 case MODE_write:
575 transaction = (argc - switch_argv - optind) > 2;
576 break;
577 case MODE_ls:
578 transaction = 0;
579 break;
580 default:
581 transaction = 1;
582 break;
583 }
585 if ( mode == MODE_ls )
586 {
587 memset(&ws, 0, sizeof(ws));
588 ret = ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
589 if (!ret)
590 max_width = ws.ws_col - 2;
591 }
593 xsh = socket ? xs_daemon_open() : xs_domain_open();
594 if (xsh == NULL)
595 err(1, socket ? "xs_daemon_open" : "xs_domain_open");
597 again:
598 if (transaction) {
599 xth = xs_transaction_start(xsh);
600 if (xth == XBT_NULL)
601 errx(1, "couldn't start transaction");
602 }
604 ret = perform(mode, optind, argc - switch_argv, argv + switch_argv, xsh, xth, prefix, tidy, upto, recurse);
606 if (transaction && !xs_transaction_end(xsh, xth, ret)) {
607 if (ret == 0 && errno == EAGAIN) {
608 output_pos = 0;
609 goto again;
610 }
611 errx(1, "couldn't end transaction");
612 }
614 if (output_pos)
615 printf("%s", output_buf);
617 return ret;
618 }