]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
command: Introduce struct command_context.
authorAndre Noll <maan@systemlinux.org>
Sat, 24 Dec 2011 00:22:58 +0000 (01:22 +0100)
committerAndre Noll <maan@systemlinux.org>
Fri, 20 Jan 2012 21:57:07 +0000 (22:57 +0100)
This exposes a couple of variables which were previously local to
handle_connect() to the command handlers, allowing them to make use
of the full command context.

All newly exposed variables are stored in an instance of the new
structure, and the command handlers now take a pointer to such
a structure.

The patch is large but also straight forward.

afs.c
afs.cmd
aft.c
attribute.c
blob.c
command.c
command.h

diff --git a/afs.c b/afs.c
index 73f2c65a3d87cdd4a2ab3861985d25047140e44a..5939cbe69cc46c1095d7cb82ffc98a741d3f6505 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -26,6 +26,7 @@
 #include "signal.h"
 #include "fd.h"
 #include "mood.h"
+#include "command.h"
 
 /** The osl tables used by afs. \sa blob.c. */
 enum afs_table_num {
@@ -592,27 +593,27 @@ out:
  */
 int sc_send_result(struct osl_object *result, void *private)
 {
-       struct stream_cipher_context *scc = private;
+       struct command_context *cc = private;
        int ret;
 
        if (!result->size)
                return 1;
-       ret = sc_send_bin_buffer(scc, result->data, result->size);
+       ret = sc_send_bin_buffer(&cc->scc, result->data, result->size);
        if (ret < 0 || ret == result->size)
                return ret;
        return -E_SHORT_WRITE;
 }
 
-int com_select(struct stream_cipher_context *scc, int argc, char * const * const argv)
+int com_select(struct command_context *cc)
 {
        struct osl_object query;
 
-       if (argc != 2)
+       if (cc->argc != 2)
                return -E_AFS_SYNTAX;
-       query.data = argv[1];
-       query.size = strlen(argv[1]) + 1;
+       query.data = cc->argv[1];
+       query.size = strlen(cc->argv[1]) + 1;
        return send_callback_request(com_select_callback, &query,
-               &sc_send_result, scc);
+               &sc_send_result, cc);
 }
 
 static void init_admissible_files(char *arg)
@@ -1026,7 +1027,7 @@ out:
        free(pb.buf);
 }
 
