diff options
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r-- | kernel/sysctl.c | 591 |
1 files changed, 79 insertions, 512 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index e0ac6cd79fcf..3ca1d5ff0319 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -90,12 +90,6 @@ extern char modprobe_path[]; | |||
90 | #ifdef CONFIG_CHR_DEV_SG | 90 | #ifdef CONFIG_CHR_DEV_SG |
91 | extern int sg_big_buff; | 91 | extern int sg_big_buff; |
92 | #endif | 92 | #endif |
93 | #ifdef CONFIG_SYSVIPC | ||
94 | static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp, | ||
95 | void __user *buffer, size_t *lenp, loff_t *ppos); | ||
96 | static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, | ||
97 | void __user *buffer, size_t *lenp, loff_t *ppos); | ||
98 | #endif | ||
99 | 93 | ||
100 | #ifdef __sparc__ | 94 | #ifdef __sparc__ |
101 | extern char reboot_command []; | 95 | extern char reboot_command []; |
@@ -135,18 +129,6 @@ static int parse_table(int __user *, int, void __user *, size_t __user *, | |||
135 | void __user *, size_t, ctl_table *); | 129 | void __user *, size_t, ctl_table *); |
136 | #endif | 130 | #endif |
137 | 131 | ||
138 | static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, | ||
139 | void __user *buffer, size_t *lenp, loff_t *ppos); | ||
140 | |||
141 | static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen, | ||
142 | void __user *oldval, size_t __user *oldlenp, | ||
143 | void __user *newval, size_t newlen); | ||
144 | |||
145 | #ifdef CONFIG_SYSVIPC | ||
146 | static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, | ||
147 | void __user *oldval, size_t __user *oldlenp, | ||
148 | void __user *newval, size_t newlen); | ||
149 | #endif | ||
150 | 132 | ||
151 | #ifdef CONFIG_PROC_SYSCTL | 133 | #ifdef CONFIG_PROC_SYSCTL |
152 | static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, | 134 | static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, |
@@ -177,60 +159,6 @@ int sysctl_legacy_va_layout; | |||
177 | #endif | 159 | #endif |
178 | 160 | ||
179 | 161 | ||
180 | static void *get_uts(ctl_table *table, int write) | ||
181 | { | ||
182 | char *which = table->data; | ||
183 | #ifdef CONFIG_UTS_NS | ||
184 | struct uts_namespace *uts_ns = current->nsproxy->uts_ns; | ||
185 | which = (which - (char *)&init_uts_ns) + (char *)uts_ns; | ||
186 | #endif | ||
187 | if (!write) | ||
188 | down_read(&uts_sem); | ||
189 | else | ||
190 | down_write(&uts_sem); | ||
191 | return which; | ||
192 | } | ||
193 | |||
194 | static void put_uts(ctl_table *table, int write, void *which) | ||
195 | { | ||
196 | if (!write) | ||
197 | up_read(&uts_sem); | ||
198 | else | ||
199 | up_write(&uts_sem); | ||
200 | } | ||
201 | |||
202 | #ifdef CONFIG_SYSVIPC | ||
203 | static void *get_ipc(ctl_table *table, int write) | ||
204 | { | ||
205 | char *which = table->data; | ||
206 | struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; | ||
207 | which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns; | ||
208 | return which; | ||
209 | } | ||
210 | #else | ||
211 | #define get_ipc(T,W) ((T)->data) | ||
212 | #endif | ||
213 | |||
214 | /* /proc declarations: */ | ||
215 | |||
216 | #ifdef CONFIG_PROC_SYSCTL | ||
217 | |||
218 | static ssize_t proc_readsys(struct file *, char __user *, size_t, loff_t *); | ||
219 | static ssize_t proc_writesys(struct file *, const char __user *, size_t, loff_t *); | ||
220 | static int proc_opensys(struct inode *, struct file *); | ||
221 | |||
222 | const struct file_operations proc_sys_file_operations = { | ||
223 | .open = proc_opensys, | ||
224 | .read = proc_readsys, | ||
225 | .write = proc_writesys, | ||
226 | }; | ||
227 | |||
228 | extern struct proc_dir_entry *proc_sys_root; | ||
229 | |||
230 | static void register_proc_table(ctl_table *, struct proc_dir_entry *, void *); | ||
231 | static void unregister_proc_table(ctl_table *, struct proc_dir_entry *); | ||
232 | #endif | ||
233 | |||
234 | /* The default sysctl tables: */ | 162 | /* The default sysctl tables: */ |
235 | 163 | ||
236 | static ctl_table root_table[] = { | 164 | static ctl_table root_table[] = { |
@@ -278,51 +206,6 @@ static ctl_table root_table[] = { | |||
278 | 206 | ||
279 | static ctl_table kern_table[] = { | 207 | static ctl_table kern_table[] = { |
280 | { | 208 | { |
281 | .ctl_name = KERN_OSTYPE, | ||
282 | .procname = "ostype", | ||
283 | .data = init_uts_ns.name.sysname, | ||
284 | .maxlen = sizeof(init_uts_ns.name.sysname), | ||
285 | .mode = 0444, | ||
286 | .proc_handler = &proc_do_uts_string, | ||
287 | .strategy = &sysctl_uts_string, | ||
288 | }, | ||
289 | { | ||
290 | .ctl_name = KERN_OSRELEASE, | ||
291 | .procname = "osrelease", | ||
292 | .data = init_uts_ns.name.release, | ||
293 | .maxlen = sizeof(init_uts_ns.name.release), | ||
294 | .mode = 0444, | ||
295 | .proc_handler = &proc_do_uts_string, | ||
296 | .strategy = &sysctl_uts_string, | ||
297 | }, | ||
298 | { | ||
299 | .ctl_name = KERN_VERSION, | ||
300 | .procname = "version", | ||
301 | .data = init_uts_ns.name.version, | ||
302 | .maxlen = sizeof(init_uts_ns.name.version), | ||
303 | .mode = 0444, | ||
304 | .proc_handler = &proc_do_uts_string, | ||
305 | .strategy = &sysctl_uts_string, | ||
306 | }, | ||
307 | { | ||
308 | .ctl_name = KERN_NODENAME, | ||
309 | .procname = "hostname", | ||
310 | .data = init_uts_ns.name.nodename, | ||
311 | .maxlen = sizeof(init_uts_ns.name.nodename), | ||
312 | .mode = 0644, | ||
313 | .proc_handler = &proc_do_uts_string, | ||
314 | .strategy = &sysctl_uts_string, | ||
315 | }, | ||
316 | { | ||
317 | .ctl_name = KERN_DOMAINNAME, | ||
318 | .procname = "domainname", | ||
319 | .data = init_uts_ns.name.domainname, | ||
320 | .maxlen = sizeof(init_uts_ns.name.domainname), | ||
321 | .mode = 0644, | ||
322 | .proc_handler = &proc_do_uts_string, | ||
323 | .strategy = &sysctl_uts_string, | ||
324 | }, | ||
325 | { | ||
326 | .ctl_name = KERN_PANIC, | 209 | .ctl_name = KERN_PANIC, |
327 | .procname = "panic", | 210 | .procname = "panic", |
328 | .data = &panic_timeout, | 211 | .data = &panic_timeout, |
@@ -478,71 +361,6 @@ static ctl_table kern_table[] = { | |||
478 | .proc_handler = &proc_dointvec, | 361 | .proc_handler = &proc_dointvec, |
479 | }, | 362 | }, |
480 | #endif | 363 | #endif |
481 | #ifdef CONFIG_SYSVIPC | ||
482 | { | ||
483 | .ctl_name = KERN_SHMMAX, | ||
484 | .procname = "shmmax", | ||
485 | .data = &init_ipc_ns.shm_ctlmax, | ||
486 | .maxlen = sizeof (init_ipc_ns.shm_ctlmax), | ||
487 | .mode = 0644, | ||
488 | .proc_handler = &proc_ipc_doulongvec_minmax, | ||
489 | .strategy = sysctl_ipc_data, | ||
490 | }, | ||
491 | { | ||
492 | .ctl_name = KERN_SHMALL, | ||
493 | .procname = "shmall", | ||
494 | .data = &init_ipc_ns.shm_ctlall, | ||
495 | .maxlen = sizeof (init_ipc_ns.shm_ctlall), | ||
496 | .mode = 0644, | ||
497 | .proc_handler = &proc_ipc_doulongvec_minmax, | ||
498 | .strategy = sysctl_ipc_data, | ||
499 | }, | ||
500 | { | ||
501 | .ctl_name = KERN_SHMMNI, | ||
502 | .procname = "shmmni", | ||
503 | .data = &init_ipc_ns.shm_ctlmni, | ||
504 | .maxlen = sizeof (init_ipc_ns.shm_ctlmni), | ||
505 | .mode = 0644, | ||
506 | .proc_handler = &proc_ipc_dointvec, | ||
507 | .strategy = sysctl_ipc_data, | ||
508 | }, | ||
509 | { | ||
510 | .ctl_name = KERN_MSGMAX, | ||
511 | .procname = "msgmax", | ||
512 | .data = &init_ipc_ns.msg_ctlmax, | ||
513 | .maxlen = sizeof (init_ipc_ns.msg_ctlmax), | ||
514 | .mode = 0644, | ||
515 | .proc_handler = &proc_ipc_dointvec, | ||
516 | .strategy = sysctl_ipc_data, | ||
517 | }, | ||
518 | { | ||
519 | .ctl_name = KERN_MSGMNI, | ||
520 | .procname = "msgmni", | ||
521 | .data = &init_ipc_ns.msg_ctlmni, | ||
522 | .maxlen = sizeof (init_ipc_ns.msg_ctlmni), | ||
523 | .mode = 0644, | ||
524 | .proc_handler = &proc_ipc_dointvec, | ||
525 | .strategy = sysctl_ipc_data, | ||
526 | }, | ||
527 | { | ||
528 | .ctl_name = KERN_MSGMNB, | ||
529 | .procname = "msgmnb", | ||
530 | .data = &init_ipc_ns.msg_ctlmnb, | ||
531 | .maxlen = sizeof (init_ipc_ns.msg_ctlmnb), | ||
532 | .mode = 0644, | ||
533 | .proc_handler = &proc_ipc_dointvec, | ||
534 | .strategy = sysctl_ipc_data, | ||
535 | }, | ||
536 | { | ||
537 | .ctl_name = KERN_SEM, | ||
538 | .procname = "sem", | ||
539 | .data = &init_ipc_ns.sem_ctls, | ||
540 | .maxlen = 4*sizeof (int), | ||
541 | .mode = 0644, | ||
542 | .proc_handler = &proc_ipc_dointvec, | ||
543 | .strategy = sysctl_ipc_data, | ||
544 | }, | ||
545 | #endif | ||
546 | #ifdef CONFIG_MAGIC_SYSRQ | 364 | #ifdef CONFIG_MAGIC_SYSRQ |
547 | { | 365 | { |
548 | .ctl_name = KERN_SYSRQ, | 366 | .ctl_name = KERN_SYSRQ, |
@@ -1043,6 +861,12 @@ static ctl_table vm_table[] = { | |||
1043 | { .ctl_name = 0 } | 861 | { .ctl_name = 0 } |
1044 | }; | 862 | }; |
1045 | 863 | ||
864 | #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) | ||
865 | static ctl_table binfmt_misc_table[] = { | ||
866 | { .ctl_name = 0 } | ||
867 | }; | ||
868 | #endif | ||
869 | |||
1046 | static ctl_table fs_table[] = { | 870 | static ctl_table fs_table[] = { |
1047 | { | 871 | { |
1048 | .ctl_name = FS_NRINODE, | 872 | .ctl_name = FS_NRINODE, |
@@ -1166,6 +990,14 @@ static ctl_table fs_table[] = { | |||
1166 | .mode = 0644, | 990 | .mode = 0644, |
1167 | .proc_handler = &proc_dointvec, | 991 | .proc_handler = &proc_dointvec, |
1168 | }, | 992 | }, |
993 | #if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) | ||
994 | { | ||
995 | .ctl_name = CTL_UNNUMBERED, | ||
996 | .procname = "binfmt_misc", | ||
997 | .mode = 0555, | ||
998 | .child = binfmt_misc_table, | ||
999 | }, | ||
1000 | #endif | ||
1169 | { .ctl_name = 0 } | 1001 | { .ctl_name = 0 } |
1170 | }; | 1002 | }; |
1171 | 1003 | ||
@@ -1177,8 +1009,6 @@ static ctl_table dev_table[] = { | |||
1177 | { .ctl_name = 0 } | 1009 | { .ctl_name = 0 } |
1178 | }; | 1010 | }; |
1179 | 1011 | ||
1180 | extern void init_irq_proc (void); | ||
1181 | |||
1182 | static DEFINE_SPINLOCK(sysctl_lock); | 1012 | static DEFINE_SPINLOCK(sysctl_lock); |
1183 | 1013 | ||
1184 | /* called under sysctl_lock */ | 1014 | /* called under sysctl_lock */ |
@@ -1220,19 +1050,47 @@ static void start_unregistering(struct ctl_table_header *p) | |||
1220 | list_del_init(&p->ctl_entry); | 1050 | list_del_init(&p->ctl_entry); |
1221 | } | 1051 | } |
1222 | 1052 | ||
1223 | void __init sysctl_init(void) | 1053 | void sysctl_head_finish(struct ctl_table_header *head) |
1224 | { | 1054 | { |
1225 | #ifdef CONFIG_PROC_SYSCTL | 1055 | if (!head) |
1226 | register_proc_table(root_table, proc_sys_root, &root_table_header); | 1056 | return; |
1227 | init_irq_proc(); | 1057 | spin_lock(&sysctl_lock); |
1228 | #endif | 1058 | unuse_table(head); |
1059 | spin_unlock(&sysctl_lock); | ||
1060 | } | ||
1061 | |||
1062 | struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev) | ||
1063 | { | ||
1064 | struct ctl_table_header *head; | ||
1065 | struct list_head *tmp; | ||
1066 | spin_lock(&sysctl_lock); | ||
1067 | if (prev) { | ||
1068 | tmp = &prev->ctl_entry; | ||
1069 | unuse_table(prev); | ||
1070 | goto next; | ||
1071 | } | ||
1072 | tmp = &root_table_header.ctl_entry; | ||
1073 | for (;;) { | ||
1074 | head = list_entry(tmp, struct ctl_table_header, ctl_entry); | ||
1075 | |||
1076 | if (!use_table(head)) | ||
1077 | goto next; | ||
1078 | spin_unlock(&sysctl_lock); | ||
1079 | return head; | ||
1080 | next: | ||
1081 | tmp = tmp->next; | ||
1082 | if (tmp == &root_table_header.ctl_entry) | ||
1083 | break; | ||
1084 | } | ||
1085 | spin_unlock(&sysctl_lock); | ||
1086 | return NULL; | ||
1229 | } | 1087 | } |
1230 | 1088 | ||
1231 | #ifdef CONFIG_SYSCTL_SYSCALL | 1089 | #ifdef CONFIG_SYSCTL_SYSCALL |
1232 | int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, | 1090 | int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, |
1233 | void __user *newval, size_t newlen) | 1091 | void __user *newval, size_t newlen) |
1234 | { | 1092 | { |
1235 | struct list_head *tmp; | 1093 | struct ctl_table_header *head; |
1236 | int error = -ENOTDIR; | 1094 | int error = -ENOTDIR; |
1237 | 1095 | ||
1238 | if (nlen <= 0 || nlen >= CTL_MAXNAME) | 1096 | if (nlen <= 0 || nlen >= CTL_MAXNAME) |
@@ -1242,26 +1100,16 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol | |||
1242 | if (!oldlenp || get_user(old_len, oldlenp)) | 1100 | if (!oldlenp || get_user(old_len, oldlenp)) |
1243 | return -EFAULT; | 1101 | return -EFAULT; |
1244 | } | 1102 | } |
1245 | spin_lock(&sysctl_lock); | ||
1246 | tmp = &root_table_header.ctl_entry; | ||
1247 | do { | ||
1248 | struct ctl_table_header *head = | ||
1249 | list_entry(tmp, struct ctl_table_header, ctl_entry); | ||
1250 | |||
1251 | if (!use_table(head)) | ||
1252 | continue; | ||
1253 | |||
1254 | spin_unlock(&sysctl_lock); | ||
1255 | 1103 | ||
1104 | for (head = sysctl_head_next(NULL); head; | ||
1105 | head = sysctl_head_next(head)) { | ||
1256 | error = parse_table(name, nlen, oldval, oldlenp, | 1106 | error = parse_table(name, nlen, oldval, oldlenp, |
1257 | newval, newlen, head->ctl_table); | 1107 | newval, newlen, head->ctl_table); |
1258 | 1108 | if (error != -ENOTDIR) { | |
1259 | spin_lock(&sysctl_lock); | 1109 | sysctl_head_finish(head); |
1260 | unuse_table(head); | ||
1261 | if (error != -ENOTDIR) | ||
1262 | break; | 1110 | break; |
1263 | } while ((tmp = tmp->next) != &root_table_header.ctl_entry); | 1111 | } |
1264 | spin_unlock(&sysctl_lock); | 1112 | } |
1265 | return error; | 1113 | return error; |
1266 | } | 1114 | } |
1267 | 1115 | ||
@@ -1282,7 +1130,7 @@ asmlinkage long sys_sysctl(struct __sysctl_args __user *args) | |||
1282 | #endif /* CONFIG_SYSCTL_SYSCALL */ | 1130 | #endif /* CONFIG_SYSCTL_SYSCALL */ |
1283 | 1131 | ||
1284 | /* | 1132 | /* |
1285 | * ctl_perm does NOT grant the superuser all rights automatically, because | 1133 | * sysctl_perm does NOT grant the superuser all rights automatically, because |
1286 | * some sysctl variables are readonly even to root. | 1134 | * some sysctl variables are readonly even to root. |
1287 | */ | 1135 | */ |
1288 | 1136 | ||
@@ -1297,7 +1145,7 @@ static int test_perm(int mode, int op) | |||
1297 | return -EACCES; | 1145 | return -EACCES; |
1298 | } | 1146 | } |
1299 | 1147 | ||
1300 | static inline int ctl_perm(ctl_table *table, int op) | 1148 | int sysctl_perm(ctl_table *table, int op) |
1301 | { | 1149 | { |
1302 | int error; | 1150 | int error; |
1303 | error = security_sysctl(table, op); | 1151 | error = security_sysctl(table, op); |
@@ -1321,19 +1169,11 @@ repeat: | |||
1321 | for ( ; table->ctl_name || table->procname; table++) { | 1169 | for ( ; table->ctl_name || table->procname; table++) { |
1322 | if (!table->ctl_name) | 1170 | if (!table->ctl_name) |
1323 | continue; | 1171 | continue; |
1324 | if (n == table->ctl_name || table->ctl_name == CTL_ANY) { | 1172 | if (n == table->ctl_name) { |
1325 | int error; | 1173 | int error; |
1326 | if (table->child) { | 1174 | if (table->child) { |
1327 | if (ctl_perm(table, 001)) | 1175 | if (sysctl_perm(table, 001)) |
1328 | return -EPERM; | 1176 | return -EPERM; |
1329 | if (table->strategy) { | ||
1330 | error = table->strategy( | ||
1331 | table, name, nlen, | ||
1332 | oldval, oldlenp, | ||
1333 | newval, newlen); | ||
1334 | if (error) | ||
1335 | return error; | ||
1336 | } | ||
1337 | name++; | 1177 | name++; |
1338 | nlen--; | 1178 | nlen--; |
1339 | table = table->child; | 1179 | table = table->child; |
@@ -1361,7 +1201,7 @@ int do_sysctl_strategy (ctl_table *table, | |||
1361 | op |= 004; | 1201 | op |= 004; |
1362 | if (newval) | 1202 | if (newval) |
1363 | op |= 002; | 1203 | op |= 002; |
1364 | if (ctl_perm(table, op)) | 1204 | if (sysctl_perm(table, op)) |
1365 | return -EPERM; | 1205 | return -EPERM; |
1366 | 1206 | ||
1367 | if (table->strategy) { | 1207 | if (table->strategy) { |
@@ -1400,10 +1240,26 @@ int do_sysctl_strategy (ctl_table *table, | |||
1400 | } | 1240 | } |
1401 | #endif /* CONFIG_SYSCTL_SYSCALL */ | 1241 | #endif /* CONFIG_SYSCTL_SYSCALL */ |
1402 | 1242 | ||
1243 | static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table) | ||
1244 | { | ||
1245 | for (; table->ctl_name || table->procname; table++) { | ||
1246 | table->parent = parent; | ||
1247 | if (table->child) | ||
1248 | sysctl_set_parent(table, table->child); | ||
1249 | } | ||
1250 | } | ||
1251 | |||
1252 | static __init int sysctl_init(void) | ||
1253 | { | ||
1254 | sysctl_set_parent(NULL, root_table); | ||
1255 | return 0; | ||
1256 | } | ||
1257 | |||
1258 | core_initcall(sysctl_init); | ||
1259 | |||
1403 | /** | 1260 | /** |
1404 | * register_sysctl_table - register a sysctl hierarchy | 1261 | * register_sysctl_table - register a sysctl hierarchy |
1405 | * @table: the top-level table structure | 1262 | * @table: the top-level table structure |
1406 | * @insert_at_head: whether the entry should be inserted in front or at the end | ||
1407 | * | 1263 | * |
1408 | * Register a sysctl table hierarchy. @table should be a filled in ctl_table | 1264 | * Register a sysctl table hierarchy. @table should be a filled in ctl_table |
1409 | * array. An entry with a ctl_name of 0 terminates the table. | 1265 | * array. An entry with a ctl_name of 0 terminates the table. |
@@ -1469,8 +1325,7 @@ int do_sysctl_strategy (ctl_table *table, | |||
1469 | * This routine returns %NULL on a failure to register, and a pointer | 1325 | * This routine returns %NULL on a failure to register, and a pointer |
1470 | * to the table header on success. | 1326 | * to the table header on success. |
1471 | */ | 1327 | */ |
1472 | struct ctl_table_header *register_sysctl_table(ctl_table * table, | 1328 | struct ctl_table_header *register_sysctl_table(ctl_table * table) |
1473 | int insert_at_head) | ||
1474 | { | 1329 | { |
1475 | struct ctl_table_header *tmp; | 1330 | struct ctl_table_header *tmp; |
1476 | tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL); | 1331 | tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL); |
@@ -1480,15 +1335,10 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table, | |||
1480 | INIT_LIST_HEAD(&tmp->ctl_entry); | 1335 | INIT_LIST_HEAD(&tmp->ctl_entry); |
1481 | tmp->used = 0; | 1336 | tmp->used = 0; |
1482 | tmp->unregistering = NULL; | 1337 | tmp->unregistering = NULL; |
1338 | sysctl_set_parent(NULL, table); | ||
1483 | spin_lock(&sysctl_lock); | 1339 | spin_lock(&sysctl_lock); |
1484 | if (insert_at_head) | 1340 | list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); |
1485 | list_add(&tmp->ctl_entry, &root_table_header.ctl_entry); | ||
1486 | else | ||
1487 | list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); | ||
1488 | spin_unlock(&sysctl_lock); | 1341 | spin_unlock(&sysctl_lock); |
1489 | #ifdef CONFIG_PROC_SYSCTL | ||
1490 | register_proc_table(table, proc_sys_root, tmp); | ||
1491 | #endif | ||
1492 | return tmp; | 1342 | return tmp; |
1493 | } | 1343 | } |
1494 | 1344 | ||
@@ -1504,9 +1354,6 @@ void unregister_sysctl_table(struct ctl_table_header * header) | |||
1504 | might_sleep(); | 1354 | might_sleep(); |
1505 | spin_lock(&sysctl_lock); | 1355 | spin_lock(&sysctl_lock); |
1506 | start_unregistering(header); | 1356 | start_unregistering(header); |
1507 | #ifdef CONFIG_PROC_SYSCTL | ||
1508 | unregister_proc_table(header->ctl_table, proc_sys_root); | ||
1509 | #endif | ||
1510 | spin_unlock(&sysctl_lock); | 1357 | spin_unlock(&sysctl_lock); |
1511 | kfree(header); | 1358 | kfree(header); |
1512 | } | 1359 | } |
@@ -1530,155 +1377,6 @@ void unregister_sysctl_table(struct ctl_table_header * table) | |||
1530 | 1377 | ||
1531 | #ifdef CONFIG_PROC_SYSCTL | 1378 | #ifdef CONFIG_PROC_SYSCTL |
1532 | 1379 | ||
1533 | /* Scan the sysctl entries in table and add them all into /proc */ | ||
1534 | static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set) | ||
1535 | { | ||
1536 | struct proc_dir_entry *de; | ||
1537 | int len; | ||
1538 | mode_t mode; | ||
1539 | |||
1540 | for (; table->ctl_name || table->procname; table++) { | ||
1541 | /* Can't do anything without a proc name. */ | ||
1542 | if (!table->procname) | ||
1543 | continue; | ||
1544 | /* Maybe we can't do anything with it... */ | ||
1545 | if (!table->proc_handler && !table->child) { | ||
1546 | printk(KERN_WARNING "SYSCTL: Can't register %s\n", | ||
1547 | table->procname); | ||
1548 | continue; | ||
1549 | } | ||
1550 | |||
1551 | len = strlen(table->procname); | ||
1552 | mode = table->mode; | ||
1553 | |||
1554 | de = NULL; | ||
1555 | if (table->proc_handler) | ||
1556 | mode |= S_IFREG; | ||
1557 | else { | ||
1558 | mode |= S_IFDIR; | ||
1559 | for (de = root->subdir; de; de = de->next) { | ||
1560 | if (proc_match(len, table->procname, de)) | ||
1561 | break; | ||
1562 | } | ||
1563 | /* If the subdir exists already, de is non-NULL */ | ||
1564 | } | ||
1565 | |||
1566 | if (!de) { | ||
1567 | de = create_proc_entry(table->procname, mode, root); | ||
1568 | if (!de) | ||
1569 | continue; | ||
1570 | de->set = set; | ||
1571 | de->data = (void *) table; | ||
1572 | if (table->proc_handler) | ||
1573 | de->proc_fops = &proc_sys_file_operations; | ||
1574 | } | ||
1575 | table->de = de; | ||
1576 | if (de->mode & S_IFDIR) | ||
1577 | register_proc_table(table->child, de, set); | ||
1578 | } | ||
1579 | } | ||
1580 | |||
1581 | /* | ||
1582 | * Unregister a /proc sysctl table and any subdirectories. | ||
1583 | */ | ||
1584 | static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root) | ||
1585 | { | ||
1586 | struct proc_dir_entry *de; | ||
1587 | for (; table->ctl_name || table->procname; table++) { | ||
1588 | if (!(de = table->de)) | ||
1589 | continue; | ||
1590 | if (de->mode & S_IFDIR) { | ||
1591 | if (!table->child) { | ||
1592 | printk (KERN_ALERT "Help - malformed sysctl tree on free\n"); | ||
1593 | continue; | ||
1594 | } | ||
1595 | unregister_proc_table(table->child, de); | ||
1596 | |||
1597 | /* Don't unregister directories which still have entries.. */ | ||
1598 | if (de->subdir) | ||
1599 | continue; | ||
1600 | } | ||
1601 | |||
1602 | /* | ||
1603 | * In any case, mark the entry as goner; we'll keep it | ||
1604 | * around if it's busy, but we'll know to do nothing with | ||
1605 | * its fields. We are under sysctl_lock here. | ||
1606 | */ | ||
1607 | de->data = NULL; | ||
1608 | |||
1609 | /* Don't unregister proc entries that are still being used.. */ | ||
1610 | if (atomic_read(&de->count)) | ||
1611 | continue; | ||
1612 | |||
1613 | table->de = NULL; | ||
1614 | remove_proc_entry(table->procname, root); | ||
1615 | } | ||
1616 | } | ||
1617 | |||
1618 | static ssize_t do_rw_proc(int write, struct file * file, char __user * buf, | ||
1619 | size_t count, loff_t *ppos) | ||
1620 | { | ||
1621 | int op; | ||
1622 | struct proc_dir_entry *de = PDE(file->f_path.dentry->d_inode); | ||
1623 | struct ctl_table *table; | ||
1624 | size_t res; | ||
1625 | ssize_t error = -ENOTDIR; | ||
1626 | |||
1627 | spin_lock(&sysctl_lock); | ||
1628 | if (de && de->data && use_table(de->set)) { | ||
1629 | /* | ||
1630 | * at that point we know that sysctl was not unregistered | ||
1631 | * and won't be until we finish | ||
1632 | */ | ||
1633 | spin_unlock(&sysctl_lock); | ||
1634 | table = (struct ctl_table *) de->data; | ||
1635 | if (!table || !table->proc_handler) | ||
1636 | goto out; | ||
1637 | error = -EPERM; | ||
1638 | op = (write ? 002 : 004); | ||
1639 | if (ctl_perm(table, op)) | ||
1640 | goto out; | ||
1641 | |||
1642 | /* careful: calling conventions are nasty here */ | ||
1643 | res = count; | ||
1644 | error = (*table->proc_handler)(table, write, file, | ||
1645 | buf, &res, ppos); | ||
1646 | if (!error) | ||
1647 | error = res; | ||
1648 | out: | ||
1649 | spin_lock(&sysctl_lock); | ||
1650 | unuse_table(de->set); | ||
1651 | } | ||
1652 | spin_unlock(&sysctl_lock); | ||
1653 | return error; | ||
1654 | } | ||
1655 | |||
1656 | static int proc_opensys(struct inode *inode, struct file *file) | ||
1657 | { | ||
1658 | if (file->f_mode & FMODE_WRITE) { | ||
1659 | /* | ||
1660 | * sysctl entries that are not writable, | ||
1661 | * are _NOT_ writable, capabilities or not. | ||
1662 | */ | ||
1663 | if (!(inode->i_mode & S_IWUSR)) | ||
1664 | return -EPERM; | ||
1665 | } | ||
1666 | |||
1667 | return 0; | ||
1668 | } | ||
1669 | |||
1670 | static ssize_t proc_readsys(struct file * file, char __user * buf, | ||
1671 | size_t count, loff_t *ppos) | ||
1672 | { | ||
1673 | return do_rw_proc(0, file, buf, count, ppos); | ||
1674 | } | ||
1675 | |||
1676 | static ssize_t proc_writesys(struct file * file, const char __user * buf, | ||
1677 | size_t count, loff_t *ppos) | ||
1678 | { | ||
1679 | return do_rw_proc(1, file, (char __user *) buf, count, ppos); | ||
1680 | } | ||
1681 | |||
1682 | static int _proc_do_string(void* data, int maxlen, int write, | 1380 | static int _proc_do_string(void* data, int maxlen, int write, |
1683 | struct file *filp, void __user *buffer, | 1381 | struct file *filp, void __user *buffer, |
1684 | size_t *lenp, loff_t *ppos) | 1382 | size_t *lenp, loff_t *ppos) |
@@ -1762,21 +1460,6 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, | |||
1762 | buffer, lenp, ppos); | 1460 | buffer, lenp, ppos); |
1763 | } | 1461 | } |
1764 | 1462 | ||
1765 | /* | ||
1766 | * Special case of dostring for the UTS structure. This has locks | ||
1767 | * to observe. Should this be in kernel/sys.c ???? | ||
1768 | */ | ||
1769 | |||
1770 | static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, | ||
1771 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
1772 | { | ||
1773 | int r; | ||
1774 | void *which; | ||
1775 | which = get_uts(table, write); | ||
1776 | r = _proc_do_string(which, table->maxlen,write,filp,buffer,lenp, ppos); | ||
1777 | put_uts(table, write, which); | ||
1778 | return r; | ||
1779 | } | ||
1780 | 1463 | ||
1781 | static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, | 1464 | static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp, |
1782 | int *valp, | 1465 | int *valp, |
@@ -2362,27 +2045,6 @@ int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp, | |||
2362 | do_proc_dointvec_ms_jiffies_conv, NULL); | 2045 | do_proc_dointvec_ms_jiffies_conv, NULL); |
2363 | } | 2046 | } |
2364 | 2047 | ||
2365 | #ifdef CONFIG_SYSVIPC | ||
2366 | static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp, | ||
2367 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2368 | { | ||
2369 | void *which; | ||
2370 | which = get_ipc(table, write); | ||
2371 | return __do_proc_dointvec(which, table, write, filp, buffer, | ||
2372 | lenp, ppos, NULL, NULL); | ||
2373 | } | ||
2374 | |||
2375 | static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, | ||
2376 | struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2377 | { | ||
2378 | void *which; | ||
2379 | which = get_ipc(table, write); | ||
2380 | return __do_proc_doulongvec_minmax(which, table, write, filp, buffer, | ||
2381 | lenp, ppos, 1l, 1l); | ||
2382 | } | ||
2383 | |||
2384 | #endif | ||
2385 | |||
2386 | static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, | 2048 | static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp, |
2387 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2049 | void __user *buffer, size_t *lenp, loff_t *ppos) |
2388 | { | 2050 | { |
@@ -2413,31 +2075,6 @@ int proc_dostring(ctl_table *table, int write, struct file *filp, | |||
2413 | return -ENOSYS; | 2075 | return -ENOSYS; |
2414 | } | 2076 | } |
2415 | 2077 | ||
2416 | static int proc_do_uts_string(ctl_table *table, int write, struct file *filp, | ||
2417 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2418 | { | ||
2419 | return -ENOSYS; | ||
2420 | } | ||
2421 | |||
2422 | #ifdef CONFIG_SYSVIPC | ||
2423 | static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp, | ||
2424 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2425 | { | ||
2426 | return -ENOSYS; | ||
2427 | } | ||
2428 | static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp, | ||
2429 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
2430 | { | ||
2431 | return -ENOSYS; | ||
2432 | } | ||
2433 | static int proc_ipc_doulongvec_minmax(ctl_table *table, int write, | ||
2434 | struct file *filp, void __user *buffer, | ||
2435 | size_t *lenp, loff_t *ppos) | ||
2436 | { | ||
2437 | return -ENOSYS; | ||
2438 | } | ||
2439 | #endif | ||
2440 | |||
2441 | int proc_dointvec(ctl_table *table, int write, struct file *filp, | 2078 | int proc_dointvec(ctl_table *table, int write, struct file *filp, |
2442 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2079 | void __user *buffer, size_t *lenp, loff_t *ppos) |
2443 | { | 2080 | { |
@@ -2648,62 +2285,6 @@ int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen, | |||
2648 | } | 2285 | } |
2649 | 2286 | ||
2650 | 2287 | ||
2651 | /* The generic string strategy routine: */ | ||
2652 | static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen, | ||
2653 | void __user *oldval, size_t __user *oldlenp, | ||
2654 | void __user *newval, size_t newlen) | ||
2655 | { | ||
2656 | struct ctl_table uts_table; | ||
2657 | int r, write; | ||
2658 | write = newval && newlen; | ||
2659 | memcpy(&uts_table, table, sizeof(uts_table)); | ||
2660 | uts_table.data = get_uts(table, write); | ||
2661 | r = sysctl_string(&uts_table, name, nlen, | ||
2662 | oldval, oldlenp, newval, newlen); | ||
2663 | put_uts(table, write, uts_table.data); | ||
2664 | return r; | ||
2665 | } | ||
2666 | |||
2667 | #ifdef CONFIG_SYSVIPC | ||
2668 | /* The generic sysctl ipc data routine. */ | ||
2669 | static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, | ||
2670 | void __user *oldval, size_t __user *oldlenp, | ||
2671 | void __user *newval, size_t newlen) | ||
2672 | { | ||
2673 | size_t len; | ||
2674 | void *data; | ||
2675 | |||
2676 | /* Get out of I don't have a variable */ | ||
2677 | if (!table->data || !table->maxlen) | ||
2678 | return -ENOTDIR; | ||
2679 | |||
2680 | data = get_ipc(table, 1); | ||
2681 | if (!data) | ||
2682 | return -ENOTDIR; | ||
2683 | |||
2684 | if (oldval && oldlenp) { | ||
2685 | if (get_user(len, oldlenp)) | ||
2686 | return -EFAULT; | ||
2687 | if (len) { | ||
2688 | if (len > table->maxlen) | ||
2689 | len = table->maxlen; | ||
2690 | if (copy_to_user(oldval, data, len)) | ||
2691 | return -EFAULT; | ||
2692 | if (put_user(len, oldlenp)) | ||
2693 | return -EFAULT; | ||
2694 | } | ||
2695 | } | ||
2696 | |||
2697 | if (newval && newlen) { | ||
2698 | if (newlen > table->maxlen) | ||
2699 | newlen = table->maxlen; | ||
2700 | |||
2701 | if (copy_from_user(data, newval, newlen)) | ||
2702 | return -EFAULT; | ||
2703 | } | ||
2704 | return 1; | ||
2705 | } | ||
2706 | #endif | ||
2707 | 2288 | ||
2708 | #else /* CONFIG_SYSCTL_SYSCALL */ | 2289 | #else /* CONFIG_SYSCTL_SYSCALL */ |
2709 | 2290 | ||
@@ -2769,20 +2350,6 @@ int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen, | |||
2769 | return -ENOSYS; | 2350 | return -ENOSYS; |
2770 | } | 2351 | } |
2771 | 2352 | ||
2772 | static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen, | ||
2773 | void __user *oldval, size_t __user *oldlenp, | ||
2774 | void __user *newval, size_t newlen) | ||
2775 | { | ||
2776 | return -ENOSYS; | ||
2777 | } | ||
2778 | #ifdef CONFIG_SYSVIPC | ||
2779 | static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen, | ||
2780 | void __user *oldval, size_t __user *oldlenp, | ||
2781 | void __user *newval, size_t newlen) | ||
2782 | { | ||
2783 | return -ENOSYS; | ||
2784 | } | ||
2785 | #endif | ||
2786 | #endif /* CONFIG_SYSCTL_SYSCALL */ | 2353 | #endif /* CONFIG_SYSCTL_SYSCALL */ |
2787 | 2354 | ||
2788 | /* | 2355 | /* |