OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [kernel/] [sysctl.c] - Blame information for rev 1767

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.