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 13 static char *saved_boot_config; 14 15 static 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 */ 26 static 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 if (!key) 36 return -ENOMEM; 37 38 xbc_for_each_key_value(leaf, val) { 39 ret = xbc_node_compose_key(leaf, key, XBC_KEYLEN_MAX); 40 if (ret < 0) 41 break; 42 ret = snprintf(dst, rest(dst, end), "%s = ", key); 43 if (ret < 0) 44 break; 45 dst += ret; 46 vnode = xbc_node_get_child(leaf); 47 if (vnode) { 48 xbc_array_for_each_value(vnode, val) { 49 if (strchr(val, '"')) 50 q = '\''; 51 else 52 q = '"'; 53 ret = snprintf(dst, rest(dst, end), "%c%s%c%s", 54 q, val, q, xbc_node_is_array(vnode) ? ", " : "\n"); 55 if (ret < 0) 56 goto out; 57 dst += ret; 58 } 59 } else { 60 ret = snprintf(dst, rest(dst, end), "\"\"\n"); 61 if (ret < 0) 62 break; 63 dst += ret; 64 } 65 } 66 if (cmdline_has_extra_options() && ret >= 0 && boot_command_line[0]) { 67 ret = snprintf(dst, rest(dst, end), "# Parameters from bootloader:\n# %s\n", 68 boot_command_line); 69 if (ret > 0) 70 dst += ret; 71 } 72 out: 73 kfree(key); 74 75 return ret < 0 ? ret : dst - (end - size); 76 } 77 78 static int __init proc_boot_config_init(void) 79 { 80 int len; 81 82 len = copy_xbc_key_value_list(NULL, 0); 83 if (len < 0) 84 return len; 85 86 if (len > 0) { 87 saved_boot_config = kzalloc(len + 1, GFP_KERNEL); 88 if (!saved_boot_config) 89 return -ENOMEM; 90 91 len = copy_xbc_key_value_list(saved_boot_config, len + 1); 92 if (len < 0) { 93 kfree(saved_boot_config); 94 return len; 95 } 96 } 97 98 proc_create_single("bootconfig", 0, NULL, boot_config_proc_show); 99 100 return 0; 101 } 102 fs_initcall(proc_boot_config_init); 103