static const char *field;
struct param {
- struct param *next;
const char *name;
const char *desc;
const char *type;
};
static int add_param(const char *name, size_t namelen, enum parm_info parm_info,
- const char *value, struct param **list)
+ const char *value, struct param *params, unsigned int params_count)
{
size_t valuelen = strlen(value);
struct param *it;
if (namelen > INT_MAX || valuelen > INT_MAX)
return -EINVAL;
- for (it = *list; it != NULL; it = it->next) {
- if (it->namelen == (int)namelen && memcmp(it->name, name, namelen) == 0)
- break;
- }
+ /* We are guaranteed to have a match, or at least one empty entry */
+ for (unsigned int i = 0; i < params_count; i++) {
+ it = ¶ms[i];
+
+ if (it->name != NULL && (it->namelen != (int)namelen ||
+ memcmp(it->name, name, namelen) != 0)) {
+ continue;
+ }
- if (it == NULL) {
- it = malloc(sizeof(struct param));
- if (it == NULL)
- return -ENOMEM;
- it->next = *list;
- *list = it;
it->name = name;
it->namelen = namelen;
- it->desc = NULL;
- it->type = NULL;
- it->desclen = 0;
- it->typelen = 0;
- }
- switch (parm_info) {
- case (parm_desc):
- it->desc = value;
- it->desclen = (int)valuelen;
- break;
- case (parm_type):
- it->type = value;
- it->typelen = (int)valuelen;
+ switch (parm_info) {
+ case (parm_desc):
+ it->desc = value;
+ it->desclen = (int)valuelen;
+ break;
+ case (parm_type):
+ it->type = value;
+ it->typelen = (int)valuelen;
+ break;
+ }
break;
}
return 0;
}
-static int process_parm(enum parm_info parm_info, const char *value, struct param **params)
+static int process_parm(enum parm_info parm_info, const char *value, struct param *params,
+ unsigned int params_count)
{
const char *name;
size_t namelen;
name = value;
namelen = colon - value;
- ret = add_param(name, namelen, parm_info, colon + 1, params);
+ ret = add_param(name, namelen, parm_info, colon + 1, params, params_count);
if (ret < 0) {
ERR("Unable to add parameter: %s\n", strerror(-ret));
return -ENOMEM;
}
}
-static int modinfo_params_do(const struct kmod_list *list)
-{
- const struct kmod_list *l;
- struct param *params = NULL;
- int err = 0;
-
- kmod_list_foreach(l, list) {
- const char *key = kmod_module_info_get_key(l);
- const char *value = kmod_module_info_get_value(l);
- if (streq(key, "parm")) {
- err = process_parm(parm_desc, value, ¶ms);
- if (err < 0)
- goto end;
- } else if (streq(key, "parmtype")) {
- err = process_parm(parm_type, value, ¶ms);
- if (err < 0)
- goto end;
- }
- }
-
- while (params != NULL) {
- struct param *p = params;
- params = p->next;
-
- if (p->type != NULL)
- printf("%.*s:%.*s (%.*s)%c", p->namelen, p->name, p->desclen,
- p->desc, p->typelen, p->type, separator);
- else
- printf("%.*s:%.*s%c", p->namelen, p->name, p->desclen, p->desc,
- separator);
-
- free(p);
- }
-
-end:
- while (params != NULL) {
- void *tmp = params;
- params = params->next;
- free(tmp);
- }
-
- return err;
-}
-
static int modinfo_do(struct kmod_module *mod)
{
const enum kmod_module_initstate state = kmod_module_get_initstate(mod);
const bool print_parm = !print_all && streq(field, "parm");
struct kmod_list *l, *list = NULL;
struct param *params = NULL;
+ unsigned int params_count = 0;
+ char *sbuf = NULL;
int err;
/* TODO: align builtin vs not wrt listing "name:" via kmod_module_get_info() */
return err;
}
- if (print_parm) {
- err = modinfo_params_do(list);
- goto end;
+ if (print_all || print_parm) {
+ size_t count = 0;
+ size_t longest_desc = 0;
+ size_t longest_type = 0;
+
+ /*
+ * Usually parm/parmtype come in pairs, where we print once per pair.
+ *
+ * Get worst case scenario & longest entry, for sufficiently large buffers.
+ */
+ kmod_list_foreach(l, list) {
+ const char *key = kmod_module_info_get_key(l);
+
+ if (streq(key, "parm")) {
+ const char *value = kmod_module_info_get_value(l);
+ size_t len = strlen(value);
+
+ count++;
+
+ if (len > longest_desc)
+ longest_desc = len;
+ } else if (streq(key, "parmtype")) {
+ const char *value = kmod_module_info_get_value(l);
+ size_t len = strlen(value);
+
+ count++;
+
+ if (len > longest_type)
+ longest_type = len;
+ }
+ }
+
+ /* XXX: do we want to emit a warning/error here? */
+ params_count = (params_count > UINT_MAX) ? UINT_MAX : (unsigned int)count;
+
+ params = calloc(params_count, sizeof(*params));
+ /*
+ * The "name:" exists in both parm&parmtype, so don't worry if we
+ * overallocate.
+ */
+ sbuf = malloc(longest_desc + longest_type + strlen(" ()"));
+ if (params == NULL || sbuf == NULL) {
+ err = -ENOMEM;
+ goto end;
+ }
}
kmod_list_foreach(l, list) {
const char *key = kmod_module_info_get_key(l);
const char *value = kmod_module_info_get_value(l);
- if (!print_all) {
+ if (!print_all && !print_parm) {
if (streq(field, key)) {
print_line(NULL, value);
goto end;
continue;
}
if (streq(key, "parm")) {
- err = process_parm(parm_desc, value, ¶ms);
+ err = process_parm(parm_desc, value, params, params_count);
if (err < 0)
goto end;
} else if (streq(key, "parmtype")) {
- err = process_parm(parm_type, value, ¶ms);
+ err = process_parm(parm_type, value, params, params_count);
if (err < 0)
goto end;
} else {
- print_line(key, value);
+ if (print_all)
+ print_line(key, value);
}
}
- if (!print_all)
- goto end;
-
- while (params != NULL) {
- struct param *p = params;
- params = p->next;
+ for (unsigned int i = 0; i < params_count; i++) {
+ struct param *p = ¶ms[i];
+ if (p->name == NULL)
+ continue;
if (p->type != NULL)
- printf("%-16s%.*s:%.*s (%.*s)%c", "parm:", p->namelen, p->name,
- p->desclen, p->desc, p->typelen, p->type, separator);
+ sprintf(sbuf, "%.*s:%.*s (%.*s)", p->namelen, p->name, p->desclen,
+ p->desc, p->typelen, p->type);
else
- printf("%-16s%.*s:%.*s%c", "parm:", p->namelen, p->name,
- p->desclen, p->desc, separator);
+ sprintf(sbuf, "%.*s:%.*s", p->namelen, p->name, p->desclen,
+ p->desc);
- free(p);
+ print_line(print_parm ? NULL : "parm", sbuf);
}
end:
- while (params != NULL) {
- void *tmp = params;
- params = params->next;
- free(tmp);
- }
+ free(sbuf);
+ free(params);
kmod_module_info_free_list(list);
return err;