~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/kernel/sysctl.c

Version: ~ [ 0.6-2.3.46 ] ~
Architecture: ~ [ um ] ~

** Warning: Cannot open xref database.

1 /* 2 * sysctl.c: General linux system control interface 3 * 4 * Begun 24 March 1995, Stephen Tweedie 5 * Added /proc support, Dec 1995 6 * Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas. 7 * Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver. 8 * Added kernel/java-{interpreter,appletviewer}, 96/5/10, Mike Shaver. 9 * Dynamic registration fixes, Stephen Tweedie. 10 * Added kswapd-interval, ctrl-alt-del, printk stuff, 1/8/97, Chris Horn. 11 * Made sysctl support optional via CONFIG_SYSCTL, 1/10/97, Chris 12 * Horn. 13 * Added proc_doulongvec_ms_jiffies_minmax, 09/08/99, Carlos H. Bauer. 14 * Added proc_doulongvec_minmax, 09/08/99, Carlos H. Bauer. 15 */ 16 17 #include <linux/config.h> 18 #include <linux/malloc.h> 19 #include <linux/sysctl.h> 20 #include <linux/swapctl.h> 21 #include <linux/proc_fs.h> 22 #include <linux/ctype.h> 23 #include <linux/utsname.h> 24 #include <linux/capability.h> 25 #include <linux/smp_lock.h> 26 #include <linux/init.h> 27 #include <linux/sysrq.h> 28 #include <linux/highuid.h> 29 30 #include <asm/uaccess.h> 31 32 #ifdef CONFIG_ROOT_NFS 33 #include <linux/nfs_fs.h> 34 #endif 35 36 #if defined(CONFIG_SYSCTL) 37 38 /* External variables not in a header file. */ 39 extern int panic_timeout; 40 extern int console_loglevel, C_A_D; 41 extern int bdf_prm[], bdflush_min[], bdflush_max[]; 42 extern int sysctl_overcommit_memory; 43 extern int max_threads; 44 extern int nr_queued_signals, max_queued_signals; 45 46 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ 47 static int maxolduid = 65535; 48 static int minolduid = 0; 49 50 #ifdef CONFIG_KMOD 51 extern char modprobe_path[]; 52 #endif 53 #ifdef CONFIG_CHR_DEV_SG 54 extern int sg_big_buff; 55 #endif 56 #ifdef CONFIG_SYSVIPC 57 extern size_t shm_ctlmax; 58 extern int shm_ctlall; 59 extern int shm_ctlmni; 60 extern int msg_ctlmax; 61 extern int msg_ctlmnb; 62 extern int msg_ctlmni; 63 extern int sem_ctls[]; 64 #endif 65 66 #ifdef __sparc__ 67 extern char reboot_command []; 68 extern int stop_a_enabled; 69 #endif 70 #ifdef __powerpc__ 71 extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap; 72 int proc_dol2crvec(ctl_table *table, int write, struct file *filp, 73 void *buffer, size_t *lenp); 74 #endif 75 76 #ifdef CONFIG_BSD_PROCESS_ACCT 77 extern int acct_parm[]; 78 #endif 79 80 extern int pgt_cache_water[]; 81 82 static int parse_table(int *, int, void *, size_t *, void *, size_t, 83 ctl_table *, void **); 84 static int proc_doutsstring(ctl_table *table, int write, struct file *filp, 85 void *buffer, size_t *lenp); 86 87 88 static ctl_table root_table[]; 89 static struct ctl_table_header root_table_header = 90 {root_table, DNODE_SINGLE(&root_table_header)}; 91 92 static ctl_table kern_table[]; 93 static ctl_table vm_table[]; 94 #ifdef CONFIG_NET 95 extern ctl_table net_table[]; 96 #endif 97 static ctl_table proc_table[]; 98 static ctl_table fs_table[]; 99 static ctl_table debug_table[]; 100 static ctl_table dev_table[]; 101 extern ctl_table random_table[]; 102 103 104 /* /proc declarations: */ 105 106 #ifdef CONFIG_PROC_FS 107 108 static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *); 109 static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *); 110 static int proc_sys_permission(struct inode *, int); 111 112 struct file_operations proc_sys_file_operations = 113 { 114 read: proc_readsys, 115 write: proc_writesys, 116 }; 117 118 struct inode_operations proc_sys_inode_operations = 119 { 120 &proc_sys_file_operations, 121 NULL, /* create */ 122 NULL, /* lookup */ 123 NULL, /* link */ 124 NULL, /* unlink */ 125 NULL, /* symlink */ 126 NULL, /* mkdir */ 127 NULL, /* rmdir */ 128 NULL, /* mknod */ 129 NULL, /* rename */ 130 NULL, /* readlink */ 131 NULL, /* follow_link */ 132 NULL, /* truncate */ 133 proc_sys_permission, /* permission */ 134 NULL /* revalidate */ 135 }; 136 137 extern struct proc_dir_entry *proc_sys_root; 138 139 static void register_proc_table(ctl_table *, struct proc_dir_entry *); 140 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *); 141 #endif 142 extern int inodes_stat[]; 143 extern int dentry_stat[]; 144 145 /* The default sysctl tables: */ 146 147 static ctl_table root_table[] = { 148 {CTL_KERN, "kernel", NULL, 0, 0555, kern_table}, 149 {CTL_VM, "vm", NULL, 0, 0555, vm_table}, 150 #ifdef CONFIG_NET 151 {CTL_NET, "net", NULL, 0, 0555, net_table}, 152 #endif 153 {CTL_PROC, "proc", NULL, 0, 0555, proc_table}, 154 {CTL_FS, "fs", NULL, 0, 0555, fs_table}, 155 {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table}, 156 {CTL_DEV, "dev", NULL, 0, 0555, dev_table}, 157 {0} 158 }; 159 160 static ctl_table kern_table[] = { 161 {KERN_OSTYPE, "ostype", system_utsname.sysname, 64, 162 0444, NULL, &proc_doutsstring, &sysctl_string}, 163 {KERN_OSRELEASE, "osrelease", system_utsname.release, 64, 164 0444, NULL, &proc_doutsstring, &sysctl_string}, 165 {KERN_VERSION, "version", system_utsname.version, 64, 166 0444, NULL, &proc_doutsstring, &sysctl_string}, 167 {KERN_NODENAME, "hostname", system_utsname.nodename, 64, 168 0644, NULL, &proc_doutsstring, &sysctl_string}, 169 {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64, 170 0644, NULL, &proc_doutsstring, &sysctl_string}, 171 {KERN_PANIC, "panic", &panic_timeout, sizeof(int), 172 0644, NULL, &proc_dointvec}, 173 {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t), 174 0600, NULL, &proc_dointvec_bset}, 175 #ifdef CONFIG_BLK_DEV_INITRD 176 {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int), 177 0644, NULL, &proc_dointvec}, 178 #endif 179 #ifdef __sparc__ 180 {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command, 181 256, 0644, NULL, &proc_dostring, &sysctl_string }, 182 {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int), 183 0644, NULL, &proc_dointvec}, 184 #endif 185 #ifdef __powerpc__ 186 {KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int), 187 0644, NULL, &proc_dointvec}, 188 {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int), 189 0644, NULL, &proc_dointvec}, 190 {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int), 191 0644, NULL, &proc_dointvec}, 192 {KERN_PPC_L2CR, "l2cr", NULL, 0, 193 0644, NULL, &proc_dol2crvec}, 194 #endif 195 {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int), 196 0644, NULL, &proc_dointvec}, 197 {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int), 198 0644, NULL, &proc_dointvec}, 199 #ifdef CONFIG_KMOD 200 {KERN_MODPROBE, "modprobe", &modprobe_path, 256, 201 0644, NULL, &proc_dostring, &sysctl_string }, 202 #endif 203 #ifdef CONFIG_CHR_DEV_SG 204 {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int), 205 0444, NULL, &proc_dointvec}, 206 #endif 207 #ifdef CONFIG_BSD_PROCESS_ACCT 208 {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int), 209 0644, NULL, &proc_dointvec}, 210 #endif 211 {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int), 212 0444, NULL, &proc_dointvec}, 213 {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int), 214 0644, NULL, &proc_dointvec}, 215 #ifdef CONFIG_SYSVIPC 216 {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t), 217 0644, NULL, &proc_doulongvec_minmax}, 218 {KERN_SHMALL, "shmall", &shm_ctlall, sizeof (int), 219 0644, NULL, &proc_dointvec}, 220 {KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int), 221 0644, NULL, &proc_dointvec}, 222 {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int), 223 0644, NULL, &proc_dointvec}, 224 {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int), 225 0644, NULL, &proc_dointvec}, 226 {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int), 227 0644, NULL, &proc_dointvec}, 228 {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int), 229 0644, NULL, &proc_dointvec}, 230 #endif 231 #ifdef CONFIG_MAGIC_SYSRQ 232 {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int), 233 0644, NULL, &proc_dointvec}, 234 #endif 235 {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int), 236 0644, NULL, &proc_dointvec}, 237 {KERN_RANDOM, "random", NULL, 0, 0555, random_table}, 238 {KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL, 239 &proc_dointvec_minmax, &sysctl_intvec, NULL, 240 &minolduid, &maxolduid}, 241 {KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL, 242 &proc_dointvec_minmax, &sysctl_intvec, NULL, 243 &minolduid, &maxolduid}, 244 {0} 245 }; 246 247 static ctl_table vm_table[] = { 248 {VM_FREEPG, "freepages", 249 &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec}, 250 {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL, 251 &proc_dointvec_minmax, &sysctl_intvec, NULL, 252 &bdflush_min, &bdflush_max}, 253 {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory, 254 sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec}, 255 {VM_BUFFERMEM, "buffermem", 256 &buffer_mem, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec}, 257 {VM_PAGECACHE, "pagecache", 258 &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec}, 259 {VM_PAGERDAEMON, "kswapd", 260 &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec}, 261 {VM_PGT_CACHE, "pagetable_cache", 262 &pgt_cache_water, 2*sizeof(int), 0600, NULL, &proc_dointvec}, 263 {VM_PAGE_CLUSTER, "page-cluster", 264 &page_cluster, sizeof(int), 0600, NULL, &proc_dointvec}, 265 {0} 266 }; 267 268 static ctl_table proc_table[] = { 269 {0} 270 }; 271 272 static ctl_table fs_table[] = { 273 {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int), 274 0444, NULL, &proc_dointvec}, 275 {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int), 276 0444, NULL, &proc_dointvec}, 277 {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int), 278 0444, NULL, &proc_dointvec}, 279 {FS_MAXFILE, "file-max", &max_files, sizeof(int), 280 0644, NULL, &proc_dointvec}, 281 {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int), 282 0444, NULL, &proc_dointvec}, 283 {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int), 284 0644, NULL, &proc_dointvec}, 285 {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int), 286 0444, NULL, &proc_dointvec}, 287 {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int), 288 0644, NULL, &proc_dointvec}, 289 {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int), 290 0444, NULL, &proc_dointvec}, 291 {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL, 292 &proc_dointvec_minmax, &sysctl_intvec, NULL, 293 &minolduid, &maxolduid}, 294 {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL, 295 &proc_dointvec_minmax, &sysctl_intvec, NULL, 296 &minolduid, &maxolduid}, 297 {0} 298 }; 299 300 static ctl_table debug_table[] = { 301 {0} 302 }; 303 304 static ctl_table dev_table[] = { 305 {0} 306 }; 307 308 309 void __init sysctl_init(void) 310 { 311 #ifdef CONFIG_PROC_FS 312 register_proc_table(root_table, proc_sys_root); 313 #endif 314 } 315 316 317 int do_sysctl (int *name, int nlen, 318 void *oldval, size_t *oldlenp, 319 void *newval, size_t newlen) 320 { 321 int error; 322 struct ctl_table_header *tmp; 323 void *context; 324 325 if (nlen == 0 || nlen >= CTL_MAXNAME) 326 return -ENOTDIR; 327 328 if (oldval) 329 { 330 int old_len; 331 if (!oldlenp) 332 return -EFAULT; 333 if(get_user(old_len, oldlenp)) 334 return -EFAULT; 335 } 336 tmp = &root_table_header; 337 do { 338 context = NULL; 339 error = parse_table(name, nlen, oldval, oldlenp, 340 newval, newlen, tmp->ctl_table, &context); 341 if (context) 342 kfree(context); 343 if (error != -ENOTDIR) 344 return error; 345 tmp = tmp->DLIST_NEXT(ctl_entry); 346 } while (tmp != &root_table_header); 347 return -ENOTDIR; 348 } 349 350 extern asmlinkage long sys_sysctl(struct __sysctl_args *args) 351 { 352 struct __sysctl_args tmp; 353 int error; 354 355 if(copy_from_user(&tmp, args, sizeof(tmp))) 356 return -EFAULT; 357 358 lock_kernel(); 359 error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, 360 tmp.newval, tmp.newlen); 361 unlock_kernel(); 362 return error; 363 } 364 365 /* ctl_perm does NOT grant the superuser all rights automatically, because 366 some sysctl variables are readonly even to root. */ 367 368 static int test_perm(int mode, int op) 369 { 370 if (!current->euid) 371 mode >>= 6; 372 else if (in_egroup_p(0)) 373 mode >>= 3; 374 if ((mode & op & 0007) == op) 375 return 0; 376 return -EACCES; 377 } 378 379 static inline int ctl_perm(ctl_table *table, int op) 380 { 381 return test_perm(table->mode, op); 382 } 383 384 static int parse_table(int *name, int nlen, 385 void *oldval, size_t *oldlenp, 386 void *newval, size_t newlen, 387 ctl_table *table, void **context) 388 { 389 int error; 390 repeat: 391 if (!nlen) 392 return -ENOTDIR; 393 394 for ( ; table->ctl_name; table++) { 395 int n; 396 if(get_user(n,name)) 397 return -EFAULT; 398 if (n == table->ctl_name || 399 table->ctl_name == CTL_ANY) { 400 if (table->child) { 401 if (ctl_perm(table, 001)) 402 return -EPERM; 403 if (table->strategy) { 404 error = table->strategy( 405 table, name, nlen, 406 oldval, oldlenp, 407 newval, newlen, context); 408 if (error) 409 return error; 410 } 411 name++; 412 nlen--; 413 table = table->child; 414 goto repeat; 415 } 416 error = do_sysctl_strategy(table, name, nlen, 417 oldval, oldlenp, 418 newval, newlen, context); 419 return error; 420 } 421 }; 422 return -ENOTDIR; 423 } 424 425 /* Perform the actual read/write of a sysctl table entry. */ 426 int do_sysctl_strategy (ctl_table *table, 427 int *name, int nlen, 428 void *oldval, size_t *oldlenp, 429 void *newval, size_t newlen, void **context) 430 { 431 int op = 0, rc, len; 432 433 if (oldval) 434 op |= 004; 435 if (newval) 436 op |= 002; 437 if (ctl_perm(table, op)) 438 return -EPERM; 439 440 if (table->strategy) { 441 rc = table->strategy(table, name, nlen, oldval, oldlenp, 442 newval, newlen, context); 443 if (rc < 0) 444 return rc; 445 if (rc > 0) 446 return 0; 447 } 448 449 /* If there is no strategy routine, or if the strategy returns 450 * zero, proceed with automatic r/w */ 451 if (table->data && table->maxlen) { 452 if (oldval && oldlenp) { 453 get_user(len, oldlenp); 454 if (len) { 455 if (len > table->maxlen) 456 len = table->maxlen; 457 if(copy_to_user(oldval, table->data, len)) 458 return -EFAULT; 459 if(put_user(len, oldlenp)) 460 return -EFAULT; 461 } 462 } 463 if (newval && newlen) { 464 len = newlen; 465 if (len > table->maxlen) 466 len = table->maxlen; 467 if(copy_from_user(table->data, newval, len)) 468 return -EFAULT; 469 } 470 } 471 return 0; 472 } 473 474 struct ctl_table_header *register_sysctl_table(ctl_table * table, 475 int insert_at_head) 476 { 477 struct ctl_table_header *tmp; 478 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); 479 if (!tmp) 480 return 0; 481 *tmp = ((struct ctl_table_header) {table, DNODE_NULL}); 482 if (insert_at_head) 483 DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry); 484 else 485 DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry); 486 #ifdef CONFIG_PROC_FS 487 register_proc_table(table, proc_sys_root); 488 #endif 489 return tmp; 490 } 491 492 /* 493 * Unlink and free a ctl_table. 494 */ 495 void unregister_sysctl_table(struct ctl_table_header * header) 496 { 497 DLIST_DELETE(header, ctl_entry); 498 #ifdef CONFIG_PROC_FS 499 unregister_proc_table(header->ctl_table, proc_sys_root); 500 #endif 501 kfree(header); 502 } 503 504 /* 505 * /proc/sys support 506 */ 507 508 #ifdef CONFIG_PROC_FS 509 510 /* Scan the sysctl entries in table and add them all into /proc */ 511 static void register_proc_table(ctl_table * table, struct proc_dir_entry *root) 512 { 513 struct proc_dir_entry *de; 514 int len; 515 mode_t mode; 516 517 for (; table->ctl_name; table++) { 518 /* Can't do anything without a proc name. */ 519 if (!table->procname) 520 continue; 521 /* Maybe we can't do anything with it... */ 522 if (!table->proc_handler && !table->child) { 523 printk(KERN_WARNING "SYSCTL: Can't register %s\n", 524 table->procname); 525 continue; 526 } 527 528 len = strlen(table->procname); 529 mode = table->mode; 530 531 de = NULL; 532 if (table->proc_handler) 533 mode |= S_IFREG; 534 else { 535 mode |= S_IFDIR; 536 for (de = root->subdir; de; de = de->next) { 537 if (proc_match(len, table->procname, de)) 538 break; 539 } 540 /* If the subdir exists already, de is non-NULL */ 541 } 542 543 if (!de) { 544 de = create_proc_entry(table->procname, mode, root); 545 if (!de) 546 continue; 547 de->data = (void *) table; 548 if (table->proc_handler) 549 de->ops = &proc_sys_inode_operations; 550 551 } 552 table->de = de; 553 if (de->mode & S_IFDIR) 554 register_proc_table(table->child, de); 555 } 556 } 557 558 /* 559 * Unregister a /proc sysctl table and any subdirectories. 560 */ 561 static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root) 562 { 563 struct proc_dir_entry *de; 564 for (; table->ctl_name; table++) { 565 if (!(de = table->de)) 566 continue; 567 if (de->mode & S_IFDIR) { 568 if (!table->child) { 569 printk (KERN_ALERT "Help - malformed sysctl tree on free\n"); 570 continue; 571 } 572 unregister_proc_table(table->child, de); 573 574 /* Don't unregister directories which still have entries.. */ 575 if (de->subdir) 576 continue; 577 } 578 579 /* Don't unregister proc entries that are still being used.. */ 580 if (de->count) 581 continue; 582 583 table->de = NULL; 584 remove_proc_entry(table->procname, root); 585 } 586 } 587 588 static ssize_t do_rw_proc(int write, struct file * file, char * buf, 589 size_t count, loff_t *ppos) 590 { 591 int op; 592 struct proc_dir_entry *de; 593 struct ctl_table *table; 594 size_t res; 595 ssize_t error; 596 597 de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip; 598 if (!de || !de->data) 599 return -ENOTDIR; 600 table = (struct ctl_table *) de->data; 601 if (!table || !table->proc_handler) 602 return -ENOTDIR; 603 op = (write ? 002 : 004); 604 if (ctl_perm(table, op)) 605 return -EPERM; 606 607 res = count; 608 609 /* 610 * FIXME: we need to pass on ppos to the handler. 611 */ 612 613 error = (*table->proc_handler) (table, write, file, buf, &res); 614 if (error) 615 return error; 616 return res; 617 } 618 619 static ssize_t proc_readsys(struct file * file, char * buf, 620 size_t count, loff_t *ppos) 621 { 622 return do_rw_proc(0, file, buf, count, ppos); 623 } 624 625 static ssize_t proc_writesys(struct file * file, const char * buf, 626 size_t count, loff_t *ppos) 627 { 628 return do_rw_proc(1, file, (char *) buf, count, ppos); 629 } 630 631 static int proc_sys_permission(struct inode *inode, int op) 632 { 633 return test_perm(inode->i_mode, op); 634 } 635 636 int proc_dostring(ctl_table *table, int write, struct file *filp, 637 void *buffer, size_t *lenp) 638 { 639 int len; 640 char *p, c; 641 642 if (!table->data || !table->maxlen || !*lenp || 643 (filp->f_pos && !write)) { 644 *lenp = 0; 645 return 0; 646 } 647 648 if (write) { 649 len = 0; 650 p = buffer; 651 while (len < *lenp) { 652 if(get_user(c, p++)) 653 return -EFAULT; 654 if (c == 0 || c == '\n') 655 break; 656 len++; 657 } 658 if (len >= table->maxlen) 659 len = table->maxlen-1; 660 if(copy_from_user(table->data, buffer, len)) 661 return -EFAULT; 662 ((char *) table->data)[len] = 0; 663 filp->f_pos += *lenp; 664 } else { 665 len = strlen(table->data); 666 if (len > table->maxlen) 667 len = table->maxlen; 668 if (len > *lenp) 669 len = *lenp; 670 if (len) 671 if(copy_to_user(buffer, table->data, len)) 672 return -EFAULT; 673 if (len < *lenp) { 674 if(put_user('\n', ((char *) buffer) + len)) 675 return -EFAULT; 676 len++; 677 } 678 *lenp = len; 679 filp->f_pos += len; 680 } 681 return 0; 682 } 683 684 /* 685 * Special case of dostring for the UTS structure. This has locks 686 * to observe. Should this be in kernel/sys.c ???? 687 */ 688 689 static int proc_doutsstring(ctl_table *table, int write, struct file *filp, 690 void *buffer, size_t *lenp) 691 { 692 int r; 693 694 if (!write) { 695 down_read(&uts_sem); 696 r=proc_dostring(table,0,filp,buffer,lenp); 697 up_read(&uts_sem); 698 } else { 699 down_write(&uts_sem); 700 r=proc_dostring(table,1,filp,buffer,lenp); 701 up_write(&uts_sem); 702 } 703 return r; 704 } 705 706 #define OP_SET 0 707 #define OP_AND 1 708 #define OP_OR 2 709 #define OP_MAX 3 710 #define OP_MIN 4 711 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp, 712 void *buffer, size_t *lenp, int conv, int op) 713 { 714 int *i, vleft, first=1, len, left, neg, val; 715 #define TMPBUFLEN 20 716 char buf[TMPBUFLEN], *p; 717 718 if (!table->data || !table->maxlen || !*lenp || 719 (filp->f_pos && !write)) { 720 *lenp = 0; 721 return 0; 722 } 723 724 i = (int *) table->data; 725 vleft = table->maxlen / sizeof(int); 726 left = *lenp; 727 728 for (; left && vleft--; i++, first=0) { 729 if (write) { 730 while (left) { 731 char c; 732 if(get_user(c,(char *) buffer)) 733 return -EFAULT; 734 if (!isspace(c)) 735 break; 736 left--; 737 ((char *) buffer)++; 738 } 739 if (!left) 740 break; 741 neg = 0; 742 len = left; 743 if (len > TMPBUFLEN-1) 744 len = TMPBUFLEN-1; 745 if(copy_from_user(buf, buffer, len)) 746 return -EFAULT; 747 buf[len] = 0; 748 p = buf; 749 if (*p == '-' && left > 1) { 750 neg = 1; 751 left--, p++; 752 } 753 if (*p < '' || *p > '9') 754 break; 755 val = simple_strtoul(p, &p, 0) * conv; 756 len = p-buf; 757 if ((len < left) && *p && !isspace(*p)) 758 break; 759 if (neg) 760 val = -val; 761 buffer += len; 762 left -= len; 763 switch(op) { 764 case OP_SET: *i = val; break; 765 case OP_AND: *i &= val; break; 766 case OP_OR: *i |= val; break; 767 case OP_MAX: if(*i < val) 768 *i = val; 769 break; 770 case OP_MIN: if(*i > val) 771 *i = val; 772 break; 773 } 774 } else { 775 p = buf; 776 if (!first) 777 *p++ = '\t'; 778 sprintf(p, "%d", (*i) / conv); 779 len = strlen(buf); 780 if (len > left) 781 len = left; 782 if(copy_to_user(buffer, buf, len)) 783 return -EFAULT; 784 left -= len; 785 buffer += len; 786 } 787 } 788 789 if (!write && !first && left) { 790 if(put_user('\n', (char *) buffer)) 791 return -EFAULT; 792 left--, buffer++; 793 } 794 if (write) { 795 p = (char *) buffer; 796 while (left) { 797 char c; 798 if(get_user(c, p++)) 799 return -EFAULT; 800 if (!isspace(c)) 801 break; 802 left--; 803 } 804 } 805 if (write && first) 806 return -EINVAL; 807 *lenp -= left; 808 filp->f_pos += *lenp; 809 return 0; 810 } 811 812 int proc_dointvec(ctl_table *table, int write, struct file *filp, 813 void *buffer, size_t *lenp) 814 { 815 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET); 816 } 817 818 /* 819 * init may raise the set. 820 */ 821 822 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, 823 void *buffer, size_t *lenp) 824 { 825 return do_proc_dointvec(table,write,filp,buffer,lenp,1, 826 (current->pid == 1) ? OP_SET : OP_AND); 827 } 828 829 830 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, 831 void *buffer, size_t *lenp) 832 { 833 int *i, *min, *max, vleft, first=1, len, left, neg, val; 834 #define TMPBUFLEN 20 835 char buf[TMPBUFLEN], *p; 836 837 if (!table->data || !table->maxlen || !*lenp || 838 (filp->f_pos && !write)) { 839 *lenp = 0; 840 return 0; 841 } 842 843 i = (int *) table->data; 844 min = (int *) table->extra1; 845 max = (int *) table->extra2; 846 vleft = table->maxlen / sizeof(int); 847 left = *lenp; 848 849 for (; left && vleft--; i++, first=0) { 850 if (write) { 851 while (left) { 852 char c; 853 if(get_user(c, (char *) buffer)) 854 return -EFAULT; 855 if (!isspace(c)) 856 break; 857 left--; 858 ((char *) buffer)++; 859 } 860 if (!left) 861 break; 862 neg = 0; 863 len = left; 864 if (len > TMPBUFLEN-1) 865 len = TMPBUFLEN-1; 866 if(copy_from_user(buf, buffer, len)) 867 return -EFAULT; 868 buf[len] = 0; 869 p = buf; 870 if (*p == '-' && left > 1) { 871 neg = 1; 872 left--, p++; 873 } 874 if (*p < '' || *p > '9') 875 break; 876 val = simple_strtoul(p, &p, 0); 877 len = p-buf; 878 if ((len < left) && *p && !isspace(*p)) 879 break; 880 if (neg) 881 val = -val; 882 buffer += len; 883 left -= len; 884 885 if (min && val < *min++) 886 continue; 887 if (max && val > *max++) 888 continue; 889 *i = val; 890 } else { 891 p = buf; 892 if (!first) 893 *p++ = '\t'; 894 sprintf(p, "%d", *i); 895 len = strlen(buf); 896 if (len > left) 897 len = left; 898 if(copy_to_user(buffer, buf, len)) 899 return -EFAULT; 900 left -= len; 901 buffer += len; 902 } 903 } 904 905 if (!write && !first && left) { 906 if(put_user('\n', (char *) buffer)) 907 return -EFAULT; 908 left--, buffer++; 909 } 910 if (write) { 911 p = (char *) buffer; 912 while (left) { 913 char c; 914 if(get_user(c, p++)) 915 return -EFAULT; 916 if (!isspace(c)) 917 break; 918 left--; 919 } 920 } 921 if (write && first) 922 return -EINVAL; 923 *lenp -= left; 924 filp->f_pos += *lenp; 925 return 0; 926 } 927 928 929 /* 930 * an unsigned long function version 931 */ 932 933 static int do_proc_doulongvec_minmax(ctl_table *table, int write, 934 struct file *filp, 935 void *buffer, size_t *lenp, 936 unsigned long convmul, 937 unsigned long convdiv) 938 { 939 #define TMPBUFLEN 20 940 unsigned long *i, *min, *max, val; 941 int vleft, first=1, len, left, neg; 942 char buf[TMPBUFLEN], *p; 943 944 if (!table->data || !table->maxlen || !*lenp || 945 (filp->f_pos && !write)) { 946 *lenp = 0; 947 return 0; 948 } 949 950 i = (unsigned long *) table->data; 951 min = (unsigned long *) table->extra1; 952 max = (unsigned long *) table->extra2; 953 vleft = table->maxlen / sizeof(unsigned long); 954 left = *lenp; 955 956 for (; left && vleft--; i++, first=0) { 957 if (write) { 958 while (left) { 959 char c; 960 if(get_user(c, (char *) buffer)) 961 return -EFAULT; 962 if (!isspace(c)) 963 break; 964 left--; 965 ((char *) buffer)++; 966 } 967 if (!left) 968 break; 969 neg = 0; 970 len = left; 971 if (len > TMPBUFLEN-1) 972 len = TMPBUFLEN-1; 973 if(copy_from_user(buf, buffer, len)) 974 return -EFAULT; 975 buf[len] = 0; 976 p = buf; 977 if (*p == '-' && left > 1) { 978 neg = 1; 979 left--, p++; 980 } 981 if (*p < '' || *p > '9') 982 break; 983 val = simple_strtoul(p, &p, 0) * convmul / convdiv ; 984 len = p-buf; 985 if ((len < left) && *p && !isspace(*p)) 986 break; 987 if (neg) 988 val = -val; 989 buffer += len; 990 left -= len; 991 992 if(neg) 993 continue; 994 if (min && val < *min++) 995 continue; 996 if (max && val > *max++) 997 continue; 998 *i = val; 999 } else { 1000 p = buf; 1001 if (!first) 1002 *p++ = '\t'; 1003 sprintf(p, "%lu", convdiv * (*i) / convmul); 1004 len = strlen(buf); 1005 if (len > left) 1006 len = left; 1007 if(copy_to_user(buffer, buf, len)) 1008 return -EFAULT; 1009 left -= len; 1010 buffer += len; 1011 } 1012 } 1013 1014 if (!write && !first && left) { 1015 if(put_user('\n', (char *) buffer)) 1016 return -EFAULT; 1017 left--, buffer++; 1018 } 1019 if (write) { 1020 p = (char *) buffer; 1021 while (left) { 1022 char c; 1023 if(get_user(c, p++)) 1024 return -EFAULT; 1025 if (!isspace(c)) 1026 break; 1027 left--; 1028 } 1029 } 1030 if (write && first) 1031 return -EINVAL; 1032 *lenp -= left; 1033 filp->f_pos += *lenp; 1034 return 0; 1035 #undef TMPBUFLEN 1036 } 1037 1038 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, 1039 void *buffer, size_t *lenp) 1040 { 1041 return do_proc_doulongvec_minmax(table, write, filp, buffer, lenp, 1l, 1l); 1042 } 1043 1044 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, 1045 struct file *filp, 1046 void *buffer, size_t *lenp) 1047 { 1048 return do_proc_doulongvec_minmax(table, write, filp, buffer, 1049 lenp, HZ, 1000l); 1050 } 1051 1052 1053 /* Like proc_dointvec, but converts seconds to jiffies */ 1054 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, 1055 void *buffer, size_t *lenp) 1056 { 1057 return do_proc_dointvec(table,write,filp,buffer,lenp,HZ,OP_SET); 1058 } 1059 1060 #else /* CONFIG_PROC_FS */ 1061 1062 int proc_dostring(ctl_table *table, int write, struct file *filp, 1063 void *buffer, size_t *lenp) 1064 { 1065 return -ENOSYS; 1066 } 1067 1068 static int proc_doutsstring(ctl_table *table, int write, struct file *filp, 1069 void *buffer, size_t *lenp) 1070 { 1071 return -ENOSYS; 1072 } 1073 1074 int proc_dointvec(ctl_table *table, int write, struct file *filp, 1075 void *buffer, size_t *lenp) 1076 { 1077 return -ENOSYS; 1078 } 1079 1080 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, 1081 void *buffer, size_t *lenp) 1082 { 1083 return -ENOSYS; 1084 } 1085 1086 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, 1087 void *buffer, size_t *lenp) 1088 { 1089 return -ENOSYS; 1090 } 1091 1092 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, 1093 void *buffer, size_t *lenp) 1094 { 1095 return -ENOSYS; 1096 } 1097 1098 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, 1099 void *buffer, size_t *lenp) 1100 { 1101 return -ENOSYS; 1102 } 1103 1104 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, 1105 struct file *filp, 1106 void *buffer, size_t *lenp) 1107 { 1108 return -ENOSYS; 1109 } 1110 1111 1112 #endif /* CONFIG_PROC_FS */ 1113 1114 1115 /* 1116 * General sysctl support routines 1117 */ 1118 1119 /* The generic string strategy routine: */ 1120 int sysctl_string(ctl_table *table, int *name, int nlen, 1121 void *oldval, size_t *oldlenp, 1122 void *newval, size_t newlen, void **context) 1123 { 1124 int l, len; 1125 1126 if (!table->data || !table->maxlen) 1127 return -ENOTDIR; 1128 1129 if (oldval && oldlenp) { 1130 if(get_user(len, oldlenp)) 1131 return -EFAULT; 1132 if (len) { 1133 l = strlen(table->data); 1134 if (len > l) len = l; 1135 if (len >= table->maxlen) 1136 len = table->maxlen; 1137 if(copy_to_user(oldval, table->data, len)) 1138 return -EFAULT; 1139 if(put_user(0, ((char *) oldval) + len)) 1140 return -EFAULT; 1141 if(put_user(len, oldlenp)) 1142 return -EFAULT; 1143 } 1144 } 1145 if (newval && newlen) { 1146 len = newlen; 1147 if (len > table->maxlen) 1148 len = table->maxlen; 1149 if(copy_from_user(table->data, newval, len)) 1150 return -EFAULT; 1151 if (len == table->maxlen) 1152 len--; 1153 ((char *) table->data)[len] = 0; 1154 } 1155 return 0; 1156 } 1157 1158 /* 1159 * This function makes sure that all of the integers in the vector 1160 * are between the minimum and maximum values given in the arrays 1161 * table->extra1 and table->extra2, respectively. 1162 */ 1163 int sysctl_intvec(ctl_table *table, int *name, int nlen, 1164 void *oldval, size_t *oldlenp, 1165 void *newval, size_t newlen, void **context) 1166 { 1167 int i, length, *vec, *min, *max; 1168 1169 if (newval && newlen) { 1170 if (newlen % sizeof(int) != 0) 1171 return -EINVAL; 1172 1173 if (!table->extra1 && !table->extra2) 1174 return 0; 1175 1176 if (newlen > table->maxlen) 1177 newlen = table->maxlen; 1178 length = newlen / sizeof(int); 1179 1180 vec = (int *) newval; 1181 min = (int *) table->extra1; 1182 max = (int *) table->extra2; 1183 1184 for (i = 0; i < length; i++) { 1185 int value; 1186 get_user(value, vec + i); 1187 if (min && value < min[i]) 1188 return -EINVAL; 1189 if (max && value > max[i]) 1190 return -EINVAL; 1191 } 1192 } 1193 return 0; 1194 } 1195 1196 /* Strategy function to convert jiffies to seconds */ 1197 int sysctl_jiffies(ctl_table *table, int *name, int nlen, 1198 void *oldval, size_t *oldlenp, 1199 void *newval, size_t newlen, void **context) 1200 { 1201 if (oldval) { 1202 size_t olen; 1203 if (oldlenp) { 1204 if (get_user(olen, oldlenp)) 1205 return -EFAULT; 1206 if (olen!=sizeof(int)) 1207 return -EINVAL; 1208 } 1209 if (put_user(*(int *)(table->data) / HZ, (int *)oldval) || 1210 (oldlenp && put_user(sizeof(int),oldlenp))) 1211 return -EFAULT; 1212 } 1213 if (newval && newlen) { 1214 int new; 1215 if (newlen != sizeof(int)) 1216 return -EINVAL; 1217 if (get_user(new, (int *)newval)) 1218 return -EFAULT; 1219 *(int *)(table->data) = new*HZ; 1220 } 1221 return 1; 1222 } 1223 1224 int do_string ( 1225 void *oldval, size_t *oldlenp, void *newval, size_t newlen, 1226 int rdwr, char *data, size_t max) 1227 { 1228 int l = strlen(data) + 1; 1229 if (newval && !rdwr) 1230 return -EPERM; 1231 if (newval && newlen >= max) 1232 return -EINVAL; 1233 if (oldval) { 1234 int old_l; 1235 if(get_user(old_l, oldlenp)) 1236 return -EFAULT; 1237 if (l > old_l) 1238 return -ENOMEM; 1239 if(put_user(l, oldlenp) || copy_to_user(oldval, data, l)) 1240 return -EFAULT; 1241 } 1242 if (newval) { 1243 if(copy_from_user(data, newval, newlen)) 1244 return -EFAULT; 1245 data[newlen] = 0; 1246 } 1247 return 0; 1248 } 1249 1250 int do_int ( 1251 void *oldval, size_t *oldlenp, void *newval, size_t newlen, 1252 int rdwr, int *data) 1253 { 1254 if (newval && !rdwr) 1255 return -EPERM; 1256 if (newval && newlen != sizeof(int)) 1257 return -EINVAL; 1258 if (oldval) { 1259 int old_l; 1260 if(get_user(old_l, oldlenp)) 1261 return -EFAULT; 1262 if (old_l < sizeof(int)) 1263 return -ENOMEM; 1264 if(put_user(sizeof(int), oldlenp)||copy_to_user(oldval, data, sizeof(int))) 1265 return -EFAULT; 1266 } 1267 if (newval) 1268 if(copy_from_user(data, newval, sizeof(int))) 1269 return -EFAULT; 1270 return 0; 1271 } 1272 1273 int do_struct ( 1274 void *oldval, size_t *oldlenp, void *newval, size_t newlen, 1275 int rdwr, void *data, size_t len) 1276 { 1277 if (newval && !rdwr) 1278 return -EPERM; 1279 if (newval && newlen != len) 1280 return -EINVAL; 1281 if (oldval) { 1282 int old_l; 1283 if(get_user(old_l, oldlenp)) 1284 return -EFAULT; 1285 if (old_l < len) 1286 return -ENOMEM; 1287 if(put_user(len, oldlenp) || copy_to_user(oldval, data, len)) 1288 return -EFAULT; 1289 } 1290 if (newval) 1291 if(copy_from_user(data, newval, len)) 1292 return -EFAULT; 1293 return 0; 1294 } 1295 1296 1297 #else /* CONFIG_SYSCTL */ 1298 1299 1300 extern asmlinkage long sys_sysctl(struct __sysctl_args *args) 1301 { 1302 return -ENOSYS; 1303 } 1304 1305 int sysctl_string(ctl_table *table, int *name, int nlen, 1306 void *oldval, size_t *oldlenp, 1307 void *newval, size_t newlen, void **context) 1308 { 1309 return -ENOSYS; 1310 } 1311 1312 int sysctl_intvec(ctl_table *table, int *name, int nlen, 1313 void *oldval, size_t *oldlenp, 1314 void *newval, size_t newlen, void **context) 1315 { 1316 return -ENOSYS; 1317 } 1318 1319 int proc_dostring(ctl_table *table, int write, struct file *filp, 1320 void *buffer, size_t *lenp) 1321 { 1322 return -ENOSYS; 1323 } 1324 1325 int proc_dointvec(ctl_table *table, int write, struct file *filp, 1326 void *buffer, size_t *lenp) 1327 { 1328 return -ENOSYS; 1329 } 1330 1331 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, 1332 void *buffer, size_t *lenp) 1333 { 1334 return -ENOSYS; 1335 } 1336 1337 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp, 1338 void *buffer, size_t *lenp) 1339 { 1340 return -ENOSYS; 1341 } 1342 1343 int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp, 1344 void *buffer, size_t *lenp) 1345 { 1346 return -ENOSYS; 1347 } 1348 1349 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, 1350 void *buffer, size_t *lenp) 1351 { 1352 return -ENOSYS; 1353 } 1354 1355 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write, 1356 struct file *filp, 1357 void *buffer, size_t *lenp) 1358 { 1359 return -ENOSYS; 1360 } 1361 1362 struct ctl_table_header * register_sysctl_table(ctl_table * table, 1363 int insert_at_head) 1364 { 1365 return 0; 1366 } 1367 1368 void unregister_sysctl_table(struct ctl_table_header * table) 1369 { 1370 } 1371 1372 #endif /* CONFIG_SYSCTL */ 1373

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.