~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to tools/xenstore/xenstore_client.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 */
 
10
 
 
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>
 
22
 
 
23
#include <sys/ioctl.h>
 
24
 
 
25
#define PATH_SEP '/'
 
26
#define MAX_PATH_LEN 256
 
27
 
 
28
#define MAX_PERMS 16
 
29
 
 
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
};
 
40
 
 
41
static char *output_buf = NULL;
 
42
static int output_pos = 0;
 
43
 
 
44
static int output_size = 0;
 
45
 
 
46
static void
 
47
output(const char *fmt, ...) {
 
48
    va_list ap;
 
49
    int len;
 
50
    char buf[1];
 
51
 
 
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
}
 
69
 
 
70
static void
 
71
usage(enum mode mode, int incl_mode, const char *progname)
 
72
{
 
73
    const char *mstr = NULL;
 
74
 
 
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
}
 
100
 
 
101
 
 
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
}
 
113
 
 
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;
 
118
 
 
119
#define TAG " = \"...\""
 
120
#define TAG_LEN strlen(TAG)
 
121
 
 
122
#define MIN(a, b) (((a) < (b))? (a) : (b))
 
123
 
 
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;
 
132
 
 
133
    e = xs_directory(h, XBT_NULL, path, &num);
 
134
    if (e == NULL)
 
135
        err(1, "xs_directory (%s)", path);
 
136
 
 
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;
 
142
 
 
143
        /* Compose fullpath */
 
144
        newpath_len = snprintf(newpath, sizeof(newpath), "%s%s%s", path, 
 
145
                path[strlen(path)-1] == '/' ? "" : "/", 
 
146
                e[i]);
 
147
 
 
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
        }
 
159
 
 
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
        }
 
169
 
 
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);
 
193
 
 
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
        }
 
211
 
 
212
        putchar('\n');
 
213
            
 
214
        do_ls(h, newpath, cur_depth+1, show_perms); 
 
215
    }
 
216
    free(e);
 
217
}
 
218
 
 
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;
 
224
 
 
225
    if (!path[0])
 
226
        return;
 
227
 
 
228
    ret = xs_set_permissions(xsh, xth, path, perms, nperms);
 
229
    if (!ret)
 
230
        err(1, "Error occurred setting permissions on '%s'", path);
 
231
 
 
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);
 
238
        
 
239
        *path_sep_ptr = '\0'; /* truncate path */
 
240
        
 
241
        do_chmod(path, perms, nperms, 1, 0, xsh, xth);
 
242
 
 
243
        *path_sep_ptr = PATH_SEP;
 
244
    }
 
245
 
 
246
    if (recurse) {
 
247
        char buf[MAX_PATH_LEN];
 
248
 
 
249
        /* apply same permissions to all child entries: */
 
250
        unsigned int xsval_n;
 
251
        char **xsval = xs_directory(xsh, xth, path, &xsval_n);
 
252
 
 
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]);
 
257
 
 
258
                do_chmod(buf, perms, nperms, 0, 1, xsh, xth);
 
259
            }
 
260
 
 
261
            free(xsval);
 
262
        }
 
263
    }
 
264
}
 
265
 
 
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
    }
 
282
 
 
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
            */
 
321
 
 
322
            char *slash, *path = argv[optind];
 
323
 
 
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;
 
330
 
 
331
            again:
 
332
                if (do_rm(path, xsh, xth)) {
 
333
                    return 1;
 
334
                }
 
335
 
 
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);
 
345
 
 
346
                        if (list) {
 
347
                            free(list);
 
348
                            if (num == 0)
 
349
                                goto again;
 
350
                        }
 
351
                    }
 
352
                }
 
353
 
 
354
                free(path);
 
355
            }
 
356
            else {
 
357
                if (do_rm(path, xsh, xth)) {
 
358
                    return 1;
 
359
                }
 
360
            }
 
361
 
 
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);
 
405
 
 
406
                perms[nperms].id = atoi(argv[optind]+1);
 
407
 
 
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
            }
 
427
 
 
428
            do_chmod(path, perms, nperms, upto, recurse, xsh, xth);
 
429
            break;
 
430
        }
 
431
        }
 
432
    }
 
433
 
 
434
    return 0;
 
435
}
 
436
 
 
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;
 
455
 
 
456
    errx(1, "unknown mode %s\n", m);
 
457
    return 0;
 
458
}
 
459
 
 
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;
 
473
 
 
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 */
 
477
 
 
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
    }
 
490
 
 
491
    mode = lookup_mode(command);
 
492
 
 
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
        };
 
505
 
 
506
        c = getopt_long(argc - switch_argv, argv + switch_argv, "hfsptur",
 
507
                        long_options, &index);
 
508
        if (c == -1)
 
509
            break;
 
510
 
 
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
    }
 
553
 
 
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
    }
 
569
 
 
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
    }
 
584
 
 
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
    }
 
592
 
 
593
    xsh = socket ? xs_daemon_open() : xs_domain_open();
 
594
    if (xsh == NULL)
 
595
        err(1, socket ? "xs_daemon_open" : "xs_domain_open");
 
596
 
 
597
again:
 
598
    if (transaction) {
 
599
        xth = xs_transaction_start(xsh);
 
600
        if (xth == XBT_NULL)
 
601
            errx(1, "couldn't start transaction");
 
602
    }
 
603
 
 
604
    ret = perform(mode, optind, argc - switch_argv, argv + switch_argv, xsh, xth, prefix, tidy, upto, recurse);
 
605
 
 
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
    }
 
613
 
 
614
    if (output_pos)
 
615
        printf("%s", output_buf);
 
616
 
 
617
    return ret;
 
618
}