RHEL4/kernel/params.c
<<
>>
Prefs
   1/* Helpers for initial module or kernel cmdline parsing
   2   Copyright (C) 2001 Rusty Russell.
   3
   4    This program is free software; you can redistribute it and/or modify
   5    it under the terms of the GNU General Public License as published by
   6    the Free Software Foundation; either version 2 of the License, or
   7    (at your option) any later version.
   8
   9    This program is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU General Public License for more details.
  13
  14    You should have received a copy of the GNU General Public License
  15    along with this program; if not, write to the Free Software
  16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17*/
  18#include <linux/moduleparam.h>
  19#include <linux/kernel.h>
  20#include <linux/string.h>
  21#include <linux/errno.h>
  22#include <linux/module.h>
  23
  24#if 0
  25#define DEBUGP printk
  26#else
  27#define DEBUGP(fmt, a...)
  28#endif
  29
  30static inline int dash2underscore(char c)
  31{
  32        if (c == '-')
  33                return '_';
  34        return c;
  35}
  36
  37static inline int parameq(const char *input, const char *paramname)
  38{
  39        unsigned int i;
  40        for (i = 0; dash2underscore(input[i]) == paramname[i]; i++)
  41                if (input[i] == '\0')
  42                        return 1;
  43        return 0;
  44}
  45
  46static int parse_one(char *param,
  47                     char *val,
  48                     struct kernel_param *params, 
  49                     unsigned num_params,
  50                     int (*handle_unknown)(char *param, char *val))
  51{
  52        unsigned int i;
  53
  54        /* Find parameter */
  55        for (i = 0; i < num_params; i++) {
  56                if (parameq(param, params[i].name)) {
  57                        DEBUGP("They are equal!  Calling %p\n",
  58                               params[i].set);
  59                        return params[i].set(val, &params[i]);
  60                }
  61        }
  62
  63        if (handle_unknown) {
  64                DEBUGP("Unknown argument: calling %p\n", handle_unknown);
  65                return handle_unknown(param, val);
  66        }
  67
  68        DEBUGP("Unknown argument `%s'\n", param);
  69        return -ENOENT;
  70}
  71
  72/* You can use " around spaces, but can't escape ". */
  73/* Hyphens and underscores equivalent in parameter names. */
  74static char *next_arg(char *args, char **param, char **val)
  75{
  76        unsigned int i, equals = 0;
  77        int in_quote = 0;
  78
  79        /* Chew any extra spaces */
  80        while (*args == ' ') args++;
  81
  82        for (i = 0; args[i]; i++) {
  83                if (args[i] == ' ' && !in_quote)
  84                        break;
  85                if (equals == 0) {
  86                        if (args[i] == '=')
  87                                equals = i;
  88                }
  89                if (args[i] == '"')
  90                        in_quote = !in_quote;
  91        }
  92
  93        *param = args;
  94        if (!equals)
  95                *val = NULL;
  96        else {
  97                args[equals] = '\0';
  98                *val = args + equals + 1;
  99
 100                /* Don't include quotes in value. */
 101                if (**val == '"') {
 102                        (*val)++;
 103                        if (args[i-1] == '"')
 104                                args[i-1] = '\0';
 105                }
 106        }
 107
 108        if (args[i]) {
 109                args[i] = '\0';
 110                return args + i + 1;
 111        } else
 112                return args + i;
 113}
 114
 115/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
 116int parse_args(const char *name,
 117               char *args,
 118               struct kernel_param *params,
 119               unsigned num,
 120               int (*unknown)(char *param, char *val))
 121{
 122        char *param, *val;
 123
 124        DEBUGP("Parsing ARGS: %s\n", args);
 125
 126        while (*args) {
 127                int ret;
 128
 129                args = next_arg(args, &param, &val);
 130                ret = parse_one(param, val, params, num, unknown);
 131                switch (ret) {
 132                case -ENOENT:
 133                        printk(KERN_ERR "%s: Unknown parameter `%s'\n",
 134                               name, param);
 135                        return ret;
 136                case -ENOSPC:
 137                        printk(KERN_ERR
 138                               "%s: `%s' too large for parameter `%s'\n",
 139                               name, val ?: "", param);
 140                        return ret;
 141                case 0:
 142                        break;
 143                default:
 144                        printk(KERN_ERR
 145                               "%s: `%s' invalid for parameter `%s'\n",
 146                               name, val ?: "", param);
 147                        return ret;
 148                }
 149        }
 150
 151        /* All parsed OK. */
 152        return 0;
 153}
 154
 155/* Lazy bastard, eh? */
 156#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn)       \
 157        int param_set_##name(const char *val, struct kernel_param *kp)  \
 158        {                                                               \
 159                char *endp;                                             \
 160                tmptype l;                                              \
 161                                                                        \
 162                if (!val) return -EINVAL;                               \
 163                l = strtolfn(val, &endp, 0);                            \
 164                if (endp == val || ((type)l != l))                      \
 165                        return -EINVAL;                                 \
 166                *((type *)kp->arg) = l;                                 \
 167                return 0;                                               \
 168        }                                                               \
 169        int param_get_##name(char *buffer, struct kernel_param *kp)     \
 170        {                                                               \
 171                return sprintf(buffer, format, *((type *)kp->arg));     \
 172        }
 173
 174STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, simple_strtoul);
 175STANDARD_PARAM_DEF(short, short, "%hi", long, simple_strtol);
 176STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, simple_strtoul);
 177STANDARD_PARAM_DEF(int, int, "%i", long, simple_strtol);
 178STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, simple_strtoul);
 179STANDARD_PARAM_DEF(long, long, "%li", long, simple_strtol);
 180STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, simple_strtoul);
 181
 182int param_set_charp(const char *val, struct kernel_param *kp)
 183{
 184        if (!val) {
 185                printk(KERN_ERR "%s: string parameter expected\n",
 186                       kp->name);
 187                return -EINVAL;
 188        }
 189
 190        if (strlen(val) > 1024) {
 191                printk(KERN_ERR "%s: string parameter too long\n",
 192                       kp->name);
 193                return -ENOSPC;
 194        }
 195
 196        *(char **)kp->arg = (char *)val;
 197        return 0;
 198}
 199
 200int param_get_charp(char *buffer, struct kernel_param *kp)
 201{
 202        return sprintf(buffer, "%s", *((char **)kp->arg));
 203}
 204
 205int param_set_bool(const char *val, struct kernel_param *kp)
 206{
 207        /* No equals means "set"... */
 208        if (!val) val = "1";
 209
 210        /* One of =[yYnN01] */
 211        switch (val[0]) {
 212        case 'y': case 'Y': case '1':
 213                *(int *)kp->arg = 1;
 214                return 0;
 215        case 'n': case 'N': case '0':
 216                *(int *)kp->arg = 0;
 217                return 0;
 218        }
 219        return -EINVAL;
 220}
 221
 222int param_get_bool(char *buffer, struct kernel_param *kp)
 223{
 224        /* Y and N chosen as being relatively non-coder friendly */
 225        return sprintf(buffer, "%c", (*(int *)kp->arg) ? 'Y' : 'N');
 226}
 227
 228int param_set_invbool(const char *val, struct kernel_param *kp)
 229{
 230        int boolval, ret;
 231        struct kernel_param dummy = { .arg = &boolval };
 232
 233        ret = param_set_bool(val, &dummy);
 234        if (ret == 0)
 235                *(int *)kp->arg = !boolval;
 236        return ret;
 237}
 238
 239int param_get_invbool(char *buffer, struct kernel_param *kp)
 240{
 241        int val;
 242        struct kernel_param dummy = { .arg = &val };
 243
 244        val = !*(int *)kp->arg;
 245        return param_get_bool(buffer, &dummy);
 246}
 247
 248/* We cheat here and temporarily mangle the string. */
 249int param_array(const char *name,
 250                const char *val,
 251                unsigned int min, unsigned int max,
 252                void *elem, int elemsize,
 253                int (*set)(const char *, struct kernel_param *kp),
 254                int *num)
 255{
 256        int ret;
 257        struct kernel_param kp;
 258        char save;
 259
 260        /* Get the name right for errors. */
 261        kp.name = name;
 262        kp.arg = elem;
 263
 264        /* No equals sign? */
 265        if (!val) {
 266                printk(KERN_ERR "%s: expects arguments\n", name);
 267                return -EINVAL;
 268        }
 269
 270        *num = 0;
 271        /* We expect a comma-separated list of values. */
 272        do {
 273                int len;
 274
 275                if (*num == max) {
 276                        printk(KERN_ERR "%s: can only take %i arguments\n",
 277                               name, max);
 278                        return -EINVAL;
 279                }
 280                len = strcspn(val, ",");
 281
 282                /* nul-terminate and parse */
 283                save = val[len];
 284                ((char *)val)[len] = '\0';
 285                ret = set(val, &kp);
 286
 287                if (ret != 0)
 288                        return ret;
 289                kp.arg += elemsize;
 290                val += len+1;
 291                (*num)++;
 292        } while (save == ',');
 293
 294        if (*num < min) {
 295                printk(KERN_ERR "%s: needs at least %i arguments\n",
 296                       name, min);
 297                return -EINVAL;
 298        }
 299        return 0;
 300}
 301
 302int param_array_set(const char *val, struct kernel_param *kp)
 303{
 304        struct kparam_array *arr = kp->arg;
 305
 306        return param_array(kp->name, val, 1, arr->max, arr->elem,
 307                           arr->elemsize, arr->set, arr->num);
 308}
 309
 310int param_array_get(char *buffer, struct kernel_param *kp)
 311{
 312        int i, off, ret;
 313        struct kparam_array *arr = kp->arg;
 314        struct kernel_param p;
 315
 316        p = *kp;
 317        for (i = off = 0; i < *arr->num; i++) {
 318                if (i)
 319                        buffer[off++] = ',';
 320                p.arg = arr->elem + arr->elemsize * i;
 321                ret = arr->get(buffer + off, &p);
 322                if (ret < 0)
 323                        return ret;
 324                off += ret;
 325        }
 326        buffer[off] = '\0';
 327        return off;
 328}
 329
 330int param_set_copystring(const char *val, struct kernel_param *kp)
 331{
 332        struct kparam_string *kps = kp->arg;
 333
 334        if (strlen(val)+1 > kps->maxlen) {
 335                printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
 336                       kp->name, kps->maxlen-1);
 337                return -ENOSPC;
 338        }
 339        strcpy(kps->string, val);
 340        return 0;
 341}
 342
 343int param_get_string(char *buffer, struct kernel_param *kp)
 344{
 345        struct kparam_string *kps = kp->arg;
 346        return strlcpy(buffer, kps->string, kps->maxlen);
 347}
 348
 349EXPORT_SYMBOL(param_set_byte);
 350EXPORT_SYMBOL(param_get_byte);
 351EXPORT_SYMBOL(param_set_short);
 352EXPORT_SYMBOL(param_get_short);
 353EXPORT_SYMBOL(param_set_ushort);
 354EXPORT_SYMBOL(param_get_ushort);
 355EXPORT_SYMBOL(param_set_int);
 356EXPORT_SYMBOL(param_get_int);
 357EXPORT_SYMBOL(param_set_uint);
 358EXPORT_SYMBOL(param_get_uint);
 359EXPORT_SYMBOL(param_set_long);
 360EXPORT_SYMBOL(param_get_long);
 361EXPORT_SYMBOL(param_set_ulong);
 362EXPORT_SYMBOL(param_get_ulong);
 363EXPORT_SYMBOL(param_set_charp);
 364EXPORT_SYMBOL(param_get_charp);
 365EXPORT_SYMBOL(param_set_bool);
 366EXPORT_SYMBOL(param_get_bool);
 367EXPORT_SYMBOL(param_set_invbool);
 368EXPORT_SYMBOL(param_get_invbool);
 369EXPORT_SYMBOL(param_array_set);
 370EXPORT_SYMBOL(param_array_get);
 371EXPORT_SYMBOL(param_set_copystring);
 372EXPORT_SYMBOL(param_get_string);
 373