root/kernel/sysctl.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sysctl_init
  2. do_sysctl
  3. sys_sysctl
  4. in_egroup_p
  5. test_perm
  6. ctl_perm
  7. parse_table
  8. do_sysctl_strategy
  9. do_securelevel_strategy
  10. register_sysctl_table
  11. unregister_sysctl_table
  12. register_proc_table
  13. unregister_proc_table
  14. do_rw_proc
  15. proc_readsys
  16. proc_writesys
  17. proc_sys_permission
  18. proc_dostring
  19. proc_dointvec
  20. proc_dointvec_minmax
  21. proc_dostring
  22. proc_dointvec
  23. proc_dointvec_minmax
  24. sysctl_string
  25. sysctl_intvec
  26. do_string
  27. do_int
  28. do_struct

   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  */
   8 
   9 #include <linux/config.h>
  10 #include <linux/sched.h>
  11 #include <linux/mm.h>
  12 #include <linux/sysctl.h>
  13 #include <linux/swapctl.h>
  14 #include <linux/proc_fs.h>
  15 #include <linux/malloc.h>
  16 #include <linux/stat.h>
  17 #include <linux/ctype.h>
  18 #include <asm/bitops.h>
  19 #include <asm/segment.h>
  20 
  21 #include <linux/utsname.h>
  22 #include <linux/swapctl.h>
  23 
  24 /* External variables not in a header file. */
  25 extern int panic_timeout;
  26 
  27 
  28 #ifdef CONFIG_ROOT_NFS
  29 #include <linux/nfs_fs.h>
  30 #endif
  31 
  32 static ctl_table root_table[];
  33 static struct ctl_table_header root_table_header = 
  34         {root_table, DNODE_SINGLE(&root_table_header)};
  35 
  36 static int parse_table(int *, int, void *, size_t *, void *, size_t,
  37                        ctl_table *, void **);
  38 
  39 static ctl_table kern_table[];
  40 static ctl_table vm_table[];
  41 
  42 /* /proc declarations: */
  43 
  44 #ifdef CONFIG_PROC_FS
  45 
  46 static int proc_readsys(struct inode * inode, struct file * file,
  47                         char * buf, int count);
  48 static int proc_writesys(struct inode * inode, struct file * file,
  49                          const char * buf, int count);
  50 static int proc_sys_permission(struct inode *, int);
  51 
  52 struct file_operations proc_sys_file_operations =
  53 {
  54         NULL,           /* lseek   */
  55         proc_readsys,   /* read    */
  56         proc_writesys,  /* write   */
  57         NULL,           /* readdir */
  58         NULL,           /* select  */
  59         NULL,           /* ioctl   */
  60         NULL,           /* mmap    */
  61         NULL,           /* no special open code    */
  62         NULL,           /* no special release code */
  63         NULL            /* can't fsync */
  64 };
  65 
  66 struct inode_operations proc_sys_inode_operations =
  67 {
  68         &proc_sys_file_operations,
  69         NULL,           /* create */
  70         NULL,           /* lookup */
  71         NULL,           /* link */
  72         NULL,           /* unlink */
  73         NULL,           /* symlink */
  74         NULL,           /* mkdir */
  75         NULL,           /* rmdir */
  76         NULL,           /* mknod */
  77         NULL,           /* rename */
  78         NULL,           /* readlink */
  79         NULL,           /* follow_link */
  80         NULL,           /* readpage */
  81         NULL,           /* writepage */
  82         NULL,           /* bmap */
  83         NULL,           /* truncate */
  84         proc_sys_permission
  85 };
  86 
  87 extern struct proc_dir_entry proc_sys_root;
  88 
  89 static void register_proc_table(ctl_table *, struct proc_dir_entry *);
  90 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
  91 #endif
  92 
  93 extern int bdf_prm[], bdflush_min[], bdflush_max[];
  94 
  95 static int do_securelevel_strategy (ctl_table *, int *, int, void *, size_t *,
  96                                     void *, size_t, void **);
  97 
  98 /* The default sysctl tables: */
  99 
 100 static ctl_table root_table[] = {
 101         {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
 102         {CTL_VM, "vm", NULL, 0, 0555, vm_table},
 103         {0}
 104 };
 105 
 106 static ctl_table kern_table[] = {
 107         {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
 108          0444, NULL, &proc_dostring, &sysctl_string},
 109         {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
 110          0444, NULL, &proc_dostring, &sysctl_string},
 111         {KERN_VERSION, "version", system_utsname.version, 64,
 112          0444, NULL, &proc_dostring, &sysctl_string},
 113         {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
 114          0644, NULL, &proc_dostring, &sysctl_string},
 115         {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
 116          0644, NULL, &proc_dostring, &sysctl_string},
 117         {KERN_NRINODE, "inode-nr", &nr_inodes, 2*sizeof(int),
 118          0444, NULL, &proc_dointvec},
 119         {KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int),
 120          0644, NULL, &proc_dointvec},
 121         {KERN_NRFILE, "file-nr", &nr_files, sizeof(int),
 122          0444, NULL, &proc_dointvec},
 123         {KERN_MAXFILE, "file-max", &max_files, sizeof(int),
 124          0644, NULL, &proc_dointvec},
 125         {KERN_SECURELVL, "securelevel", &securelevel, sizeof(int),
 126          0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy},
 127         {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
 128          0644, NULL, &proc_dointvec},
 129 #ifdef CONFIG_BLK_DEV_INITRD
 130         {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
 131          0644, NULL, &proc_dointvec},
 132 #endif
 133 #ifdef CONFIG_ROOT_NFS
 134         {KERN_NFSRNAME, "nfs-root-name", nfs_root_name, NFS_ROOT_NAME_LEN,
 135          0644, NULL, &proc_dostring, &sysctl_string },
 136         {KERN_NFSRNAME, "nfs-root-addrs", nfs_root_addrs, NFS_ROOT_ADDRS_LEN,
 137          0644, NULL, &proc_dostring, &sysctl_string },
 138 #endif
 139         {0}
 140 };
 141 
 142 static ctl_table vm_table[] = {
 143         {VM_SWAPCTL, "swapctl", 
 144          &swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec},
 145         {VM_KSWAPD, "kswapd", 
 146          &kswapd_ctl, sizeof(kswapd_ctl), 0600, NULL, &proc_dointvec},
 147         {VM_FREEPG, "freepages", 
 148          &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec},
 149         {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
 150          &proc_dointvec_minmax, &sysctl_intvec, NULL,
 151          &bdflush_min, &bdflush_max},
 152         {0}
 153 };
 154 
 155 void sysctl_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 156 {
 157 #ifdef CONFIG_PROC_FS
 158         register_proc_table(root_table, &proc_sys_root);
 159 #endif
 160 }
 161 
 162 
 163 int do_sysctl (int *name, int nlen,
     /* [previous][next][first][last][top][bottom][index][help] */
 164                void *oldval, size_t *oldlenp,
 165                void *newval, size_t newlen)
 166 {
 167         int error;
 168         struct ctl_table_header *tmp;
 169         void *context;
 170         
 171         if (nlen == 0 || nlen >= CTL_MAXNAME)
 172                 return -ENOTDIR;
 173         
 174         error = verify_area(VERIFY_READ,name,nlen*sizeof(int));
 175         if (error) return error;
 176         if (oldval) {
 177                 if (!oldlenp)
 178                         return -EFAULT;
 179                 error = verify_area(VERIFY_WRITE,oldlenp,sizeof(size_t));
 180                 if (error) return error;
 181                 error = verify_area(VERIFY_WRITE,oldval,get_user(oldlenp));
 182                 if (error) return error;
 183         }
 184         if (newval) {
 185                 error = verify_area(VERIFY_READ,newval,newlen);
 186                 if (error) return error;
 187         }
 188         tmp = &root_table_header;
 189         do {
 190                 context = 0;
 191                 error = parse_table(name, nlen, oldval, oldlenp, 
 192                                     newval, newlen, root_table, &context);
 193                 if (context)
 194                         kfree(context);
 195                 if (error != -ENOTDIR)
 196                         return error;
 197                 tmp = tmp->DLIST_NEXT(ctl_entry);
 198         } while (tmp != &root_table_header);
 199         return -ENOTDIR;
 200 }
 201 
 202 extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204         struct __sysctl_args tmp;
 205         int error;
 206         error = verify_area(VERIFY_READ, args, sizeof(*args));
 207         if (error)
 208                 return error;
 209         memcpy_fromfs(&tmp, args, sizeof(tmp));
 210         return do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp, 
 211                          tmp.newval, tmp.newlen);
 212 }
 213 
 214 /* Like in_group_p, but testing against egid, not fsgid */
 215 static int in_egroup_p(gid_t grp)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217         int     i;
 218 
 219         if (grp == current->euid)
 220                 return 1;
 221 
 222         for (i = 0; i < NGROUPS; i++) {
 223                 if (current->groups[i] == NOGROUP)
 224                         break;
 225                 if (current->groups[i] == grp)
 226                         return 1;
 227         }
 228         return 0;
 229 }
 230 /* ctl_perm does NOT grant the superuser all rights automatically, because
 231    some sysctl variables are readonly even to root. */
 232 static int test_perm(int mode, int op)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234         if (!current->euid)
 235                 mode >>= 6;
 236         else if (in_egroup_p(0))
 237                 mode >>= 3;
 238         if ((mode & op & 0007) == op)
 239                 return 0;
 240         return -EACCES;
 241 }
 242 static inline int ctl_perm(ctl_table *table, int op)
     /* [previous][next][first][last][top][bottom][index][help] */
 243 {
 244         return test_perm(table->mode, op);
 245 }
 246 
 247 static int parse_table(int *name, int nlen,
     /* [previous][next][first][last][top][bottom][index][help] */
 248                        void *oldval, size_t *oldlenp,
 249                        void *newval, size_t newlen,
 250                        ctl_table *table, void **context)
 251 {
 252         int error;
 253 repeat:
 254         if (!nlen)
 255                 return -ENOTDIR;
 256 
 257         for ( ; table->ctl_name; table++) {
 258                 if (get_user(name) == table->ctl_name ||
 259                     table->ctl_name == CTL_ANY) {
 260                         if (table->child) {
 261                                 if (ctl_perm(table, 001))
 262                                         return -EPERM;
 263                                 if (table->strategy) {
 264                                         error = table->strategy(
 265                                                 table, name, nlen,
 266                                                 oldval, oldlenp,
 267                                                 newval, newlen, context);
 268                                 if (error)
 269                                         return error;
 270                                 }
 271                                 name++;
 272                                 nlen--;
 273                                 table = table->child;
 274                                 goto repeat;
 275                         }
 276                         error = do_sysctl_strategy(table, name, nlen,
 277                                                    oldval, oldlenp,
 278                                                    newval, newlen, context);
 279                         return error;
 280                 }
 281         };
 282         return -ENOTDIR;
 283 }
 284 
 285 /* Perform the actual read/write of a sysctl table entry. */
 286 int do_sysctl_strategy (ctl_table *table, 
     /* [previous][next][first][last][top][bottom][index][help] */
 287                         int *name, int nlen,
 288                         void *oldval, size_t *oldlenp,
 289                         void *newval, size_t newlen, void **context)
 290 {
 291         int op = 0, rc, len;
 292 
 293         if (oldval)
 294                 op |= 004;
 295         if (newval) 
 296                 op |= 002;
 297         if (ctl_perm(table, op))
 298                 return -EPERM;
 299 
 300         if (table->strategy) {
 301                 rc = table->strategy(table, name, nlen, oldval, oldlenp,
 302                                      newval, newlen, context);
 303                 if (rc < 0)
 304                         return rc;
 305                 if (rc > 0)
 306                         return 0;
 307         }
 308 
 309         /* If there is no strategy routine, or if the strategy returns
 310          * zero, proceed with automatic r/w */
 311         if (table->data && table->maxlen) {
 312                 if (oldval && oldlenp && get_user(oldlenp)) {
 313                         len = get_user(oldlenp);
 314                         if (len > table->maxlen)
 315                                 len = table->maxlen;
 316                         memcpy_tofs(oldval, table->data, len);
 317                         put_user(len, oldlenp);
 318                 }
 319                 if (newval && newlen) {
 320                         len = newlen;
 321                         if (len > table->maxlen)
 322                                 len = table->maxlen;
 323                         memcpy_fromfs(table->data, newval, len);
 324                 }
 325         }
 326         return 0;
 327 }
 328 
 329 /*
 330  * This function only checks permission for changing the security level
 331  * If the tests are successfull, the actual change is done by
 332  * do_sysctl_strategy
 333  */
 334 static int do_securelevel_strategy (ctl_table *table, 
     /* [previous][next][first][last][top][bottom][index][help] */
 335                                     int *name, int nlen,
 336                                     void *oldval, size_t *oldlenp,
 337                                     void *newval, size_t newlen, void **context)
 338 {
 339         int level;
 340 
 341         if (newval && newlen) {
 342                 if (newlen != sizeof (int))
 343                         return -EINVAL;
 344                 memcpy_fromfs (&level, newval, newlen);
 345                 if (level < securelevel && current->pid != 1)
 346                         return -EPERM;
 347         }
 348         return 0;
 349 }
 350 
 351 struct ctl_table_header *register_sysctl_table(ctl_table * table, 
     /* [previous][next][first][last][top][bottom][index][help] */
 352                                                int insert_at_head)
 353 {
 354         struct ctl_table_header *tmp;
 355         tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
 356         if (!tmp)
 357                 return 0;
 358         *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
 359         if (insert_at_head)
 360                 DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
 361         else
 362                 DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
 363 #ifdef CONFIG_PROC_FS
 364         register_proc_table(table, &proc_sys_root);
 365 #endif
 366         return tmp;
 367 }
 368 
 369 void unregister_sysctl_table(struct ctl_table_header * table)
     /* [previous][next][first][last][top][bottom][index][help] */
 370 {
 371         DLIST_DELETE(table, ctl_entry);
 372 #ifdef CONFIG_PROC_FS
 373         unregister_proc_table(table->ctl_table, &proc_sys_root);
 374 #endif
 375 }
 376 
 377 /*
 378  * /proc/sys support
 379  */
 380 
 381 #ifdef CONFIG_PROC_FS
 382 
 383 /* Scan the sysctl entries in table and add them all into /proc */
 384 static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
     /* [previous][next][first][last][top][bottom][index][help] */
 385 {
 386         struct proc_dir_entry *de;
 387         
 388         for (; table->ctl_name; table++) {
 389                 /* Can't do anything without a proc name. */
 390                 if (!table->procname)
 391                         continue;
 392                 /* Maybe we can't do anything with it... */
 393                 if (!table->proc_handler &&
 394                     !table->child)
 395                         continue;
 396                 
 397                 de = kmalloc(sizeof(*de), GFP_KERNEL);
 398                 if (!de) continue;
 399                 de->namelen = strlen(table->procname);
 400                 de->name = table->procname;
 401                 de->mode = table->mode;
 402                 de->nlink = 1;
 403                 de->uid = 0;
 404                 de->gid = 0;
 405                 de->size = 0;
 406                 de->get_info = 0;       /* For internal use if we want it */
 407                 de->fill_inode = 0;     /* To override struct inode fields */
 408                 de->next = de->subdir = 0;
 409                 de->data = (void *) table;
 410                 /* Is it a file? */
 411                 if (table->proc_handler) {
 412                         de->ops = &proc_sys_inode_operations;
 413                         de->mode |= S_IFREG;
 414                 }
 415                 /* Otherwise it's a subdir */
 416                 else  {
 417                         de->ops = &proc_dir_inode_operations;
 418                         de->nlink++;
 419                         de->mode |= S_IFDIR;
 420                 }
 421                 table->de = de;
 422                 proc_register_dynamic(root, de);
 423                 if (de->mode & S_IFDIR )
 424                         register_proc_table(table->child, de);
 425         }
 426 }
 427 
 428 static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
     /* [previous][next][first][last][top][bottom][index][help] */
 429 {
 430         struct proc_dir_entry *de;
 431         for (; table->ctl_name; table++) {
 432                 if (!(de = table->de))
 433                         continue;
 434                 if (de->mode & S_IFDIR) {
 435                         if (!table->child) {
 436                                 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
 437                                 continue;
 438                         }
 439                         unregister_proc_table(table->child, de);
 440                 }
 441                 proc_unregister(root, de->low_ino);
 442                 kfree(de);                      
 443         }
 444 }
 445 
 446 
 447 static int do_rw_proc(int write, struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 448                       char * buf, int count)
 449 {
 450         int error, op;
 451         struct proc_dir_entry *de;
 452         struct ctl_table *table;
 453         size_t res;
 454         
 455         error = verify_area(write ? VERIFY_READ : VERIFY_WRITE, buf, count);
 456         if (error)
 457                 return error;
 458 
 459         de = (struct proc_dir_entry*) inode->u.generic_ip;
 460         if (!de || !de->data)
 461                 return -ENOTDIR;
 462         table = (struct ctl_table *) de->data;
 463         if (!table || !table->proc_handler)
 464                 return -ENOTDIR;
 465         op = (write ? 002 : 004);
 466         if (ctl_perm(table, op))
 467                 return -EPERM;
 468         
 469         res = count;
 470         error = (*table->proc_handler) (table, write, file, buf, &res);
 471         if (error)
 472                 return error;
 473         return res;
 474 }
 475 
 476 static int proc_readsys(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 477                         char * buf, int count)
 478 {
 479         return do_rw_proc(0, inode, file, buf, count);
 480 }
 481 
 482 static int proc_writesys(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 483                          const char * buf, int count)
 484 {
 485         return do_rw_proc(1, inode, file, (char *) buf, count);
 486 }
 487 
 488 static int proc_sys_permission(struct inode *inode, int op)
     /* [previous][next][first][last][top][bottom][index][help] */
 489 {
 490         return test_perm(inode->i_mode, op);
 491 }
 492 
 493 int proc_dostring(ctl_table *table, int write, struct file *filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 494                   void *buffer, size_t *lenp)
 495 {
 496         int len;
 497         char *p, c;
 498         
 499         if (!table->data || !table->maxlen || !*lenp ||
 500             (filp->f_pos && !write)) {
 501                 *lenp = 0;
 502                 return 0;
 503         }
 504         
 505         if (write) {
 506                 len = 0;
 507                 p = buffer;
 508                 while (len < *lenp && 
 509                        (c = get_user(p++)) != 0 && c != '\n')
 510                         len++;
 511                 if (len >= table->maxlen)
 512                         len = table->maxlen-1;
 513                 memcpy_fromfs(table->data, buffer, len);
 514                 ((char *) table->data)[len] = 0;
 515                 filp->f_pos += *lenp;
 516         } else {
 517                 len = strlen(table->data) + 1;
 518                 if (len > table->maxlen)
 519                         len = table->maxlen;
 520                 if (len > *lenp)
 521                         len = *lenp;
 522                 if (len) {                      
 523                         memcpy_tofs(buffer, table->data, len-1);
 524                         put_user(0, ((char *) buffer) + len - 1);
 525                 }
 526                 if (len < *lenp) {
 527                         put_user('\n', ((char *) buffer) + len);
 528                         len++;
 529                 }
 530                 *lenp = len;
 531                 filp->f_pos += len;
 532         }
 533         return 0;
 534 }
 535 
 536 int proc_dointvec(ctl_table *table, int write, struct file *filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 537                   void *buffer, size_t *lenp)
 538 {
 539         int *i, vleft, first=1, len, left, neg, val;
 540         #define TMPBUFLEN 20
 541         char buf[TMPBUFLEN], *p;
 542         
 543         if (!table->data || !table->maxlen || !*lenp ||
 544             (filp->f_pos && !write)) {
 545                 *lenp = 0;
 546                 return 0;
 547         }
 548         
 549         i = (int *) table->data;
 550         vleft = table->maxlen / sizeof(int);
 551         left = *lenp;
 552         
 553         for (; left && vleft--; i++, first=0) {
 554                 if (write) {
 555                         while (left && isspace(get_user((char *) buffer)))
 556                                 left--, ((char *) buffer)++;
 557                         if (!left)
 558                                 break;
 559                         neg = 0;
 560                         len = left;
 561                         if (len > TMPBUFLEN-1)
 562                                 len = TMPBUFLEN-1;
 563                         memcpy_fromfs(buf, buffer, len);
 564                         buf[len] = 0;
 565                         p = buf;
 566                         if (*p == '-' && left > 1) {
 567                                 neg = 1;
 568                                 left--, p++;
 569                         }
 570                         if (*p < '0' || *p > '9')
 571                                 break;
 572                         val = simple_strtoul(p, &p, 0);
 573                         len = p-buf;
 574                         if ((len < left) && *p && !isspace(*p))
 575                                 break;
 576                         if (neg)
 577                                 val = -val;
 578                         buffer += len;
 579                         left -= len;
 580                         *i = val;
 581                 } else {
 582                         p = buf;
 583                         if (!first)
 584                                 *p++ = '\t';
 585                         sprintf(p, "%d", *i);
 586                         len = strlen(buf);
 587                         if (len > left)
 588                                 len = left;
 589                         memcpy_tofs(buffer, buf, len);
 590                         left -= len;
 591                         buffer += len;
 592                 }
 593         }
 594 
 595         if (!write && !first && left) {
 596                 put_user('\n', (char *) buffer);
 597                 left--, buffer++;
 598         }
 599         if (write) {
 600                 p = (char *) buffer;
 601                 while (left && isspace(get_user(p++)))
 602                         left--;
 603         }
 604         if (write && first)
 605                 return -EINVAL;
 606         *lenp -= left;
 607         filp->f_pos += *lenp;
 608         return 0;
 609 }
 610 
 611 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 612                   void *buffer, size_t *lenp)
 613 {
 614         int *i, *min, *max, vleft, first=1, len, left, neg, val;
 615         #define TMPBUFLEN 20
 616         char buf[TMPBUFLEN], *p;
 617         
 618         if (!table->data || !table->maxlen || !*lenp ||
 619             (filp->f_pos && !write)) {
 620                 *lenp = 0;
 621                 return 0;
 622         }
 623         
 624         i = (int *) table->data;
 625         min = (int *) table->extra1;
 626         max = (int *) table->extra2;
 627         vleft = table->maxlen / sizeof(int);
 628         left = *lenp;
 629         
 630         for (; left && vleft--; i++, first=0) {
 631                 if (write) {
 632                         while (left && isspace(get_user((char *) buffer)))
 633                                 left--, ((char *) buffer)++;
 634                         if (!left)
 635                                 break;
 636                         neg = 0;
 637                         len = left;
 638                         if (len > TMPBUFLEN-1)
 639                                 len = TMPBUFLEN-1;
 640                         memcpy_fromfs(buf, buffer, len);
 641                         buf[len] = 0;
 642                         p = buf;
 643                         if (*p == '-' && left > 1) {
 644                                 neg = 1;
 645                                 left--, p++;
 646                         }
 647                         if (*p < '0' || *p > '9')
 648                                 break;
 649                         val = simple_strtoul(p, &p, 0);
 650                         len = p-buf;
 651                         if ((len < left) && *p && !isspace(*p))
 652                                 break;
 653                         if (neg)
 654                                 val = -val;
 655                         buffer += len;
 656                         left -= len;
 657 
 658                         if (min && val < *min++)
 659                                 continue;
 660                         if (max && val > *max++)
 661                                 continue;
 662                         *i = val;
 663                 } else {
 664                         p = buf;
 665                         if (!first)
 666                                 *p++ = '\t';
 667                         sprintf(p, "%d", *i);
 668                         len = strlen(buf);
 669                         if (len > left)
 670                                 len = left;
 671                         memcpy_tofs(buffer, buf, len);
 672                         left -= len;
 673                         buffer += len;
 674                 }
 675         }
 676 
 677         if (!write && !first && left) {
 678                 put_user('\n', (char *) buffer);
 679                 left--, buffer++;
 680         }
 681         if (write) {
 682                 p = (char *) buffer;
 683                 while (left && isspace(get_user(p++)))
 684                         left--;
 685         }
 686         if (write && first)
 687                 return -EINVAL;
 688         *lenp -= left;
 689         filp->f_pos += *lenp;
 690         return 0;
 691 }
 692 
 693 #else /* CONFIG_PROC_FS */
 694 
 695 int proc_dostring(ctl_table *table, int write, struct file *filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 696                   void *buffer, size_t *lenp)
 697 {
 698         return -ENOSYS;
 699 }
 700 
 701 int proc_dointvec(ctl_table *table, int write, struct file *filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 702                   void *buffer, size_t *lenp)
 703 {
 704         return -ENOSYS;
 705 }
 706 
 707 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 708                     void *buffer, size_t *lenp)
 709 {
 710         return -ENOSYS;
 711 }
 712 
 713 #endif /* CONFIG_PROC_FS */
 714 
 715 
 716 /*
 717  * General sysctl support routines 
 718  */
 719 
 720 /* The generic string strategy routine: */
 721 int sysctl_string(ctl_table *table, int *name, int nlen,
     /* [previous][next][first][last][top][bottom][index][help] */
 722                   void *oldval, size_t *oldlenp,
 723                   void *newval, size_t newlen, void **context)
 724 {
 725         int l, len;
 726         
 727         if (!table->data || !table->maxlen) 
 728                 return -ENOTDIR;
 729         
 730         if (oldval && oldlenp && get_user(oldlenp)) {
 731                 len = get_user(oldlenp);
 732                 l = strlen(table->data);
 733                 if (len > l) len = l;
 734                 if (len >= table->maxlen)
 735                         len = table->maxlen;
 736                 memcpy_tofs(oldval, table->data, len);
 737                 put_user(0, ((char *) oldval) + len);
 738                 put_user(len, oldlenp);
 739         }
 740         if (newval && newlen) {
 741                 len = newlen;
 742                 if (len > table->maxlen)
 743                         len = table->maxlen;
 744                 memcpy_fromfs(table->data, newval, len);
 745                 if (len == table->maxlen)
 746                         len--;
 747                 ((char *) table->data)[len] = 0;
 748         }
 749         return 0;
 750 }
 751 
 752 /*
 753  * This function makes sure that all of the integers in the vector
 754  * are between the minimum and maximum values given in the arrays
 755  * table->extra1 and table->extra2, respectively.
 756  */
 757 int sysctl_intvec(ctl_table *table, int *name, int nlen,
     /* [previous][next][first][last][top][bottom][index][help] */
 758                 void *oldval, size_t *oldlenp,
 759                 void *newval, size_t newlen, void **context)
 760 {
 761         int i, length, *vec, *min, *max;
 762 
 763         if (newval && newlen) {
 764                 if (newlen % sizeof(int) != 0)
 765                         return -EINVAL;
 766 
 767                 if (!table->extra1 && !table->extra2)
 768                         return 0;
 769 
 770                 if (newlen > table->maxlen)
 771                         newlen = table->maxlen;
 772                 length = newlen / sizeof(int);
 773 
 774                 vec = (int *) newval;
 775                 min = (int *) table->extra1;
 776                 max = (int *) table->extra2;
 777 
 778                 for (i = 0; i < length; i++) {
 779                         int value = get_user(vec + i);
 780                         if (min && value < min[i])
 781                                 return -EINVAL;
 782                         if (max && value > max[i])
 783                                 return -EINVAL;
 784                 }
 785         }
 786         return 0;
 787 }
 788 
 789 int do_string (
     /* [previous][next][first][last][top][bottom][index][help] */
 790         void *oldval, size_t *oldlenp, void *newval, size_t newlen,
 791         int rdwr, char *data, size_t max)
 792 {
 793         int l = strlen(data) + 1;
 794         if (newval && !rdwr)
 795                 return -EPERM;
 796         if (newval && newlen >= max)
 797                 return -EINVAL;
 798         if (oldval) {
 799                 if (l > get_user(oldlenp))
 800                         return -ENOMEM;
 801                 put_user(l, oldlenp);
 802                 memcpy_tofs(oldval, data, l);
 803         }
 804         if (newval) {
 805                 memcpy_fromfs(data, newval, newlen);
 806                 data[newlen] = 0;
 807         }
 808         return 0;
 809 }
 810 
 811 int do_int (
     /* [previous][next][first][last][top][bottom][index][help] */
 812         void *oldval, size_t *oldlenp, void *newval, size_t newlen,
 813         int rdwr, int *data)
 814 {
 815         if (newval && !rdwr)
 816                 return -EPERM;
 817         if (newval && newlen != sizeof(int))
 818                 return -EINVAL;
 819         if (oldval) {
 820                 if (get_user(oldlenp) < sizeof(int))
 821                         return -ENOMEM;
 822                 put_user(sizeof(int), oldlenp);
 823                 memcpy_tofs(oldval, data, sizeof(int));
 824         }
 825         if (newval)
 826                 memcpy_fromfs(data, newval, sizeof(int));
 827         return 0;
 828 }
 829 
 830 int do_struct (
     /* [previous][next][first][last][top][bottom][index][help] */
 831         void *oldval, size_t *oldlenp, void *newval, size_t newlen,
 832         int rdwr, void *data, size_t len)
 833 {
 834         if (newval && !rdwr)
 835                 return -EPERM;
 836         if (newval && newlen != len)
 837                 return -EINVAL;
 838         if (oldval) {
 839                 if (get_user(oldlenp) < len)
 840                         return -ENOMEM;
 841                 put_user(len, oldlenp);
 842                 memcpy_tofs(oldval, data, len);
 843         }
 844         if (newval)
 845                 memcpy_fromfs(data, newval, len);
 846         return 0;
 847 }
 848 

/* [previous][next][first][last][top][bottom][index][help] */