linux/fs/proc/bootconfig.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * /proc/bootconfig - Extra boot configuration
   4 */
   5#include <linux/fs.h>
   6#include <linux/init.h>
   7#include <linux/printk.h>
   8#include <linux/proc_fs.h>
   9#include <linux/seq_file.h>
  10#include <linux/bootconfig.h>
  11#include <linux/slab.h>
  12
  13static char *saved_boot_config;
  14
  15static int boot_config_proc_show(struct seq_file *m, void *v)
  16{
  17        if (saved_boot_config)
  18                seq_puts(m, saved_boot_config);
  19        return 0;
  20}
  21
  22/* Rest size of buffer */
  23#define rest(dst, end) ((end) > (dst) ? (end) - (dst) : 0)
  24
  25/* Return the needed total length if @size is 0 */
  26static int __init copy_xbc_key_value_list(char *dst, size_t size)
  27{
  28        struct xbc_node *leaf, *vnode;
  29        char *key, *end = dst + size;
  30        const char *val;
  31        char q;
  32        int ret = 0;
  33
  34        key = kzalloc(XBC_KEYLEN_MAX, GFP_KERNEL);
  35
  36        xbc_for_each_key_value(leaf, val) {
  37                ret = xbc_node_compose_key(leaf, key, XBC_KEYLEN_MAX);
  38                if (ret < 0)
  39                        break;
  40                ret = snprintf(dst, rest(dst, end), "%s = ", key);
  41                if (ret < 0)
  42                        break;
  43                dst += ret;
  44                vnode = xbc_node_get_child(leaf);
  45                if (vnode) {
  46                        xbc_array_for_each_value(vnode, val) {
  47                                if (strchr(val, '"'))
  48                                        q = '\'';
  49                                else
  50                                        q = '"';
  51                                ret = snprintf(dst, rest(dst, end), "%c%s%c%s",
  52                                        q, val, q, vnode->next ? ", " : "\n");
  53                                if (ret < 0)
  54                                        goto out;
  55                                dst += ret;
  56                        }
  57                } else {
  58                        ret = snprintf(dst, rest(dst, end), "\"\"\n");
  59                        if (ret < 0)
  60                                break;
  61                        dst += ret;
  62                }
  63        }
  64out:
  65        kfree(key);
  66
  67        return ret < 0 ? ret : dst - (end - size);
  68}
  69
  70static int __init proc_boot_config_init(void)
  71{
  72        int len;
  73
  74        len = copy_xbc_key_value_list(NULL, 0);
  75        if (len < 0)
  76                return len;
  77
  78        if (len > 0) {
  79                saved_boot_config = kzalloc(len + 1, GFP_KERNEL);
  80                if (!saved_boot_config)
  81                        return -ENOMEM;
  82
  83                len = copy_xbc_key_value_list(saved_boot_config, len + 1);
  84                if (len < 0) {
  85                        kfree(saved_boot_config);
  86                        return len;
  87                }
  88        }
  89
  90        proc_create_single("bootconfig", 0, NULL, boot_config_proc_show);
  91
  92        return 0;
  93}
  94fs_initcall(proc_boot_config_init);
  95