source: trunk/packages/xen-3.1/xen-3.1/tools/xenstore/xenstore_client.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 8.3 KB
Line 
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 <xs.h>
20
21static char *output_buf = NULL;
22static int output_pos = 0;
23
24#if defined(CLIENT_read) || defined(CLIENT_list)
25static int output_size = 0;
26
27static void
28output(const char *fmt, ...) {
29    va_list ap;
30    int len;
31    char buf[1];
32
33    va_start(ap, fmt);
34    len = vsnprintf(buf, 1, fmt, ap);
35    if (len < 0)
36        err(1, "output");
37    va_end(ap);
38    if (len + 1 + output_pos > output_size) {
39        output_size += len + 1024;
40        output_buf = realloc(output_buf, output_size);
41        if (output_buf == NULL)
42            err(1, "malloc");
43    }
44    va_start(ap, fmt);
45    if (vsnprintf(&output_buf[output_pos], len + 1, fmt, ap) != len)
46        err(1, "output");
47    va_end(ap);
48    output_pos += len;
49}
50#endif
51
52static void
53usage(const char *progname)
54{
55#if defined(CLIENT_read)
56    errx(1, "Usage: %s [-h] [-p] [-s] key [...]", progname);
57#elif defined(CLIENT_write)
58    errx(1, "Usage: %s [-h] [-s] key value [...]", progname);
59#elif defined(CLIENT_rm)
60    errx(1, "Usage: %s [-h] [-s] [-t] key [...]", progname);
61#elif defined(CLIENT_exists) || defined(CLIENT_list)
62    errx(1, "Usage: %s [-h] [-s] key [...]", progname);
63#elif defined(CLIENT_chmod)
64    errx(1, "Usage: %s [-h] [-s] key <mode [modes...]>", progname);
65#endif
66}
67
68
69#if defined(CLIENT_rm)
70static int
71do_rm(char *path, struct xs_handle *xsh, xs_transaction_t xth)
72{
73    if (xs_rm(xsh, xth, path)) {
74        return 0;
75    }
76    else {
77        warnx("could not remove path %s", path);
78        return 1;
79    }
80}
81#endif
82
83#if defined(CLIENT_chmod)
84#define PATH_SEP '/'
85#define MAX_PATH_LEN 256
86
87static void
88do_chmod(char *path, struct xs_permissions *perms, int nperms, int upto,
89         int recurse, struct xs_handle *xsh, xs_transaction_t xth)
90{
91    int ret;
92
93    if (!path[0])
94        return;
95
96    ret = xs_set_permissions(xsh, xth, path, perms, nperms);
97    if (!ret)
98        err(1, "Error occurred setting permissions on '%s'", path);
99
100    if (upto) {
101        /* apply same permissions to all parent entries: */
102        char *path_sep_ptr = strrchr(path, PATH_SEP);
103        if (!path_sep_ptr)
104            errx(1, "Unable to locate path separator '%c' in '%s'",
105                 PATH_SEP, path);
106       
107        *path_sep_ptr = '\0'; /* truncate path */
108       
109        do_chmod(path, perms, nperms, 1, 0, xsh, xth);
110
111        *path_sep_ptr = PATH_SEP;
112    }
113
114    if (recurse) {
115        char buf[MAX_PATH_LEN];
116
117        /* apply same permissions to all child entries: */
118        unsigned int xsval_n;
119        char **xsval = xs_directory(xsh, xth, path, &xsval_n);
120
121        if (xsval) {
122            int i;
123            for (i = 0; i < xsval_n; i++) {
124                snprintf(buf, MAX_PATH_LEN, "%s/%s", path, xsval[i]);
125
126                do_chmod(buf, perms, nperms, 0, 1, xsh, xth);
127            }
128
129            free(xsval);
130        }
131    }
132}
133#endif
134
135static int
136perform(int optind, int argc, char **argv, struct xs_handle *xsh,
137        xs_transaction_t xth, int prefix, int tidy, int upto, int recurse)
138{
139    while (optind < argc) {
140#if defined(CLIENT_read)
141        char *val = xs_read(xsh, xth, argv[optind], NULL);
142        if (val == NULL) {
143            warnx("couldn't read path %s", argv[optind]);
144            return 1;
145        }
146        if (prefix)
147            output("%s: ", argv[optind]);
148        output("%s\n", val);
149        free(val);
150        optind++;
151#elif defined(CLIENT_write)
152        if (!xs_write(xsh, xth, argv[optind], argv[optind + 1],
153                      strlen(argv[optind + 1]))) {
154            warnx("could not write path %s", argv[optind]);
155            return 1;
156        }
157        optind += 2;
158#elif defined(CLIENT_rm)
159        /* Remove the specified path.  If the tidy flag is set, then also
160           remove any containing directories that are both empty and have no
161           value attached, and repeat, recursing all the way up to the root if
162           necessary.
163        */
164
165        char *slash, *path = argv[optind];
166
167        if (tidy) {
168            /* Copy path, because we can't modify argv because we will need it
169               again if xs_transaction_end gives us EAGAIN. */
170            char *p = malloc(strlen(path) + 1);
171            strcpy(p, path);
172            path = p;
173
174        again:
175            if (do_rm(path, xsh, xth)) {
176                return 1;
177            }
178
179            slash = strrchr(p, '/');
180            if (slash) {
181                char *val;
182                *slash = '\0';
183                val = xs_read(xsh, xth, p, NULL);
184                if (val && strlen(val) == 0) {
185                    unsigned int num;
186                    char ** list = xs_directory(xsh, xth, p, &num);
187
188                    if (list && num == 0) {
189                        goto again;
190                    }
191                }
192            }
193
194            free(path);
195        }
196        else {
197            if (do_rm(path, xsh, xth)) {
198                return 1;
199            }
200        }
201
202        optind++;
203#elif defined(CLIENT_exists)
204        char *val = xs_read(xsh, xth, argv[optind], NULL);
205        if (val == NULL) {
206            return 1;
207        }
208        free(val);
209        optind++;
210#elif defined(CLIENT_list)
211        unsigned int i, num;
212        char **list = xs_directory(xsh, xth, argv[optind], &num);
213        if (list == NULL) {
214            warnx("could not list path %s", argv[optind]);
215            return 1;
216        }
217        for (i = 0; i < num; i++) {
218            if (prefix)
219                output("%s/", argv[optind]);
220            output("%s\n", list[i]);
221        }
222        free(list);
223        optind++;
224#elif defined(CLIENT_chmod)
225#define MAX_PERMS 16
226        struct xs_permissions perms[MAX_PERMS];
227        int nperms = 0;
228        /* save path pointer: */
229        char *path = argv[optind++];
230        for (; argv[optind]; optind++, nperms++)
231        {
232            if (MAX_PERMS <= nperms)
233                errx(1, "Too many permissions specified.  "
234                     "Maximum per invocation is %d.", MAX_PERMS);
235
236            perms[nperms].id = atoi(argv[optind]+1);
237
238            switch (argv[optind][0])
239            {
240            case 'n':
241                perms[nperms].perms = XS_PERM_NONE;
242                break;
243            case 'r':
244                perms[nperms].perms = XS_PERM_READ;
245                break;
246            case 'w':
247                perms[nperms].perms = XS_PERM_WRITE;
248                break;
249            case 'b':
250                perms[nperms].perms = XS_PERM_READ | XS_PERM_WRITE;
251                break;
252            default:
253                errx(1, "Invalid permission specification: '%c'",
254                     argv[optind][0]);
255            }
256        }
257
258        do_chmod(path, perms, nperms, upto, recurse, xsh, xth);
259#endif
260    }
261
262    return 0;
263}
264
265
266int
267main(int argc, char **argv)
268{
269    struct xs_handle *xsh;
270    xs_transaction_t xth = XBT_NULL;
271    int ret = 0, socket = 0;
272    int prefix = 0;
273    int tidy = 0;
274    int upto = 0;
275    int recurse = 0;
276    int transaction;
277
278    while (1) {
279        int c, index = 0;
280        static struct option long_options[] = {
281            {"help", 0, 0, 'h'},
282            {"socket", 0, 0, 's'},
283#if defined(CLIENT_read) || defined(CLIENT_list)
284            {"prefix", 0, 0, 'p'},
285#elif defined(CLIENT_rm)
286            {"tidy",   0, 0, 't'},
287#elif defined(CLIENT_chmod)
288            {"upto",    0, 0, 'u'},
289            {"recurse", 0, 0, 'r'},
290#endif
291            {0, 0, 0, 0}
292        };
293
294        c = getopt_long(argc, argv, "hs"
295#if defined(CLIENT_read) || defined(CLIENT_list)
296                        "p"
297#elif defined(CLIENT_rm)
298                        "t"
299#elif defined(CLIENT_chmod)
300                        "ur"
301#endif
302                        , long_options, &index);
303        if (c == -1)
304            break;
305
306        switch (c) {
307        case 'h':
308            usage(argv[0]);
309            /* NOTREACHED */
310        case 's':
311            socket = 1;
312            break;
313#if defined(CLIENT_read) || defined(CLIENT_list)
314        case 'p':
315            prefix = 1;
316            break;
317#elif defined(CLIENT_rm)
318        case 't':
319            tidy = 1;
320            break;
321#elif defined(CLIENT_chmod)
322        case 'u':
323            upto = 1;
324            break;
325        case 'r':
326            recurse = 1;
327            break;
328#endif
329        }
330    }
331
332    if (optind == argc) {
333        usage(argv[0]);
334        /* NOTREACHED */
335    }
336#if defined(CLIENT_write)
337    if ((argc - optind) % 2 == 1) {
338        usage(argv[0]);
339        /* NOTREACHED */
340    }
341#endif
342
343#if defined(CLIENT_read)
344    transaction = (argc - optind) > 1;
345#elif defined(CLIENT_write)
346    transaction = (argc - optind) > 2;
347#else
348    transaction = 1;
349#endif
350
351    xsh = socket ? xs_daemon_open() : xs_domain_open();
352    if (xsh == NULL)
353        err(1, socket ? "xs_daemon_open" : "xs_domain_open");
354
355  again:
356    if (transaction) {
357        xth = xs_transaction_start(xsh);
358        if (xth == XBT_NULL)
359            errx(1, "couldn't start transaction");
360    }
361
362    ret = perform(optind, argc, argv, xsh, xth, prefix, tidy, upto, recurse);
363
364    if (transaction && !xs_transaction_end(xsh, xth, ret)) {
365        if (ret == 0 && errno == EAGAIN) {
366            output_pos = 0;
367            goto again;
368        }
369        errx(1, "couldn't end transaction");
370    }
371
372    if (output_pos)
373        printf("%s", output_buf);
374
375    return ret;
376}
Note: See TracBrowser for help on using the repository browser.