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.
6
* Copyright (C) 2005 by Christian Limpach
7
* Copyright (C) 2005 XenSource Ltd.
23
#include <sys/ioctl.h>
26
#define MAX_PATH_LEN 256
41
static char *output_buf = NULL;
42
static int output_pos = 0;
44
static int output_size = 0;
47
output(const char *fmt, ...) {
53
len = vsnprintf(buf, 1, fmt, 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)
64
if (vsnprintf(&output_buf[output_pos], len + 1, fmt, ap) != len)
71
usage(enum mode mode, int incl_mode, const char *progname)
73
const char *mstr = NULL;
77
errx(1, "Usage: %s <mode> [-h] [...]", progname);
79
mstr = incl_mode ? "read " : "";
80
errx(1, "Usage: %s %s[-h] [-p] [-s] key [...]", progname, mstr);
82
mstr = incl_mode ? "write " : "";
83
errx(1, "Usage: %s %s[-h] [-s] key value [...]", progname, mstr);
85
mstr = incl_mode ? "rm " : "";
86
errx(1, "Usage: %s %s[-h] [-s] [-t] key [...]", progname, mstr);
88
mstr = incl_mode ? "exists " : "";
90
mstr = mstr ? : incl_mode ? "list " : "";
91
errx(1, "Usage: %s %s[-h] [-p] [-s] key [...]", progname, mstr);
93
mstr = mstr ? : incl_mode ? "ls " : "";
94
errx(1, "Usage: %s %s[-h] [-f] [-p] [-s] [path]", progname, mstr);
96
mstr = incl_mode ? "chmod " : "";
97
errx(1, "Usage: %s %s[-h] [-u] [-r] [-s] key <mode [modes...]>", progname, mstr);
103
do_rm(char *path, struct xs_handle *xsh, xs_transaction_t xth)
105
if (xs_rm(xsh, xth, path)) {
109
warnx("could not remove path %s", path);
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)
126
static struct expanding_buffer ebuf;
128
char newpath[STRING_MAX], *val;
131
unsigned int num, len;
133
e = xs_directory(h, XBT_NULL, path, &num);
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;
143
/* Compose fullpath */
144
newpath_len = snprintf(newpath, sizeof(newpath), "%s%s%s", path,
145
path[strlen(path)-1] == '/' ? "" : "/",
148
/* Print indent and path basename */
150
if (show_whole_path) {
151
fputs(newpath, stdout);
153
for (; linewid<cur_depth; linewid++) {
156
linewid += printf("%.*s",
157
(int) (max_width - TAG_LEN - linewid), e[i]);
161
if ( newpath_len < sizeof(newpath) ) {
162
val = xs_read(h, XBT_NULL, newpath, &len);
165
/* Path was truncated and thus invalid */
175
if (max_width < (linewid + len + TAG_LEN)) {
176
printf(" = \"%.*s\\...\"",
177
(int)(max_width - TAG_LEN - linewid),
178
sanitise_value(&ebuf, val, len));
181
linewid += printf(" = \"%s\"",
182
sanitise_value(&ebuf, val, len));
186
linewid < MIN(desired_width, max_width);
188
putchar((linewid & 1)? '.' : ' ');
195
perms = xs_get_permissions(h, XBT_NULL, newpath, &nperms);
197
warn("\ncould not access permissions for %s", e[i]);
202
for (i = 0; i < nperms; i++) {
205
xs_perm_to_string(perms+i, buf, sizeof(buf));
214
do_ls(h, newpath, cur_depth+1, show_perms);
220
do_chmod(char *path, struct xs_permissions *perms, int nperms, int upto,
221
int recurse, struct xs_handle *xsh, xs_transaction_t xth)
228
ret = xs_set_permissions(xsh, xth, path, perms, nperms);
230
err(1, "Error occurred setting permissions on '%s'", path);
233
/* apply same permissions to all parent entries: */
234
char *path_sep_ptr = strrchr(path, PATH_SEP);
236
errx(1, "Unable to locate path separator '%c' in '%s'",
239
*path_sep_ptr = '\0'; /* truncate path */
241
do_chmod(path, perms, nperms, 1, 0, xsh, xth);
243
*path_sep_ptr = PATH_SEP;
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);
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);
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)
283
while (optind < argc) {
286
/* CANNOT BE REACHED */
287
errx(1, "invalid mode %d", mode);
289
static struct expanding_buffer ebuf;
291
char *val = xs_read(xsh, xth, argv[optind], &len);
293
warnx("couldn't read path %s", argv[optind]);
297
output("%s: ", argv[optind]);
298
output("%s\n", sanitise_value(&ebuf, val, len));
304
static struct expanding_buffer ebuf;
305
char *val_spec = argv[optind + 1];
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]);
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
322
char *slash, *path = argv[optind];
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);
332
if (do_rm(path, xsh, xth)) {
336
slash = strrchr(p, '/');
341
val = xs_read(xsh, xth, p, &len);
342
if (val && len == 0) {
344
char ** list = xs_directory(xsh, xth, p, &num);
357
if (do_rm(path, xsh, xth)) {
366
char *val = xs_read(xsh, xth, argv[optind], NULL);
376
char **list = xs_directory(xsh, xth, argv[optind], &num);
378
warnx("could not list path %s", argv[optind]);
381
for (i = 0; i < num; i++) {
383
output("%s/", argv[optind]);
384
output("%s\n", list[i]);
391
do_ls(xsh, argv[optind], 0, prefix);
396
struct xs_permissions perms[MAX_PERMS];
398
/* save path pointer: */
399
char *path = argv[optind++];
400
for (; argv[optind]; optind++, nperms++)
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])
411
perms[nperms].perms = XS_PERM_NONE;
414
perms[nperms].perms = XS_PERM_READ;
417
perms[nperms].perms = XS_PERM_WRITE;
420
perms[nperms].perms = XS_PERM_READ | XS_PERM_WRITE;
423
errx(1, "Invalid permission specification: '%c'",
428
do_chmod(path, perms, nperms, upto, recurse, xsh, xth);
437
static enum mode lookup_mode(const char *m)
439
if (strcmp(m, "read") == 0)
441
else if (strcmp(m, "chmod") == 0)
443
else if (strcmp(m, "exists") == 0)
445
else if (strcmp(m, "list") == 0)
447
else if (strcmp(m, "ls") == 0)
449
else if (strcmp(m, "rm") == 0)
451
else if (strcmp(m, "write") == 0)
453
else if (strcmp(m, "read") == 0)
456
errx(1, "unknown mode %s\n", m);
461
main(int argc, char **argv)
463
struct xs_handle *xsh;
464
xs_transaction_t xth = XBT_NULL;
465
int ret = 0, socket = 0;
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)
481
command = command + strlen("xenstore-");
484
usage(MODE_unknown, 0, argv[0]);
491
mode = lookup_mode(command);
495
static struct option long_options[] = {
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 */
506
c = getopt_long(argc - switch_argv, argv + switch_argv, "hfsptur",
507
long_options, &index);
513
usage(mode, switch_argv, argv[0]);
516
if ( mode == MODE_ls ) {
517
max_width = INT_MAX/2;
521
usage(mode, switch_argv, argv[0]);
528
if ( mode == MODE_read || mode == MODE_list || mode == MODE_ls )
531
usage(mode, switch_argv, argv[0]);
534
if ( mode == MODE_rm )
537
usage(mode, switch_argv, argv[0]);
540
if ( mode == MODE_chmod )
543
usage(mode, switch_argv, argv[0]);
546
if ( mode == MODE_chmod )
549
usage(mode, switch_argv, argv[0]);
558
if ((argc - switch_argv - optind) % 2 == 1) {
559
usage(mode, switch_argv, argv[0]);
564
if (optind == argc - switch_argv) {
565
usage(mode, switch_argv, argv[0]);
572
transaction = (argc - switch_argv - optind) > 1;
575
transaction = (argc - switch_argv - optind) > 2;
585
if ( mode == MODE_ls )
587
memset(&ws, 0, sizeof(ws));
588
ret = ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
590
max_width = ws.ws_col - 2;
593
xsh = socket ? xs_daemon_open() : xs_domain_open();
595
err(1, socket ? "xs_daemon_open" : "xs_domain_open");
599
xth = xs_transaction_start(xsh);
601
errx(1, "couldn't start transaction");
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) {
611
errx(1, "couldn't end transaction");
615
printf("%s", output_buf);