ia64/xen-unstable

changeset 17408:7259de99f7fd

xenstore: make the xenstore clients a single multicall binary
rather than multiply compiled source.

This saves a bunch of space when statically compiling.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Apr 09 13:30:37 2008 +0100 (2008-04-09)
parents 32e3c81ada56
children b982ab47285e
files .hgignore tools/xenstore/Makefile tools/xenstore/xenstore_client.c
line diff
     1.1 --- a/.hgignore	Wed Apr 09 13:27:33 2008 +0100
     1.2 +++ b/.hgignore	Wed Apr 09 13:30:37 2008 +0100
     1.3 @@ -209,6 +209,7 @@
     1.4  ^tools/xenstat/xentop/xentop$
     1.5  ^tools/xenstore/testsuite/tmp/.*$
     1.6  ^tools/xenstore/xen$
     1.7 +^tools/xenstore/xenstore$
     1.8  ^tools/xenstore/xenstore-chmod$
     1.9  ^tools/xenstore/xenstore-exists$
    1.10  ^tools/xenstore/xenstore-list$
     2.1 --- a/tools/xenstore/Makefile	Wed Apr 09 13:27:33 2008 +0100
     2.2 +++ b/tools/xenstore/Makefile	Wed Apr 09 13:30:37 2008 +0100
     2.3 @@ -14,7 +14,6 @@ DEP    = .*.d
     2.4  
     2.5  CLIENTS := xenstore-exists xenstore-list xenstore-read xenstore-rm xenstore-chmod
     2.6  CLIENTS += xenstore-write
     2.7 -CLIENTS_OBJS := $(patsubst xenstore-%,xenstore_%.o,$(CLIENTS))
     2.8  
     2.9  XENSTORED_OBJS = xenstored_core.o xenstored_watch.o xenstored_domain.o xenstored_transaction.o xs_lib.o talloc.o utils.o tdb.o hashtable.o
    2.10  
    2.11 @@ -28,14 +27,14 @@ ifneq ($(XENSTORE_STATIC_CLIENTS),y)
    2.12  LIBXENSTORE := libxenstore.so
    2.13  else
    2.14  LIBXENSTORE := libxenstore.a
    2.15 -$(CLIENTS) xenstore-control xenstore-ls: CFLAGS += -static
    2.16 +xenstore xenstore-control xenstore-ls: CFLAGS += -static
    2.17  endif
    2.18  
    2.19  .PHONY: all
    2.20  all: libxenstore.so libxenstore.a xenstored clients xs_tdb_dump 
    2.21  
    2.22  .PHONY: clients
    2.23 -clients: $(CLIENTS) xenstore-control xenstore-ls
    2.24 +clients: xenstore $(CLIENTS) xenstore-control xenstore-ls
    2.25  
    2.26  ifeq ($(CONFIG_SunOS),y)
    2.27  xenstored_probes.h: xenstored_probes.d
    2.28 @@ -52,12 +51,12 @@ endif
    2.29  xenstored: $(XENSTORED_OBJS)
    2.30  	$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDFLAGS_libxenctrl) $(SOCKET_LIBS) -o $@
    2.31  
    2.32 -$(CLIENTS): xenstore-%: xenstore_%.o $(LIBXENSTORE)
    2.33 +$(CLIENTS): xenstore
    2.34 +	ln -f xenstore $@
    2.35 +
    2.36 +xenstore: xenstore_client.o $(LIBXENSTORE)
    2.37  	$(CC) $(CFLAGS) $(LDFLAGS) $< -L. -lxenstore $(SOCKET_LIBS) -o $@
    2.38  
    2.39 -$(CLIENTS_OBJS): xenstore_%.o: xenstore_client.c
    2.40 -	$(COMPILE.c) -DCLIENT_$(*F) -o $@ $<
    2.41 -
    2.42  xenstore-control: xenstore_control.o $(LIBXENSTORE)
    2.43  	$(CC) $(CFLAGS) $(LDFLAGS) $< -L. -lxenstore $(SOCKET_LIBS) -o $@
    2.44  
    2.45 @@ -85,7 +84,7 @@ clean:
    2.46  	rm -f *.a *.o *.opic *.so* xenstored_probes.h
    2.47  	rm -f xenstored xs_random xs_stress xs_crashme
    2.48  	rm -f xs_tdb_dump xenstore-control xenstore-ls
    2.49 -	rm -f $(CLIENTS)
    2.50 +	rm -f xenstore $(CLIENTS)
    2.51  	$(RM) $(DEP)
    2.52  
    2.53  .PHONY: TAGS
    2.54 @@ -104,8 +103,11 @@ install: all
    2.55  	$(INSTALL_DIR) $(DESTDIR)$(SBINDIR)
    2.56  	$(INSTALL_DIR) $(DESTDIR)$(INCLUDEDIR)
    2.57  	$(INSTALL_PROG) xenstored $(DESTDIR)$(SBINDIR)
    2.58 -	$(INSTALL_PROG) $(CLIENTS) $(DESTDIR)$(BINDIR)
    2.59  	$(INSTALL_PROG) xenstore-control $(DESTDIR)$(BINDIR)
    2.60 +	$(INSTALL_PROG) xenstore $(DESTDIR)/usr/bin
    2.61 +	set -e ; for c in $(CLIENTS) ; do \
    2.62 +		ln -f $(DESTDIR)/usr/bin/xenstore $(DESTDIR)/usr/bin/$${c} ; \
    2.63 +	done
    2.64  	$(INSTALL_PROG) xenstore-ls $(DESTDIR)$(BINDIR)
    2.65  	$(INSTALL_DIR) $(DESTDIR)$(LIBDIR)
    2.66  	$(INSTALL_PROG) libxenstore.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR)
     3.1 --- a/tools/xenstore/xenstore_client.c	Wed Apr 09 13:27:33 2008 +0100
     3.2 +++ b/tools/xenstore/xenstore_client.c	Wed Apr 09 13:30:37 2008 +0100
     3.3 @@ -18,10 +18,24 @@
     3.4  #include <string.h>
     3.5  #include <xs.h>
     3.6  
     3.7 +#define PATH_SEP '/'
     3.8 +#define MAX_PATH_LEN 256
     3.9 +
    3.10 +#define MAX_PERMS 16
    3.11 +
    3.12 +enum mode {
    3.13 +    MODE_unknown,
    3.14 +    MODE_chmod,
    3.15 +    MODE_exists,
    3.16 +    MODE_list,
    3.17 +    MODE_read,
    3.18 +    MODE_rm,
    3.19 +    MODE_write,
    3.20 +};
    3.21 +
    3.22  static char *output_buf = NULL;
    3.23  static int output_pos = 0;
    3.24  
    3.25 -#if defined(CLIENT_read) || defined(CLIENT_list)
    3.26  static int output_size = 0;
    3.27  
    3.28  static void
    3.29 @@ -47,26 +61,36 @@ output(const char *fmt, ...) {
    3.30      va_end(ap);
    3.31      output_pos += len;
    3.32  }
    3.33 -#endif
    3.34  
    3.35  static void
    3.36 -usage(const char *progname)
    3.37 +usage(enum mode mode, int incl_mode, const char *progname)
    3.38  {
    3.39 -#if defined(CLIENT_read)
    3.40 -    errx(1, "Usage: %s [-h] [-p] [-s] key [...]", progname);
    3.41 -#elif defined(CLIENT_write)
    3.42 -    errx(1, "Usage: %s [-h] [-s] key value [...]", progname);
    3.43 -#elif defined(CLIENT_rm)
    3.44 -    errx(1, "Usage: %s [-h] [-s] [-t] key [...]", progname);
    3.45 -#elif defined(CLIENT_exists) || defined(CLIENT_list)
    3.46 -    errx(1, "Usage: %s [-h] [-s] key [...]", progname);
    3.47 -#elif defined(CLIENT_chmod)
    3.48 -    errx(1, "Usage: %s [-h] [-s] key <mode [modes...]>", progname);
    3.49 -#endif
    3.50 +    const char *mstr = NULL;
    3.51 +
    3.52 +    switch (mode) {
    3.53 +    case MODE_unknown:
    3.54 +	errx(1, "Usage: %s <mode> [-h] [...]", progname);
    3.55 +    case MODE_read:
    3.56 +	mstr = incl_mode ? "read " : "";
    3.57 +	errx(1, "Usage: %s %s[-h] [-p] [-s] key [...]", progname, mstr);
    3.58 +    case MODE_write:
    3.59 +	mstr = incl_mode ? "write " : "";
    3.60 +	errx(1, "Usage: %s %s[-h] [-s] key value [...]", progname, mstr);
    3.61 +    case MODE_rm:
    3.62 +	mstr = incl_mode ? "rm " : "";
    3.63 +	errx(1, "Usage: %s %s[-h] [-s] [-t] key [...]", progname, mstr);
    3.64 +    case MODE_exists:
    3.65 +	mstr = incl_mode ? "exists " : "";
    3.66 +    case MODE_list:
    3.67 +	mstr = mstr ? : incl_mode ? "list " : "";
    3.68 +	errx(1, "Usage: %s %s[-h] [-s] key [...]", progname, mstr);
    3.69 +    case MODE_chmod:
    3.70 +	mstr = incl_mode ? "chmod " : "";
    3.71 +	errx(1, "Usage: %s %s[-h] [-s] key <mode [modes...]>", progname, mstr);
    3.72 +    }
    3.73  }
    3.74  
    3.75  
    3.76 -#if defined(CLIENT_rm)
    3.77  static int
    3.78  do_rm(char *path, struct xs_handle *xsh, xs_transaction_t xth)
    3.79  {
    3.80 @@ -78,11 +102,6 @@ do_rm(char *path, struct xs_handle *xsh,
    3.81          return 1;
    3.82      }
    3.83  }
    3.84 -#endif
    3.85 -
    3.86 -#if defined(CLIENT_chmod)
    3.87 -#define PATH_SEP '/'
    3.88 -#define MAX_PATH_LEN 256
    3.89  
    3.90  static void
    3.91  do_chmod(char *path, struct xs_permissions *perms, int nperms, int upto,
    3.92 @@ -130,145 +149,177 @@ do_chmod(char *path, struct xs_permissio
    3.93  	}
    3.94      }
    3.95  }
    3.96 -#endif
    3.97  
    3.98  static int
    3.99 -perform(int optind, int argc, char **argv, struct xs_handle *xsh,
   3.100 +perform(enum mode mode, int optind, int argc, char **argv, struct xs_handle *xsh,
   3.101          xs_transaction_t xth, int prefix, int tidy, int upto, int recurse)
   3.102  {
   3.103      while (optind < argc) {
   3.104 -#if defined(CLIENT_read)
   3.105 -	static struct expanding_buffer ebuf;
   3.106 -	unsigned len;
   3.107 -	char *val = xs_read(xsh, xth, argv[optind], &len);
   3.108 -	if (val == NULL) {
   3.109 -	    warnx("couldn't read path %s", argv[optind]);
   3.110 -	    return 1;
   3.111 -	}
   3.112 -	if (prefix)
   3.113 -	    output("%s: ", argv[optind]);
   3.114 -	output("%s\n", sanitise_value(&ebuf, val, len));
   3.115 -	free(val);
   3.116 -	optind++;
   3.117 -#elif defined(CLIENT_write)
   3.118 -	static struct expanding_buffer ebuf;
   3.119 -	char *val_spec = argv[optind + 1];
   3.120 -	unsigned len;
   3.121 -	expanding_buffer_ensure(&ebuf, strlen(val_spec)+1);
   3.122 -	unsanitise_value(ebuf.buf, &len, val_spec);
   3.123 -	if (!xs_write(xsh, xth, argv[optind], ebuf.buf, len)) {
   3.124 -	    warnx("could not write path %s", argv[optind]);
   3.125 -	    return 1;
   3.126 -	}
   3.127 -	optind += 2;
   3.128 -#elif defined(CLIENT_rm)
   3.129 -        /* Remove the specified path.  If the tidy flag is set, then also
   3.130 -           remove any containing directories that are both empty and have no
   3.131 -           value attached, and repeat, recursing all the way up to the root if
   3.132 -           necessary.
   3.133 -        */
   3.134 -
   3.135 -        char *slash, *path = argv[optind];
   3.136 -
   3.137 -        if (tidy) {
   3.138 -            /* Copy path, because we can't modify argv because we will need it
   3.139 -               again if xs_transaction_end gives us EAGAIN. */
   3.140 -            char *p = malloc(strlen(path) + 1);
   3.141 -            strcpy(p, path);
   3.142 -            path = p;
   3.143 -
   3.144 -        again:
   3.145 -            if (do_rm(path, xsh, xth)) {
   3.146 +        switch (mode) {
   3.147 +        case MODE_unknown:
   3.148 +            /* CANNOT BE REACHED */
   3.149 +            errx(1, "invalid mode %d", mode);
   3.150 +        case MODE_read: {
   3.151 +            static struct expanding_buffer ebuf;
   3.152 +            unsigned len;
   3.153 +            char *val = xs_read(xsh, xth, argv[optind], &len);
   3.154 +            if (val == NULL) {
   3.155 +                warnx("couldn't read path %s", argv[optind]);
   3.156                  return 1;
   3.157              }
   3.158 +            if (prefix)
   3.159 +                output("%s: ", argv[optind]);
   3.160 +            output("%s\n", sanitise_value(&ebuf, val, len));
   3.161 +            free(val);
   3.162 +            optind++;
   3.163 +            break;
   3.164 +        }
   3.165 +        case MODE_write: {
   3.166 +            static struct expanding_buffer ebuf;
   3.167 +            char *val_spec = argv[optind + 1];
   3.168 +            unsigned len;
   3.169 +            expanding_buffer_ensure(&ebuf, strlen(val_spec)+1);
   3.170 +            unsanitise_value(ebuf.buf, &len, val_spec);
   3.171 +            if (!xs_write(xsh, xth, argv[optind], ebuf.buf, len)) {
   3.172 +                warnx("could not write path %s", argv[optind]);
   3.173 +                return 1;
   3.174 +            }
   3.175 +            optind += 2;
   3.176 +        } break;
   3.177 +        case MODE_rm: {
   3.178 +            /* Remove the specified path.  If the tidy flag is set, then also
   3.179 +               remove any containing directories that are both empty and have no
   3.180 +               value attached, and repeat, recursing all the way up to the root if
   3.181 +               necessary.
   3.182 +            */
   3.183  
   3.184 -            slash = strrchr(p, '/');
   3.185 -            if (slash) {
   3.186 -                char *val;
   3.187 -                unsigned len;
   3.188 -                *slash = '\0';
   3.189 -                val = xs_read(xsh, xth, p, &len);
   3.190 -                if (val && len == 0) {
   3.191 -                    unsigned int num;
   3.192 -                    char ** list = xs_directory(xsh, xth, p, &num);
   3.193 +            char *slash, *path = argv[optind];
   3.194  
   3.195 -                    if (list && num == 0) {
   3.196 -                        goto again;
   3.197 +            if (tidy) {
   3.198 +                /* Copy path, because we can't modify argv because we will need it
   3.199 +                   again if xs_transaction_end gives us EAGAIN. */
   3.200 +                char *p = malloc(strlen(path) + 1);
   3.201 +                strcpy(p, path);
   3.202 +                path = p;
   3.203 +
   3.204 +            again:
   3.205 +                if (do_rm(path, xsh, xth)) {
   3.206 +                    return 1;
   3.207 +                }
   3.208 +
   3.209 +                slash = strrchr(p, '/');
   3.210 +                if (slash) {
   3.211 +                    char *val;
   3.212 +                    unsigned len;
   3.213 +                    *slash = '\0';
   3.214 +                    val = xs_read(xsh, xth, p, &len);
   3.215 +                    if (val && len == 0) {
   3.216 +                        unsigned int num;
   3.217 +                        char ** list = xs_directory(xsh, xth, p, &num);
   3.218 +
   3.219 +                        if (list && num == 0) {
   3.220 +                            goto again;
   3.221 +                        }
   3.222                      }
   3.223                  }
   3.224 +
   3.225 +                free(path);
   3.226 +            }
   3.227 +            else {
   3.228 +                if (do_rm(path, xsh, xth)) {
   3.229 +                    return 1;
   3.230 +                }
   3.231              }
   3.232  
   3.233 -            free(path);
   3.234 +            optind++;
   3.235 +            break;
   3.236          }
   3.237 -        else {
   3.238 -            if (do_rm(path, xsh, xth)) {
   3.239 +        case MODE_exists: {
   3.240 +            char *val = xs_read(xsh, xth, argv[optind], NULL);
   3.241 +            if (val == NULL) {
   3.242                  return 1;
   3.243              }
   3.244 +            free(val);
   3.245 +            optind++;
   3.246 +            break;
   3.247 +        }
   3.248 +        case MODE_list: {
   3.249 +            unsigned int i, num;
   3.250 +            char **list = xs_directory(xsh, xth, argv[optind], &num);
   3.251 +            if (list == NULL) {
   3.252 +                warnx("could not list path %s", argv[optind]);
   3.253 +                return 1;
   3.254 +            }
   3.255 +            for (i = 0; i < num; i++) {
   3.256 +                if (prefix)
   3.257 +                    output("%s/", argv[optind]);
   3.258 +                output("%s\n", list[i]);
   3.259 +            }
   3.260 +            free(list);
   3.261 +            optind++;
   3.262 +            break;
   3.263 +        }
   3.264 +        case MODE_chmod: {
   3.265 +            struct xs_permissions perms[MAX_PERMS];
   3.266 +            int nperms = 0;
   3.267 +            /* save path pointer: */
   3.268 +            char *path = argv[optind++];
   3.269 +            for (; argv[optind]; optind++, nperms++)
   3.270 +            {
   3.271 +                if (MAX_PERMS <= nperms)
   3.272 +                    errx(1, "Too many permissions specified.  "
   3.273 +			 "Maximum per invocation is %d.", MAX_PERMS);
   3.274 +
   3.275 +                perms[nperms].id = atoi(argv[optind]+1);
   3.276 +
   3.277 +                switch (argv[optind][0])
   3.278 +                {
   3.279 +                case 'n':
   3.280 +                    perms[nperms].perms = XS_PERM_NONE;
   3.281 +                    break;
   3.282 +                case 'r':
   3.283 +                    perms[nperms].perms = XS_PERM_READ;
   3.284 +                    break;
   3.285 +                case 'w':
   3.286 +                    perms[nperms].perms = XS_PERM_WRITE;
   3.287 +                    break;
   3.288 +                case 'b':
   3.289 +                    perms[nperms].perms = XS_PERM_READ | XS_PERM_WRITE;
   3.290 +                    break;
   3.291 +                default:
   3.292 +                    errx(1, "Invalid permission specification: '%c'",
   3.293 +			 argv[optind][0]);
   3.294 +                }
   3.295 +            }
   3.296 +
   3.297 +            do_chmod(path, perms, nperms, upto, recurse, xsh, xth);
   3.298 +            break;
   3.299 +        }
   3.300          }
   3.301  
   3.302 -	optind++;
   3.303 -#elif defined(CLIENT_exists)
   3.304 -	char *val = xs_read(xsh, xth, argv[optind], NULL);
   3.305 -	if (val == NULL) {
   3.306 -	    return 1;
   3.307 -	}
   3.308 -	free(val);
   3.309 -	optind++;
   3.310 -#elif defined(CLIENT_list)
   3.311 -	unsigned int i, num;
   3.312 -	char **list = xs_directory(xsh, xth, argv[optind], &num);
   3.313 -	if (list == NULL) {
   3.314 -	    warnx("could not list path %s", argv[optind]);
   3.315 -	    return 1;
   3.316 -	}
   3.317 -	for (i = 0; i < num; i++) {
   3.318 -	    if (prefix)
   3.319 -		output("%s/", argv[optind]);
   3.320 -	    output("%s\n", list[i]);
   3.321 -	}
   3.322 -	free(list);
   3.323 -	optind++;
   3.324 -#elif defined(CLIENT_chmod)
   3.325 -#define MAX_PERMS 16
   3.326 -	struct xs_permissions perms[MAX_PERMS];
   3.327 -	int nperms = 0;
   3.328 -	/* save path pointer: */
   3.329 -	char *path = argv[optind++];
   3.330 -	for (; argv[optind]; optind++, nperms++)
   3.331 -	{
   3.332 -	    if (MAX_PERMS <= nperms)
   3.333 -		errx(1, "Too many permissions specified.  "
   3.334 -		     "Maximum per invocation is %d.", MAX_PERMS);
   3.335 -
   3.336 -	    perms[nperms].id = atoi(argv[optind]+1);
   3.337 -
   3.338 -	    switch (argv[optind][0])
   3.339 -	    {
   3.340 -	    case 'n':
   3.341 -		perms[nperms].perms = XS_PERM_NONE;
   3.342 -		break;
   3.343 -	    case 'r':
   3.344 -		perms[nperms].perms = XS_PERM_READ;
   3.345 -		break;
   3.346 -	    case 'w':
   3.347 -		perms[nperms].perms = XS_PERM_WRITE;
   3.348 -		break;
   3.349 -	    case 'b':
   3.350 -		perms[nperms].perms = XS_PERM_READ | XS_PERM_WRITE;
   3.351 -		break;
   3.352 -	    default:
   3.353 -		errx(1, "Invalid permission specification: '%c'",
   3.354 -		     argv[optind][0]);
   3.355 -	    }
   3.356 -	}
   3.357 -
   3.358 -	do_chmod(path, perms, nperms, upto, recurse, xsh, xth);
   3.359 -#endif
   3.360 +        return 0;
   3.361      }
   3.362 -
   3.363 -    return 0;
   3.364  }
   3.365  
   3.366 +static enum mode lookup_mode(const char *m)
   3.367 +{
   3.368 +    if (strcmp(m, "read") == 0)
   3.369 +	return MODE_read;
   3.370 +    else if (strcmp(m, "chmod") == 0)
   3.371 +	return MODE_chmod;
   3.372 +    else if (strcmp(m, "exists") == 0)
   3.373 +	return MODE_exists;
   3.374 +    else if (strcmp(m, "list") == 0)
   3.375 +	return MODE_list;
   3.376 +    else if (strcmp(m, "rm") == 0)
   3.377 +	return MODE_rm;
   3.378 +    else if (strcmp(m, "write") == 0)
   3.379 +	return MODE_write;
   3.380 +    else if (strcmp(m, "read") == 0)
   3.381 +	return MODE_read;
   3.382 +    else
   3.383 +	errx(1, "unknown mode %s\n", m);
   3.384 +}
   3.385  
   3.386  int
   3.387  main(int argc, char **argv)
   3.388 @@ -281,92 +332,111 @@ main(int argc, char **argv)
   3.389      int upto = 0;
   3.390      int recurse = 0;
   3.391      int transaction;
   3.392 +    enum mode mode;
   3.393 +
   3.394 +    const char *_command = strrchr(argv[0], '/');
   3.395 +    const char *command = _command ? &_command[1] : argv[0];
   3.396 +    int switch_argv = -1; /* which element of argv did we switch on */
   3.397 +
   3.398 +    if (strncmp(command, "xenstore-", strlen("xenstore-")) == 0)
   3.399 +    {
   3.400 +	switch_argv = 0;
   3.401 +	command = command + strlen("xenstore-");
   3.402 +    }
   3.403 +    else if (argc < 2)
   3.404 +	usage(MODE_unknown, 0, argv[0]);
   3.405 +    else
   3.406 +    {
   3.407 +	command = argv[1];
   3.408 +	switch_argv = 1;
   3.409 +    }
   3.410 +
   3.411 +    mode = lookup_mode(command);
   3.412  
   3.413      while (1) {
   3.414  	int c, index = 0;
   3.415  	static struct option long_options[] = {
   3.416 -	    {"help", 0, 0, 'h'},
   3.417 -            {"socket", 0, 0, 's'},
   3.418 -#if defined(CLIENT_read) || defined(CLIENT_list)
   3.419 -	    {"prefix", 0, 0, 'p'},
   3.420 -#elif defined(CLIENT_rm)
   3.421 -            {"tidy",   0, 0, 't'},
   3.422 -#elif defined(CLIENT_chmod)
   3.423 -	    {"upto",    0, 0, 'u'},
   3.424 -	    {"recurse", 0, 0, 'r'},
   3.425 -#endif
   3.426 +	    {"help",    0, 0, 'h'},
   3.427 +	    {"socket",  0, 0, 's'},
   3.428 +	    {"prefix",  0, 0, 'p'}, /* MODE_read || MODE_list */
   3.429 +	    {"tidy",    0, 0, 't'}, /* MODE_rm */
   3.430 +	    {"upto",    0, 0, 'u'}, /* MODE_chmod */
   3.431 +	    {"recurse", 0, 0, 'r'}, /* MODE_chmod */
   3.432  	    {0, 0, 0, 0}
   3.433  	};
   3.434  
   3.435 -	c = getopt_long(argc, argv, "hs"
   3.436 -#if defined(CLIENT_read) || defined(CLIENT_list)
   3.437 -			"p"
   3.438 -#elif defined(CLIENT_rm)
   3.439 -                        "t"
   3.440 -#elif defined(CLIENT_chmod)
   3.441 -			"ur"
   3.442 -#endif
   3.443 -			, long_options, &index);
   3.444 +	c = getopt_long(argc - switch_argv, argv + switch_argv, "hsptur",
   3.445 +			long_options, &index);
   3.446  	if (c == -1)
   3.447  	    break;
   3.448  
   3.449  	switch (c) {
   3.450  	case 'h':
   3.451 -	    usage(argv[0]);
   3.452 +	    usage(mode, switch_argv, argv[0]);
   3.453  	    /* NOTREACHED */
   3.454          case 's':
   3.455              socket = 1;
   3.456              break;
   3.457 -#if defined(CLIENT_read) || defined(CLIENT_list)
   3.458  	case 'p':
   3.459 -	    prefix = 1;
   3.460 +	    if ( mode == MODE_read || mode == MODE_list )
   3.461 +		prefix = 1;
   3.462 +	    else
   3.463 +		usage(mode, switch_argv, argv[0]);
   3.464  	    break;
   3.465 -#elif defined(CLIENT_rm)
   3.466  	case 't':
   3.467 -	    tidy = 1;
   3.468 +	    if ( mode == MODE_rm )
   3.469 +		tidy = 1;
   3.470 +	    else
   3.471 +		usage(mode, switch_argv, argv[0]);
   3.472  	    break;
   3.473 -#elif defined(CLIENT_chmod)
   3.474  	case 'u':
   3.475 -	    upto = 1;
   3.476 +	    if ( mode == MODE_chmod )
   3.477 +		upto = 1;
   3.478 +	    else
   3.479 +		usage(mode, switch_argv, argv[0]);
   3.480  	    break;
   3.481  	case 'r':
   3.482 -	    recurse = 1;
   3.483 +	    if ( mode == MODE_chmod )
   3.484 +		recurse = 1;
   3.485 +	    else
   3.486 +		usage(mode, switch_argv, argv[0]);
   3.487  	    break;
   3.488 -#endif
   3.489  	}
   3.490      }
   3.491  
   3.492      if (optind == argc) {
   3.493 -	usage(argv[0]);
   3.494 -	/* NOTREACHED */
   3.495 -    }
   3.496 -#if defined(CLIENT_write)
   3.497 -    if ((argc - optind) % 2 == 1) {
   3.498 -	usage(argv[0]);
   3.499 +	usage(mode, switch_argv, argv[0]);
   3.500  	/* NOTREACHED */
   3.501      }
   3.502 -#endif
   3.503 +    if (mode == MODE_write && (argc - switch_argv - optind) % 2 == 1) {
   3.504 +	usage(mode, switch_argv, argv[0]);
   3.505 +	/* NOTREACHED */
   3.506 +    }
   3.507  
   3.508 -#if defined(CLIENT_read)
   3.509 -    transaction = (argc - optind) > 1;
   3.510 -#elif defined(CLIENT_write)
   3.511 -    transaction = (argc - optind) > 2;
   3.512 -#else
   3.513 -    transaction = 1;
   3.514 -#endif
   3.515 +    switch (mode) {
   3.516 +    case MODE_read:
   3.517 +	transaction = (argc - switch_argv - optind) > 1;
   3.518 +	break;
   3.519 +    case MODE_write:
   3.520 +	transaction = (argc - switch_argv - optind) > 2;
   3.521 +	break;
   3.522 +    default:
   3.523 +	transaction = 1;
   3.524 +	break;
   3.525 +    }
   3.526  
   3.527      xsh = socket ? xs_daemon_open() : xs_domain_open();
   3.528      if (xsh == NULL)
   3.529  	err(1, socket ? "xs_daemon_open" : "xs_domain_open");
   3.530  
   3.531 -  again:
   3.532 +again:
   3.533      if (transaction) {
   3.534  	xth = xs_transaction_start(xsh);
   3.535  	if (xth == XBT_NULL)
   3.536  	    errx(1, "couldn't start transaction");
   3.537      }
   3.538  
   3.539 -    ret = perform(optind, argc, argv, xsh, xth, prefix, tidy, upto, recurse);
   3.540 +    ret = perform(mode, optind, argc - switch_argv, argv + switch_argv, xsh, xth, prefix, tidy, upto, recurse);
   3.541  
   3.542      if (transaction && !xs_transaction_end(xsh, xth, ret)) {
   3.543  	if (ret == 0 && errno == EAGAIN) {