-int com_init(struct stream_cipher_context *scc, int argc, char * const * const argv)
+int com_init(struct command_context *cc)
 {
        int i, j, ret;
        uint32_t table_mask = (1 << (NUM_AFS_TABLES + 1)) - 1;
@@ -1036,13 +1037,13 @@ int com_init(struct stream_cipher_context *scc, int argc, char * const * const a
        ret = make_database_dir();
        if (ret < 0)
                return ret;
-       if (argc != 1) {
+       if (cc->argc != 1) {
                table_mask = 0;
-               for (i = 1; i < argc; i++) {
+               for (i = 1; i < cc->argc; i++) {
                        for (j = 0; j < NUM_AFS_TABLES; j++) {
                                struct afs_table *t = &afs_tables[j];
 
-                               if (strcmp(argv[i], t->name))
+                               if (strcmp(cc->argv[i], t->name))
                                        continue;
                                table_mask |= (1 << j);
                                break;
@@ -1052,10 +1053,10 @@ int com_init(struct stream_cipher_context *scc, int argc, char * const * const a
                }
        }
        ret = send_callback_request(create_tables_callback, &query,
-               sc_send_result, scc);
+               sc_send_result, cc);
        if (ret < 0)
                /* ignore return value */
-               sc_send_va_buffer(scc, "%s\n", para_strerror(-ret));
+               sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret));
        return ret;
 }
 
@@ -1073,13 +1074,13 @@ enum com_check_flags {
        CHECK_PLAYLISTS = 4
 };
 
-int com_check(struct stream_cipher_context *scc, int argc, char * const * const argv)
+int com_check(struct command_context *cc)
 {
        unsigned flags = 0;
        int i, ret;
 
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
+       for (i = 1; i < cc->argc; i++) {
+               const char *arg = cc->argv[i];
                if (arg[0] != '-')
                        break;
                if (!strcmp(arg, "--")) {
@@ -1100,25 +1101,25 @@ int com_check(struct stream_cipher_context *scc, int argc, char * const * const
                }
                return -E_AFS_SYNTAX;
        }
-       if (i < argc)
+       if (i < cc->argc)
                return -E_AFS_SYNTAX;
        if (!flags)
                flags = ~0U;
        if (flags & CHECK_AFT) {
                ret = send_callback_request(aft_check_callback, NULL,
-                       sc_send_result, scc);
+                       sc_send_result, cc);
                if (ret < 0)
                        return ret;
        }
        if (flags & CHECK_PLAYLISTS) {
                ret = send_callback_request(playlist_check_callback,
-                       NULL, sc_send_result, scc);
+                       NULL, sc_send_result, cc);
                if (ret < 0)
                        return ret;
        }
        if (flags & CHECK_MOODS) {
                ret = send_callback_request(mood_check_callback, NULL,
-                       sc_send_result, scc);
+                       sc_send_result, cc);
                if (ret < 0)
                        return ret;
        }
diff --git a/afs.cmd b/afs.cmd
index 22a0786bc8d17731b242c9dc32c13d6d547e5635..c7808040370c7e8c4088e44d7b63820093e255af 100644 (file)
--- a/afs.cmd
+++ b/afs.cmd
@@ -260,7 +260,7 @@ H: loads the mood named 'foo'.
 ---
 T: add
 N: add@member@
-O: int com_add@member@(struct stream_cipher_context *scc, int argc, char * const * const argv);
+O: int com_add@member@(struct command_context *cc);
 P: AFS_READ | AFS_WRITE
 D: Read data from stdin and add it as a blob to the @member@ table.
 U: add@member@ @member@_name
@@ -273,7 +273,7 @@ H: given name already exists, its contents are replaced by the new data.
 ---
 T: cat
 N: cat@member@
-O: int com_cat@member@(struct stream_cipher_context *scc, int argc, char * const * const argv);
+O: int com_cat@member@(struct command_context *cc);
 P: AFS_READ
 D: Dump the contents of a blob of type @member@ to stdout.
 U: cat@member@ @member@_name
@@ -283,7 +283,7 @@ H: they were previously added.
 ---
 T: ls
 N: ls@member@
-O: int com_ls@member@(struct stream_cipher_context *scc, int argc, char * const * const argv);
+O: int com_ls@member@(struct command_context *cc);
 P: AFS_READ
 D: List blobs of type @member@ matching a pattern.
 U: ls@member@ [-i] [-l] [-r] [pattern]
@@ -303,7 +303,7 @@ H: -r       Reverse sort order.
 ---
 T: rm
 N: rm@member@
-O: int com_rm@member@(struct stream_cipher_context *scc, int argc, char * const * const argv);
+O: int com_rm@member@(struct command_context *cc);
 P: AFS_READ | AFS_WRITE
 D: Remove blob(s) of type @member@ from the @member@ table.
 U: rm@member@ pattern...
@@ -312,7 +312,7 @@ H: any given pattern.
 ---
 T: mv
 N: mv@member@
-O: int com_mv@member@(struct stream_cipher_context *scc, int argc, char * const * const argv);
+O: int com_mv@member@(struct command_context *cc);
 P: AFS_READ | AFS_WRITE
 D: Rename a blob of type @member@.
 U: mv@member@ old_@member@_name new_@member@_name
diff --git a/aft.c b/aft.c
index 9d87c748b4456ad61b260446b56def0e5acbaf12..f89235a484287ce2b5f5aa9081c38fd7a7a5d712 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -21,6 +21,7 @@
 #include "fd.h"
 #include "ipc.h"
 #include "portable_io.h"
+#include "command.h"
 
 static struct osl_table *audio_file_table;
 static char *status_items;
@@ -1402,7 +1403,7 @@ out:
 /*
  * TODO: flags -h (sort by hash)
  */
-int com_ls(struct stream_cipher_context *scc, int argc, char * const * const argv)
+int com_ls(struct command_context *cc)
 {
        int i, ret;
        unsigned flags = 0;
@@ -1411,8 +1412,8 @@ int com_ls(struct stream_cipher_context *scc, int argc, char * const * const arg
        struct ls_options opts = {.patterns = NULL};
        struct osl_object query = {.data = &opts, .size = sizeof(opts)};
 
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
+       for (i = 1; i < cc->argc; i++) {
+               const char *arg = cc->argv[i];
                if (arg[0] != '-')
                        break;
                if (!strcmp(arg, "--")) {
@@ -1512,9 +1513,9 @@ int com_ls(struct stream_cipher_context *scc, int argc, char * const * const arg
        opts.flags = flags;
        opts.sorting = sort;
        opts.mode = mode;
-       opts.num_patterns = argc - i;
+       opts.num_patterns = cc->argc - i;
        ret = send_option_arg_callback_request(&query, opts.num_patterns,
-               argv + i, com_ls_callback, sc_send_result, scc);
+               cc->argv + i, com_ls_callback, sc_send_result, cc);
        return ret;
 }
 
@@ -1801,8 +1802,8 @@ out:
 
 /** Used by com_add(). */
 struct private_add_data {
-       /** The socket file descriptor, including stream cipher keys. */
-       struct stream_cipher_context *scc;
+       /** The pointer passed to the original command handler. */
+       struct command_context *cc;
        /** The given add flags. */
        uint32_t flags;
 };
@@ -1857,7 +1858,7 @@ static int add_one_audio_file(const char *path, void *private_data)
        ret = 1;
        if (pb && (pad->flags & ADD_FLAG_LAZY)) { /* lazy is really cheap */
                if (pad->flags & ADD_FLAG_VERBOSE)
-                       send_ret = sc_send_va_buffer(pad->scc,
+                       send_ret = sc_send_va_buffer(&pad->cc->scc,
                                "lazy-ignore: %s\n", path);
                goto out_free;
        }
@@ -1878,7 +1879,7 @@ static int add_one_audio_file(const char *path, void *private_data)
        ret = 1;
        if (pb && hs && hs == pb && !(pad->flags & ADD_FLAG_FORCE)) {
                if (pad->flags & ADD_FLAG_VERBOSE)
-                       send_ret = sc_send_va_buffer(pad->scc,
+                       send_ret = sc_send_va_buffer(&pad->cc->scc,
                                "%s exists, not forcing update\n", path);
                goto out_unmap;
        }
@@ -1896,13 +1897,13 @@ static int add_one_audio_file(const char *path, void *private_data)
        munmap(map.data, map.size);
        close(fd);
        if (pad->flags & ADD_FLAG_VERBOSE) {
-               send_ret = sc_send_va_buffer(pad->scc, "adding %s\n", path);
+               send_ret = sc_send_va_buffer(&pad->cc->scc, "adding %s\n", path);
                if (send_ret < 0)
                        goto out_free;
        }
        save_add_callback_buffer(hash, path, afhi_ptr, pad->flags, format_num, &obj);
        /* Ask afs to consider this entry for adding. */
-       ret = send_callback_request(com_add_callback, &obj, sc_send_result, pad->scc);
+       ret = send_callback_request(com_add_callback, &obj, sc_send_result, pad->cc);
        goto out_free;
 
 out_unmap:
@@ -1910,7 +1911,7 @@ out_unmap:
        munmap(map.data, map.size);
 out_free:
        if (ret < 0 && send_ret >= 0)
-               send_ret = sc_send_va_buffer(pad->scc,
+               send_ret = sc_send_va_buffer(&pad->cc->scc,
                        "failed to add %s (%s)\n", path, para_strerror(-ret));
        free(obj.data);
        if (afhi_ptr) {
@@ -1926,14 +1927,14 @@ out_free:
        return send_ret;
 }
 
-int com_add(struct stream_cipher_context *scc, int argc, char * const * const argv)
+int com_add(struct command_context *cc)
 {
        int i, ret;
-       struct private_add_data pad = {.scc = scc, .flags = 0};
+       struct private_add_data pad = {.cc = cc, .flags = 0};
        struct stat statbuf;
 
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
+       for (i = 1; i < cc->argc; i++) {
+               const char *arg = cc->argv[i];
                if (arg[0] != '-')
                        break;
                if (!strcmp(arg, "--")) {
@@ -1957,21 +1958,22 @@ int com_add(struct stream_cipher_context *scc, int argc, char * const * const ar
                        continue;
                }
        }
-       if (argc <= i)
+       if (cc->argc <= i)
                return -E_AFT_SYNTAX;
-       for (; i < argc; i++) {
+       for (; i < cc->argc; i++) {
                char *path;
-               ret = verify_path(argv[i], &path);
+               ret = verify_path(cc->argv[i], &path);
                if (ret < 0) {
-                       ret = sc_send_va_buffer(scc, "%s: %s\n", argv[i],
-                               para_strerror(-ret));
+                       ret = sc_send_va_buffer(&cc->scc, "%s: %s\n",
+                               cc->argv[i], para_strerror(-ret));
                        if (ret < 0)
                                return ret;
                        continue;
                }
                ret = stat(path, &statbuf);
                if (ret < 0) {
-                       ret = sc_send_va_buffer(scc, "failed to stat %s (%s)\n", path,
+                       ret = sc_send_va_buffer(&cc->scc,
+                               "failed to stat %s (%s)\n", path,
                                strerror(errno));
                        free(path);
                        if (ret < 0)
@@ -1984,7 +1986,8 @@ int com_add(struct stream_cipher_context *scc, int argc, char * const * const ar
                else
                        ret = add_one_audio_file(path, &pad);
                if (ret < 0) {
-                       sc_send_va_buffer(scc, "%s: %s\n", path, para_strerror(-ret));
+                       sc_send_va_buffer(&cc->scc, "%s: %s\n", path,
+                               para_strerror(-ret));
                        free(path);
                        return ret;
                }
@@ -2112,7 +2115,7 @@ static void com_touch_callback(int fd, const struct osl_object *query)
        free(tad.pb.buf);
 }
 
-int com_touch(struct stream_cipher_context *scc, int argc, char * const * const argv)
+int com_touch(struct command_context *cc)
 {
        struct com_touch_options cto = {
                .num_played = -1,
@@ -2125,8 +2128,8 @@ int com_touch(struct stream_cipher_context *scc, int argc, char * const * const
        int i, ret;
 
 
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
+       for (i = 1; i < cc->argc; i++) {
+               const char *arg = cc->argv[i];
                if (arg[0] != '-')
                        break;
                if (!strcmp(arg, "--")) {
@@ -2177,12 +2180,12 @@ int com_touch(struct stream_cipher_context *scc, int argc, char * const * const
                }
                break; /* non-option starting with dash */
        }
-       if (i >= argc)
+       if (i >= cc->argc)
                return -E_AFT_SYNTAX;
-       ret = send_option_arg_callback_request(&query, argc - i,
-               argv + i, com_touch_callback, sc_send_result, scc);
+       ret = send_option_arg_callback_request(&query, cc->argc - i,
+               cc->argv + i, com_touch_callback, sc_send_result, cc);
        if (ret < 0)
-               sc_send_va_buffer(scc, "%s\n", para_strerror(-ret));
+               sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret));
        return ret;
 }
 
@@ -2260,14 +2263,14 @@ static void com_rm_callback(int fd, const struct osl_object *query)
 }
 
 /* TODO options: -r (recursive) */
-int com_rm(struct stream_cipher_context *scc, int argc,  char * const * const argv)
+int com_rm(struct command_context *cc)
 {
        uint32_t flags = 0;
        struct osl_object query = {.data = &flags, .size = sizeof(flags)};
        int i, ret;
 
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
+       for (i = 1; i < cc->argc; i++) {
+               const char *arg = cc->argv[i];
                if (arg[0] != '-')
                        break;
                if (!strcmp(arg, "--")) {
@@ -2288,12 +2291,12 @@ int com_rm(struct stream_cipher_context *scc, int argc,  char * const * const ar
                }
                break;
        }
-       if (i >= argc)
+       if (i >= cc->argc)
                return -E_AFT_SYNTAX;
-       ret = send_option_arg_callback_request(&query, argc - i, argv + i,
-               com_rm_callback, sc_send_result, scc);
+       ret = send_option_arg_callback_request(&query, cc->argc - i,
+               cc->argv + i, com_rm_callback, sc_send_result, cc);
        if (ret < 0)
-               sc_send_va_buffer(scc, "%s\n", para_strerror(-ret));
+               sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret));
        return ret;
 }
 
@@ -2405,14 +2408,14 @@ out:
        free(cad.pb.buf);
 }
 
-int com_cpsi(struct stream_cipher_context *scc, int argc,  char * const * const argv)
+int com_cpsi(struct command_context *cc)
 {
        unsigned flags = 0;
        int i, ret;
        struct osl_object options = {.data = &flags, .size = sizeof(flags)};
 
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
+       for (i = 1; i < cc->argc; i++) {
+               const char *arg = cc->argv[i];
                if (arg[0] != '-')
                        break;
                if (!strcmp(arg, "--")) {
@@ -2445,14 +2448,14 @@ int com_cpsi(struct stream_cipher_context *scc, int argc,  char * const * const
                }
                break;
        }
-       if (i + 1 >= argc) /* need at least source file and pattern */
+       if (i + 1 >= cc->argc) /* need at least source file and pattern */
                return -E_AFT_SYNTAX;
        if (!(flags & ~CPSI_FLAG_VERBOSE)) /* no copy flags given */
                flags = ~(unsigned)CPSI_FLAG_VERBOSE | flags;
-       ret = send_option_arg_callback_request(&options, argc - i, argv + i,
-               com_cpsi_callback, sc_send_result, scc);
+       ret = send_option_arg_callback_request(&options, cc->argc - i,
+               cc->argv + i, com_cpsi_callback, sc_send_result, cc);
        if (ret < 0)
-               sc_send_va_buffer(scc, "%s\n", para_strerror(-ret));
+               sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret));
        return ret;
 }
 
@@ -2470,7 +2473,7 @@ static void afs_stat_callback(int fd, const struct osl_object *query)
 /**
  * Get the current afs status items from the afs process and send it.
  *
- * \param scc The stream cipher context for data encryption.
+ * \param cc The command context, used e.g. for data encryption.
  * \param parser_friendly Whether parser-friendly output format should be used.
  *
  * As the contents of the afs status items change in time and the command
@@ -2481,12 +2484,12 @@ static void afs_stat_callback(int fd, const struct osl_object *query)
  *
  * \return The return value of the underyling call to \ref send_callback_request().
  */
-int send_afs_status(struct stream_cipher_context *scc, int parser_friendly)
+int send_afs_status(struct command_context *cc, int parser_friendly)
 {
        struct osl_object query = {.data = &parser_friendly,
                .size = sizeof(parser_friendly)};
 
-       return send_callback_request(afs_stat_callback, &query, sc_send_result, scc);
+       return send_callback_request(afs_stat_callback, &query, sc_send_result, cc);
 }
 
 /* TODO: optionally fix problems by removing offending rows */
index b56a9574db48d28879cf31341bc0aaaf5afbe34f..19700944dff7c266db4c78a78e73eb79fda37713 100644 (file)
@@ -16,6 +16,7 @@
 #include "afh.h"
 #include "afs.h"
 #include "ipc.h"
+#include "command.h"
 
 static struct osl_table *attribute_table;
 static int greatest_att_bitnum;
@@ -175,14 +176,14 @@ static void com_lsatt_callback(int fd, const struct osl_object *query)
        free(laad.pb.buf);
 }
 
-int com_lsatt(struct stream_cipher_context *scc, int argc, char * const * const argv)
+int com_lsatt(struct command_context *cc)
 {
        unsigned flags = 0;
        struct osl_object options = {.data = &flags, .size = sizeof(flags)};
        int ret, i;
 
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
+       for (i = 1; i < cc->argc; i++) {
+               const char *arg = cc->argv[i];
                if (arg[0] != '-')
                        break;
                if (!strcmp(arg, "--")) {
@@ -202,13 +203,13 @@ int com_lsatt(struct stream_cipher_context *scc, int argc, char * const * const
                        continue;
                }
        }
-       ret = send_option_arg_callback_request(&options, argc - i, argv + i,
-               com_lsatt_callback, sc_send_result, scc);
+       ret = send_option_arg_callback_request(&options, cc->argc - i, cc->argv + i,
+               com_lsatt_callback, sc_send_result, cc);
        if (!ret) {
-               if (argc > 1)
-                       ret = sc_send_va_buffer(scc, "no matches\n");
+               if (cc->argc > 1)
+                       ret = sc_send_va_buffer(&cc->scc, "no matches\n");
        } else if (ret < 0)
-               sc_send_va_buffer(scc, "%s\n", para_strerror(-ret));
+               sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret));
        return ret;
 }
 
@@ -276,12 +277,12 @@ out:
                PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
 }
 
-int com_setatt(__a_unused struct stream_cipher_context *scc, int argc, char * const * const argv)
+int com_setatt(struct command_context *cc)
 {
-       if (argc < 3)
+       if (cc->argc < 3)
                return -E_ATTR_SYNTAX;
-       return send_standard_callback_request(argc - 1, argv + 1, com_setatt_callback,
-               NULL, NULL);
+       return send_standard_callback_request(cc->argc - 1, cc->argv + 1,
+               com_setatt_callback, NULL, NULL);
 }
 
 struct addatt_event_data {
@@ -357,16 +358,16 @@ out:
        free(pb.buf);
 }
 
-int com_addatt(struct stream_cipher_context *scc, int argc, char * const * const argv)
+int com_addatt(struct command_context *cc)
 {
        int ret;
 
-       if (argc < 2)
+       if (cc->argc < 2)
                return -E_ATTR_SYNTAX;
-       ret = send_standard_callback_request(argc - 1, argv + 1, com_addatt_callback,
-               sc_send_result, scc);
+       ret = send_standard_callback_request(cc->argc - 1, cc->argv + 1,
+               com_addatt_callback, sc_send_result, cc);
        if (ret < 0)
-               sc_send_va_buffer(scc, "%s\n", para_strerror(-ret));
+               sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret));
        return ret;
 }
 
@@ -400,16 +401,16 @@ out:
        free(pb.buf);
 }
 
-int com_mvatt(struct stream_cipher_context *scc, int argc, char * const * const argv)
+int com_mvatt(struct command_context *cc)
 {
        int ret;
 
-       if (argc != 3)
+       if (cc->argc != 3)
                return -E_ATTR_SYNTAX;
-       ret = send_standard_callback_request(argc - 1, argv + 1, com_mvatt_callback,
-               sc_send_result, scc);
+       ret = send_standard_callback_request(cc->argc - 1, cc->argv + 1,
+               com_mvatt_callback, sc_send_result, cc);
        if (ret < 0)
-               sc_send_va_buffer(scc, "%s\n", para_strerror(-ret));
+               sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret));
        return ret;
 }
 
@@ -472,16 +473,16 @@ static void com_rmatt_callback(int fd, const struct osl_object *query)
        free(raad.pb.buf);
 }
 
-int com_rmatt(struct stream_cipher_context *scc, int argc, char * const * const argv)
+int com_rmatt(struct command_context *cc)
 {
        int ret;
 
-       if (argc < 2)
+       if (cc->argc < 2)
                return -E_ATTR_SYNTAX;
-       ret = send_standard_callback_request(argc - 1, argv + 1, com_rmatt_callback,
-               sc_send_result, scc);
+       ret = send_standard_callback_request(cc->argc - 1, cc->argv + 1,
+               com_rmatt_callback, sc_send_result, cc);
        if (ret < 0)
-               sc_send_va_buffer(scc, "%s\n", para_strerror(-ret));
+               sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret));
        return ret;
 }
 
