1 /* 2 * proc sysctl test driver 3 * 4 * Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the Free 8 * Software Foundation; either version 2 of the License, or at your option any 9 * later version; or, when distributed separately from the Linux kernel or 10 * when incorporated into other software packages, subject to the following 11 * license: 12 * 13 * This program is free software; you can redistribute it and/or modify it 14 * under the terms of copyleft-next (version 0.3.1 or later) as published 15 * at http://copyleft-next.org/. 16 */ 17 18 /* 19 * This module provides an interface to the proc sysctl interfaces. This 20 * driver requires CONFIG_PROC_SYSCTL. It will not normally be loaded by the 21 * system unless explicitly requested by name. You can also build this driver 22 * into your kernel. 23 */ 24 25 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 26 27 #include <linux/init.h> 28 #include <linux/list.h> 29 #include <linux/module.h> 30 #include <linux/printk.h> 31 #include <linux/fs.h> 32 #include <linux/miscdevice.h> 33 #include <linux/slab.h> 34 #include <linux/uaccess.h> 35 #include <linux/async.h> 36 #include <linux/delay.h> 37 #include <linux/vmalloc.h> 38 39 static int i_zero; 40 static int i_one_hundred = 100; 41 static int match_int_ok = 1; 42 43 struct test_sysctl_data { 44 int int_0001; 45 int int_0002; 46 int int_0003[4]; 47 48 int boot_int; 49 50 unsigned int uint_0001; 51 52 char string_0001[65]; 53 54 #define SYSCTL_TEST_BITMAP_SIZE 65536 55 unsigned long *bitmap_0001; 56 }; 57 58 static struct test_sysctl_data test_data = { 59 .int_0001 = 60, 60 .int_0002 = 1, 61 62 .int_0003[0] = 0, 63 .int_0003[1] = 1, 64 .int_0003[2] = 2, 65 .int_0003[3] = 3, 66 67 .boot_int = 0, 68 69 .uint_0001 = 314, 70 71 .string_0001 = "(none)", 72 }; 73 74 /* These are all under /proc/sys/debug/test_sysctl/ */ 75 static struct ctl_table test_table[] = { 76 { 77 .procname = "int_0001", 78 .data = &test_data.int_0001, 79 .maxlen = sizeof(int), 80 .mode = 0644, 81 .proc_handler = proc_dointvec_minmax, 82 .extra1 = &i_zero, 83 .extra2 = &i_one_hundred, 84 }, 85 { 86 .procname = "int_0002", 87 .data = &test_data.int_0002, 88 .maxlen = sizeof(int), 89 .mode = 0644, 90 .proc_handler = proc_dointvec, 91 }, 92 { 93 .procname = "int_0003", 94 .data = &test_data.int_0003, 95 .maxlen = sizeof(test_data.int_0003), 96 .mode = 0644, 97 .proc_handler = proc_dointvec, 98 }, 99 { 100 .procname = "match_int", 101 .data = &match_int_ok, 102 .maxlen = sizeof(match_int_ok), 103 .mode = 0444, 104 .proc_handler = proc_dointvec, 105 }, 106 { 107 .procname = "boot_int", 108 .data = &test_data.boot_int, 109 .maxlen = sizeof(test_data.boot_int), 110 .mode = 0644, 111 .proc_handler = proc_dointvec, 112 .extra1 = SYSCTL_ZERO, 113 .extra2 = SYSCTL_ONE, 114 }, 115 { 116 .procname = "uint_0001", 117 .data = &test_data.uint_0001, 118 .maxlen = sizeof(unsigned int), 119 .mode = 0644, 120 .proc_handler = proc_douintvec, 121 }, 122 { 123 .procname = "string_0001", 124 .data = &test_data.string_0001, 125 .maxlen = sizeof(test_data.string_0001), 126 .mode = 0644, 127 .proc_handler = proc_dostring, 128 }, 129 { 130 .procname = "bitmap_0001", 131 .data = &test_data.bitmap_0001, 132 .maxlen = SYSCTL_TEST_BITMAP_SIZE, 133 .mode = 0644, 134 .proc_handler = proc_do_large_bitmap, 135 }, 136 { } 137 }; 138 139 static struct ctl_table_header *test_sysctl_header; 140 141 static int __init test_sysctl_init(void) 142 { 143 int i; 144 145 struct { 146 int defined; 147 int wanted; 148 } match_int[] = { 149 {.defined = *(int *)SYSCTL_ZERO, .wanted = 0}, 150 {.defined = *(int *)SYSCTL_ONE, .wanted = 1}, 151 {.defined = *(int *)SYSCTL_TWO, .wanted = 2}, 152 {.defined = *(int *)SYSCTL_THREE, .wanted = 3}, 153 {.defined = *(int *)SYSCTL_FOUR, .wanted = 4}, 154 {.defined = *(int *)SYSCTL_ONE_HUNDRED, .wanted = 100}, 155 {.defined = *(int *)SYSCTL_TWO_HUNDRED, .wanted = 200}, 156 {.defined = *(int *)SYSCTL_ONE_THOUSAND, .wanted = 1000}, 157 {.defined = *(int *)SYSCTL_THREE_THOUSAND, .wanted = 3000}, 158 {.defined = *(int *)SYSCTL_INT_MAX, .wanted = INT_MAX}, 159 {.defined = *(int *)SYSCTL_MAXOLDUID, .wanted = 65535}, 160 {.defined = *(int *)SYSCTL_NEG_ONE, .wanted = -1}, 161 }; 162 163 for (i = 0; i < ARRAY_SIZE(match_int); i++) 164 if (match_int[i].defined != match_int[i].wanted) 165 match_int_ok = 0; 166 167 test_data.bitmap_0001 = kzalloc(SYSCTL_TEST_BITMAP_SIZE/8, GFP_KERNEL); 168 if (!test_data.bitmap_0001) 169 return -ENOMEM; 170 test_sysctl_header = register_sysctl("debug/test_sysctl", test_table); 171 if (!test_sysctl_header) { 172 kfree(test_data.bitmap_0001); 173 return -ENOMEM; 174 } 175 return 0; 176 } 177 module_init(test_sysctl_init); 178 179 static void __exit test_sysctl_exit(void) 180 { 181 kfree(test_data.bitmap_0001); 182 if (test_sysctl_header) 183 unregister_sysctl_table(test_sysctl_header); 184 } 185 186 module_exit(test_sysctl_exit); 187 188 MODULE_AUTHOR("Luis R. Rodriguez <mcgrof@kernel.org>"); 189 MODULE_LICENSE("GPL"); 190