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 const char *val; 30 char *key, *end = dst + size; 31 int ret = 0; 32 33 key = kzalloc(XBC_KEYLEN_MAX, GFP_KERNEL); 34 35 xbc_for_each_key_value(leaf, val) { 36 ret = xbc_node_compose_key(leaf, key, XBC_KEYLEN_MAX); 37 if (ret < 0) 38 break; 39 ret = snprintf(dst, rest(dst, end), "%s = ", key); 40 if (ret < 0) 41 break; 42 dst += ret; 43 vnode = xbc_node_get_child(leaf); 44 if (vnode && xbc_node_is_array(vnode)) { 45 xbc_array_for_each_value(vnode, val) { 46 ret = snprintf(dst, rest(dst, end), "\"%s\"%s", 47 val, vnode->next ? ", " : "\n"); 48 if (ret < 0) 49 goto out; 50 dst += ret; 51 } 52 } else { 53 ret = snprintf(dst, rest(dst, end), "\"%s\"\n", val); 54 if (ret < 0) 55 break; 56 dst += ret; 57 } 58 } 59 out: 60 kfree(key); 61 62 return ret < 0 ? ret : dst - (end - size); 63 } 64 65 static int __init proc_boot_config_init(void) 66 { 67 int len; 68 69 len = copy_xbc_key_value_list(NULL, 0); 70 if (len < 0) 71 return len; 72 73 if (len > 0) { 74 saved_boot_config = kzalloc(len + 1, GFP_KERNEL); 75 if (!saved_boot_config) 76 return -ENOMEM; 77 78 len = copy_xbc_key_value_list(saved_boot_config, len + 1); 79 if (len < 0) { 80 kfree(saved_boot_config); 81 return len; 82 } 83 } 84 85 proc_create_single("bootconfig", 0, NULL, boot_config_proc_show); 86 87 return 0; 88 } 89 fs_initcall(proc_boot_config_init); 90