diff --git a/blob.c b/blob.c
index ee4e405eba46b6c96c46048e77311051402c4808..409e348709de83de48090c0535f3aced79dda2c8 100644 (file)
--- a/blob.c
+++ b/blob.c
@@ -18,6 +18,7 @@
 #include "afs.h"
 #include "ipc.h"
 #include "portable_io.h"
+#include "command.h"
 
 /**
  * Compare two osl objects pointing to unsigned integers of 32 bit size.
@@ -163,14 +164,14 @@ static void com_lsblob_callback(struct osl_table *table,
        free(lbad.pb.buf);
 }
 
-static int com_lsblob(callback_function *f, struct stream_cipher_context *scc, int argc, char * const * const argv)
+static int com_lsblob(callback_function *f, struct command_context *cc)
 {
        uint32_t flags = 0;
        struct osl_object options = {.data = &flags, .size = sizeof(flags)};
        int i;
 
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
+       for (i = 1; i < cc->argc; i++) {
+               const char *arg = cc->argv[i];
                if (arg[0] != '-')
                        break;
                if (!strcmp(arg, "--")) {
@@ -193,8 +194,8 @@ static int com_lsblob(callback_function *f, struct stream_cipher_context *scc, i
        }
 //     if (argc > i)
 //             return -E_BLOB_SYNTAX;
-       return send_option_arg_callback_request(&options, argc - i,
-               argv + i, f, sc_send_result, scc);
+       return send_option_arg_callback_request(&options, cc->argc - i,
+               cc->argv + i, f, sc_send_result, cc);
 }
 
 static int cat_blob(struct osl_table *table, struct osl_row *row,
@@ -231,13 +232,12 @@ static void com_catblob_callback(struct osl_table *table, int fd,
        }
 }
 
-static int com_catblob(callback_function *f, struct stream_cipher_context *scc, int argc,
-               char * const * const argv)
+static int com_catblob(callback_function *f, struct command_context *cc)
 {
-       if (argc < 2)
+       if (cc->argc < 2)
                return -E_BLOB_SYNTAX;
-       return send_standard_callback_request(argc - 1, argv + 1, f,
-               sc_send_result, scc);
+       return send_standard_callback_request(cc->argc - 1, cc->argv + 1, f,
+               sc_send_result, cc);
 }
 
 /** Used for removing rows from a blob table. */
@@ -296,13 +296,12 @@ out:
        free(rmbd.pb.buf);
 }
 
-static int com_rmblob(callback_function *f, struct stream_cipher_context *scc, int argc,
-               char * const * const argv)
+static int com_rmblob(callback_function *f, struct command_context *cc)
 {
-       if (argc < 2)
+       if (cc->argc < 2)
                return -E_MOOD_SYNTAX;
-       return send_option_arg_callback_request(NULL, argc - 1, argv + 1, f,
-               sc_send_result, scc);
+       return send_option_arg_callback_request(NULL, cc->argc - 1, cc->argv + 1, f,
+               sc_send_result, cc);
 }
 
 static void com_addblob_callback(struct osl_table *table, __a_unused int fd,
@@ -425,7 +424,7 @@ static int fd2buf(struct stream_cipher_context *scc, unsigned max_size, struct o
  * \return Negative on errors, the return value of the underlying call to
  * send_callback_request() otherwise.
  */
-static int stdin_command(struct stream_cipher_context *scc, struct osl_object *arg_obj,
+static int stdin_command(struct command_context *cc, struct osl_object *arg_obj,
                callback_function *f, unsigned max_len,
                callback_result_handler *result_handler,
                void *private_result_data)
@@ -433,10 +432,10 @@ static int stdin_command(struct stream_cipher_context *scc, struct osl_object *a
        struct osl_object query, stdin_obj;
        int ret;
 
-       ret = sc_send_buffer(scc, AWAITING_DATA_MSG);
+       ret = sc_send_buffer(&cc->scc, AWAITING_DATA_MSG);
        if (ret < 0)
                return ret;
-       ret = fd2buf(scc, max_len, &stdin_obj);
+       ret = fd2buf(&cc->scc, max_len, &stdin_obj);
        if (ret < 0)
                return ret;
        query.size = arg_obj->size + stdin_obj.size;
@@ -449,18 +448,17 @@ static int stdin_command(struct stream_cipher_context *scc, struct osl_object *a
        return ret;
 }
 
-static int com_addblob(callback_function *f, struct stream_cipher_context *scc, int argc,
-               char * const * const argv)
+static int com_addblob(callback_function *f, struct command_context *cc)
 {
        struct osl_object arg_obj;
 
-       if (argc != 2)
+       if (cc->argc != 2)
                return -E_BLOB_SYNTAX;
-       if (!*argv[1]) /* empty name is reserved for the dummy row */
+       if (!*cc->argv[1]) /* empty name is reserved for the dummy row */
                return -E_BLOB_SYNTAX;
-       arg_obj.size = strlen(argv[1]) + 1;
-       arg_obj.data = (char *)argv[1];
-       return stdin_command(scc, &arg_obj, f, 10 * 1024 * 1024, NULL, NULL);
+       arg_obj.size = strlen(cc->argv[1]) + 1;
+       arg_obj.data = (char *)cc->argv[1];
+       return stdin_command(cc, &arg_obj, f, 10 * 1024 * 1024, NULL, NULL);
 }
 
 /* FIXME: Print output to client, not to log file */
@@ -486,13 +484,12 @@ out:
                PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
 }
 
-static int com_mvblob(callback_function *f, __a_unused struct stream_cipher_context *scc,
-               int argc, char * const * const argv)
+static int com_mvblob(callback_function *f, struct command_context *cc)
 {
-       if (argc != 3)
+       if (cc->argc != 3)
                return -E_MOOD_SYNTAX;
-       return send_option_arg_callback_request(NULL, argc - 1, argv + 1, f,
-               NULL, NULL);
+       return send_option_arg_callback_request(NULL, cc->argc - 1,
+               cc->argv + 1, f, NULL, NULL);
 }
 
 #define DEFINE_BLOB_COMMAND(cmd_name, table_name, cmd_prefix) \
@@ -500,9 +497,9 @@ static int com_mvblob(callback_function *f, __a_unused struct stream_cipher_cont
        { \
                return com_ ## cmd_name ## blob_callback(table_name ## _table, fd, query); \
        } \
-       int com_ ## cmd_name ## cmd_prefix(struct stream_cipher_context *scc, int argc, char * const * const argv) \
+       int com_ ## cmd_name ## cmd_prefix(struct command_context *cc) \
        { \
-               return com_ ## cmd_name ## blob(com_ ## cmd_name ## cmd_prefix ## _callback, scc, argc, argv); \
+               return com_ ## cmd_name ## blob(com_ ## cmd_name ## cmd_prefix ## _callback, cc); \
        }
 
 static int blob_get_name_by_id(struct osl_table *table, uint32_t id,
index 4aa262ce36f2f07c026e8453bfc2364f4684884f..4a464ebf88c56ab4ed0257e39ae5767709819811 100644 (file)
--- a/command.c
+++ b/command.c
@@ -41,7 +41,7 @@
 extern int mmd_mutex;
 extern struct misc_meta_data *mmd;
 extern struct sender senders[];
-int send_afs_status(struct stream_cipher_context *scc, int parser_friendly);
+int send_afs_status(struct command_context *cc, int parser_friendly);
 
 const char *status_item_list[] = {STATUS_ITEM_ARRAY};
 
@@ -193,29 +193,29 @@ static int check_sender_args(int argc, char * const * argv, struct sender_comman
        return 1;
 }
 
-int com_sender(struct stream_cipher_context *scc, int argc, char * const * argv)
+int com_sender(struct command_context *cc)
 {
        int i, ret;
        char *msg = NULL;
        struct sender_command_data scd;
 
-       if (argc < 2) {
+       if (cc->argc < 2) {
                for (i = 0; senders[i].name; i++) {
                        char *tmp = make_message("%s%s\n",
                                msg? msg : "", senders[i].name);
                        free(msg);
                        msg = tmp;
                }
-               ret = sc_send_buffer(scc, msg);
+               ret = sc_send_buffer(&cc->scc, msg);
                free(msg);
                return ret;
        }
-       ret = check_sender_args(argc, argv, &scd);
+       ret = check_sender_args(cc->argc, cc->argv, &scd);
        if (ret < 0) {
                if (scd.sender_num < 0)
                        return ret;
                msg = senders[scd.sender_num].help();
-               ret = sc_send_buffer(scc, msg);
+               ret = sc_send_buffer(&cc->scc, msg);
                free(msg);
                return ret;
        }
@@ -224,7 +224,7 @@ int com_sender(struct stream_cipher_context *scc, int argc, char * const * argv)
        case SENDER_ADD:
        case SENDER_DELETE:
                assert(senders[scd.sender_num].resolve_target);
-               ret = senders[scd.sender_num].resolve_target(argv[3], &scd);
+               ret = senders[scd.sender_num].resolve_target(cc->argv[3], &scd);
                if (ret < 0)
                        return ret;
        }
@@ -244,13 +244,13 @@ int com_sender(struct stream_cipher_context *scc, int argc, char * const * argv)
 }
 
 /* server info */
-int com_si(struct stream_cipher_context *scc, int argc, __a_unused char * const * argv)
+int com_si(struct command_context *cc)
 {
        int i, ret;
        char *ut;
        char *sender_info = NULL;
 
-       if (argc != 1)
+       if (cc->argc != 1)
                return -E_COMMAND_SYNTAX;
        mutex_lock(mmd_mutex);
        for (i = 0; senders[i].name; i++) {
@@ -259,7 +259,7 @@ int com_si(struct stream_cipher_context *scc, int argc, __a_unused char * const
                free(info);
        }
        ut = get_server_uptime_str(now);
-       ret = sc_send_va_buffer(scc, "version: " GIT_VERSION "\n"
+       ret = sc_send_va_buffer(&cc->scc, "version: " GIT_VERSION "\n"
                "up: %s\nplayed: %u\n"
                "server_pid: %d\n"
                "afs_pid: %d\n"
@@ -284,11 +284,11 @@ int com_si(struct stream_cipher_context *scc, int argc, __a_unused char * const
 }
 
 /* version */
-int com_version(struct stream_cipher_context *scc, int argc, __a_unused char * const * argv)
+int com_version(struct command_context *cc)
 {
-       if (argc != 1)
+       if (cc->argc != 1)
                return -E_COMMAND_SYNTAX;
-       return sc_send_buffer(scc, VERSION_TEXT("server")
+       return sc_send_buffer(&cc->scc, VERSION_TEXT("server")
                "built: " BUILD_DATE "\n"
                UNAME_RS ", " CC_VERSION "\n"
        );
@@ -350,7 +350,7 @@ static char *empty_status_items(int parser_friendly)
 #undef EMPTY_STATUS_ITEMS
 
 /* stat */
-int com_stat(struct stream_cipher_context *scc, int argc, char * const * argv)
+int com_stat(struct command_context *cc)
 {
        int i, ret;
        struct misc_meta_data tmp, *nmmd = &tmp;
@@ -360,8 +360,8 @@ int com_stat(struct stream_cipher_context *scc, int argc, char * const * argv)
 
        para_sigaction(SIGUSR1, dummy);
 
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
+       for (i = 1; i < cc->argc; i++) {
+               const char *arg = cc->argv[i];
                if (arg[0] != '-')
                        break;
                if (!strcmp(arg, "--")) {
@@ -380,12 +380,12 @@ int com_stat(struct stream_cipher_context *scc, int argc, char * const * argv)
                }
                return -E_COMMAND_SYNTAX;
        }
-       if (i != argc)
+       if (i != cc->argc)
                return -E_COMMAND_SYNTAX;
        for (;;) {
                mmd_dup(nmmd);
                s = get_status(nmmd, parser_friendly);
-               ret = sc_send_buffer(scc, s);
+               ret = sc_send_buffer(&cc->scc, s);
                free(s);
                if (ret < 0)
                        goto out;
@@ -393,11 +393,11 @@ int com_stat(struct stream_cipher_context *scc, int argc, char * const * argv)
                        static char *esi;
                        if (!esi)
                                esi = empty_status_items(parser_friendly);
-                       ret = sc_send_buffer(scc, esi);
+                       ret = sc_send_buffer(&cc->scc, esi);
                        if (ret < 0)
                                goto out;
                } else
-                       send_afs_status(scc, parser_friendly);
+                       send_afs_status(cc, parser_friendly);
                ret = 1;
                if (num > 0 && !--num)
                        goto out;
@@ -449,30 +449,30 @@ static struct server_command *get_cmd_ptr(const char *name, char **handler)
 }
 
 /* help */
-int com_help(struct stream_cipher_context *scc, int argc, char * const * argv)
+int com_help(struct command_context *cc)
 {
        struct server_command *cmd;
        char *perms, *handler;
        int ret;
 
-       if (argc < 2) {
+       if (cc->argc < 2) {
                /* no argument given, print list of commands */
-               if ((ret = send_list_of_commands(scc, server_cmds, "server")) < 0)
+               if ((ret = send_list_of_commands(&cc->scc, server_cmds, "server")) < 0)
                        return ret;
-               return send_list_of_commands(scc, afs_cmds, "afs");
+               return send_list_of_commands(&cc->scc, afs_cmds, "afs");
        }
        /* argument given for help */
-       cmd = get_cmd_ptr(argv[1], &handler);
+       cmd = get_cmd_ptr(cc->argv[1], &handler);
        if (!cmd)
                return -E_BAD_CMD;
        perms = cmd_perms_itohuman(cmd->perms);
-       ret = sc_send_va_buffer(scc,
+       ret = sc_send_va_buffer(&cc->scc,
                "%s - %s\n\n"
                "handler: %s\n"
                "permissions: %s\n"
                "usage: %s\n\n"
                "%s\n",
-               argv[1],
+               cc->argv[1],
                cmd->description,
                handler,
                perms,
@@ -485,39 +485,38 @@ int com_help(struct stream_cipher_context *scc, int argc, char * const * argv)
 }
 
 /* hup */
-int com_hup(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv)
+int com_hup(struct command_context *cc)
 {
-       if (argc != 1)
+       if (cc->argc != 1)
                return -E_COMMAND_SYNTAX;
        kill(getppid(), SIGHUP);
        return 1;
 }
 
 /* term */
-int com_term(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv)
+int com_term(struct command_context *cc)
 {
-       if (argc != 1)
+       if (cc->argc != 1)
                return -E_COMMAND_SYNTAX;
        kill(getppid(), SIGTERM);
        return 1;
 }
 
-int com_play(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv)
+int com_play(struct command_context *cc)
 {
-       if (argc != 1)
+       if (cc->argc != 1)
                return -E_COMMAND_SYNTAX;
        mutex_lock(mmd_mutex);
        mmd->new_vss_status_flags |= VSS_PLAYING;
        mmd->new_vss_status_flags &= ~VSS_NOMORE;
        mutex_unlock(mmd_mutex);
        return 1;
-
 }
 
 /* stop */
-int com_stop(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv)
+int com_stop(struct command_context *cc)
 {
-       if (argc != 1)
+       if (cc->argc != 1)
                return -E_COMMAND_SYNTAX;
        mutex_lock(mmd_mutex);
        mmd->new_vss_status_flags &= ~VSS_PLAYING;
@@ -528,9 +527,9 @@ int com_stop(__a_unused struct stream_cipher_context *scc, int argc, __a_unused
 }
 
 /* pause */
-int com_pause(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv)
+int com_pause(struct command_context *cc)
 {
-       if (argc != 1)
+       if (cc->argc != 1)
                return -E_COMMAND_SYNTAX;
        mutex_lock(mmd_mutex);
        if (!vss_paused() && !vss_stopped()) {
@@ -543,9 +542,9 @@ int com_pause(__a_unused struct stream_cipher_context *scc, int argc, __a_unused
 }
 
 /* next */
-int com_next(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv)
+int com_next(struct command_context *cc)
 {
-       if (argc != 1)
+       if (cc->argc != 1)
                return -E_COMMAND_SYNTAX;
        mutex_lock(mmd_mutex);
        mmd->events++;
@@ -555,9 +554,9 @@ int com_next(__a_unused struct stream_cipher_context *scc, int argc, __a_unused
 }
 
 /* nomore */
-int com_nomore(__a_unused struct stream_cipher_context *scc, int argc, __a_unused char * const * argv)
+int com_nomore(struct command_context *cc)
 {
-       if (argc != 1)
+       if (cc->argc != 1)
                return -E_COMMAND_SYNTAX;
        mutex_lock(mmd_mutex);
        if (vss_playing() || vss_paused())
@@ -567,16 +566,16 @@ int com_nomore(__a_unused struct stream_cipher_context *scc, int argc, __a_unuse
 }
 
 /* ff */
-int com_ff(__a_unused struct stream_cipher_context *scc, int argc, char * const * argv)
+int com_ff(struct command_context *cc)
 {
        long promille;
        int ret, backwards = 0;
        unsigned i;
        char c;
 
-       if (argc != 2)
+       if (cc->argc != 2)
                return -E_COMMAND_SYNTAX;
-       if (!(ret = sscanf(argv[1], "%u%c", &i, &c)))
+       if (!(ret = sscanf(cc->argv[1], "%u%c", &i, &c)))
                return -E_COMMAND_SYNTAX;
        if (ret > 1 && c == '-')
                backwards = 1; /* jmp backwards */
@@ -606,14 +605,14 @@ out:
 }
 
 /* jmp */
-int com_jmp(__a_unused struct stream_cipher_context *scc, int argc, char * const * argv)
+int com_jmp(struct command_context *cc)
 {
        long unsigned int i;
        int ret;
 
-       if (argc != 2)
+       if (cc->argc != 2)
                return -E_COMMAND_SYNTAX;
-       if (sscanf(argv[1], "%lu", &i) <= 0)
+       if (sscanf(cc->argv[1], "%lu", &i) <= 0)
                return -E_COMMAND_SYNTAX;
        mutex_lock(mmd_mutex);
        ret = -E_NO_AUDIO_FILE;
@@ -733,17 +732,15 @@ static void reset_signals(void)
  */
 __noreturn void handle_connect(int fd, const char *peername)
 {
-       int ret, argc;
+       int ret;
        char buf[4096];
        unsigned char rand_buf[CHALLENGE_SIZE + 2 * SESSION_KEY_LEN];
        unsigned char challenge_hash[HASH_SIZE];
-       struct user *u;
-       struct server_command *cmd = NULL;
-       char **argv = NULL;
        char *p, *command = NULL;
        size_t numbytes;
-       struct stream_cipher_context scc = {.fd = fd};
+       struct command_context cc_struct = {.peer = peername}, *cc = &cc_struct;
 
+       cc->scc.fd = fd;
        reset_signals();
        /* we need a blocking fd here as recv() might return EAGAIN otherwise. */
        ret = mark_fd_blocking(fd);
@@ -767,10 +764,10 @@ __noreturn void handle_connect(int fd, const char *peername)
                goto net_err;
        p = buf + strlen(AUTH_REQUEST_MSG);
        PARA_DEBUG_LOG("received auth request for user %s\n", p);
-       u = lookup_user(p);
-       if (u) {
+       cc->u = lookup_user(p);
+       if (cc->u) {
                get_random_bytes_or_die(rand_buf, sizeof(rand_buf));
-               ret = pub_encrypt(u->pubkey, rand_buf, sizeof(rand_buf),
+               ret = pub_encrypt(cc->u->pubkey, rand_buf, sizeof(rand_buf),
                        (unsigned char *)buf);
                if (ret < 0)
                        goto net_err;
@@ -796,7 +793,7 @@ __noreturn void handle_connect(int fd, const char *peername)
        numbytes = ret;
        PARA_DEBUG_LOG("received %d bytes challenge response\n", ret);
        ret = -E_BAD_USER;
-       if (!u)
+       if (!cc->u)
                goto net_err;
        /*
         * The correct response is the hash of the first CHALLENGE_SIZE bytes
@@ -810,50 +807,50 @@ __noreturn void handle_connect(int fd, const char *peername)
                goto net_err;
        /* auth successful */
        alarm(0);
-       PARA_INFO_LOG("good auth for %s\n", u->name);
+       PARA_INFO_LOG("good auth for %s\n", cc->u->name);
        /* init stream cipher keys with the second part of the random buffer */
-       scc.recv = sc_new(rand_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
-       scc.send = sc_new(rand_buf + CHALLENGE_SIZE + SESSION_KEY_LEN, SESSION_KEY_LEN);
-       ret = sc_send_buffer(&scc, PROCEED_MSG);
+       cc->scc.recv = sc_new(rand_buf + CHALLENGE_SIZE, SESSION_KEY_LEN);
+       cc->scc.send = sc_new(rand_buf + CHALLENGE_SIZE + SESSION_KEY_LEN, SESSION_KEY_LEN);
+       ret = sc_send_buffer(&cc->scc, PROCEED_MSG);
        if (ret < 0)
                goto net_err;
-       ret = read_command(&scc, &command);
+       ret = read_command(&cc->scc, &command);
        if (ret == -E_COMMAND_SYNTAX)
                goto err_out;
        if (ret < 0)
                goto net_err;
        ret = -E_BAD_CMD;
-       cmd = parse_cmd(command);
-       if (!cmd)
+       cc->cmd = parse_cmd(command);
+       if (!cc->cmd)
                goto err_out;
        /* valid command, check permissions */
-       ret = check_perms(u->perms, cmd);
+       ret = check_perms(cc->u->perms, cc->cmd);
        if (ret < 0)
                goto err_out;
        /* valid command and sufficient perms */
-       ret = create_argv(command, "\n", &argv);
+       ret = create_argv(command, "\n", &cc->argv);
        if (ret < 0)
                goto err_out;
-       argc = ret;
-       PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u->name,
-                       peername);
-       ret = cmd->handler(&scc, argc, argv);
-       free_argv(argv);
+       cc->argc = ret;
+       PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cc->cmd->name,
+               cc->u->name, peername);
+       ret = cc->cmd->handler(cc);
+       free_argv(cc->argv);
        mutex_lock(mmd_mutex);
        mmd->num_commands++;
        mutex_unlock(mmd_mutex);
        if (ret >= 0)
                goto out;
 err_out:
-       sc_send_va_buffer(&scc, "%s\n", para_strerror(-ret));
+       sc_send_va_buffer(&cc->scc, "%s\n", para_strerror(-ret));
 net_err:
        PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
 out:
        free(command);
-       sc_free(scc.recv);
-       sc_free(scc.send);
+       sc_free(cc->scc.recv);
+       sc_free(cc->scc.send);
        mutex_lock(mmd_mutex);
-       if (cmd && (cmd->perms & AFS_WRITE) && ret >= 0)
+       if (cc->cmd && (cc->cmd->perms & AFS_WRITE) && ret >= 0)
                mmd->events++;
        mmd->active_connections--;
        mutex_unlock(mmd_mutex);
index fd879829de5683c1adeefe9b7a957df62d247a43..05510cc08aa33d50a104f71a05d353ad3027e7d2 100644 (file)
--- a/command.h
+++ b/command.h
@@ -1,5 +1,21 @@
 /** \file command.h The structure of server and afs commands. */
 
+/** Per connection data available to command handlers. */
+struct command_context {
+       /** Network address of the peer. */
+       const char *peer;
+       /** The paraslash user that executes this command. */
+       struct user *u;
+       /** Argument count. */
+       int argc;
+       /** Argument vector. */
+       char **argv;
+       /** The command being executed. */
+       struct server_command *cmd;
+       /** File descriptor and crypto keys. */
+       struct stream_cipher_context scc;
+};
+
 /**
  * Defines one command of para_server.
  */
@@ -7,7 +23,7 @@ struct server_command {
        /** The name of the command. */
        const char *name;
        /** Pointer to the function that handles the command. */
-       int (*handler)(struct stream_cipher_context *, int, char * const * const);
+       int (*handler)(struct command_context *);
        /** The privileges a user must have to execute this command. */
        unsigned int perms;
        /** One-line description of the command. */