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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [fs/] [proc/] [proc_sysctl.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * /proc/sys support
3
 */
4
 
5
#include <linux/sysctl.h>
6
#include <linux/proc_fs.h>
7
#include <linux/security.h>
8
#include "internal.h"
9
 
10
static struct dentry_operations proc_sys_dentry_operations;
11
static const struct file_operations proc_sys_file_operations;
12
static struct inode_operations proc_sys_inode_operations;
13
 
14
static void proc_sys_refresh_inode(struct inode *inode, struct ctl_table *table)
15
{
16
        /* Refresh the cached information bits in the inode */
17
        if (table) {
18
                inode->i_uid = 0;
19
                inode->i_gid = 0;
20
                inode->i_mode = table->mode;
21
                if (table->proc_handler) {
22
                        inode->i_mode |= S_IFREG;
23
                        inode->i_nlink = 1;
24
                } else {
25
                        inode->i_mode |= S_IFDIR;
26
                        inode->i_nlink = 0;      /* It is too hard to figure out */
27
                }
28
        }
29
}
30
 
31
static struct inode *proc_sys_make_inode(struct inode *dir, struct ctl_table *table)
32
{
33
        struct inode *inode;
34
        struct proc_inode *dir_ei, *ei;
35
        int depth;
36
 
37
        inode = new_inode(dir->i_sb);
38
        if (!inode)
39
                goto out;
40
 
41
        /* A directory is always one deeper than it's parent */
42
        dir_ei = PROC_I(dir);
43
        depth = dir_ei->fd + 1;
44
 
45
        ei = PROC_I(inode);
46
        ei->fd = depth;
47
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
48
        inode->i_op = &proc_sys_inode_operations;
49
        inode->i_fop = &proc_sys_file_operations;
50
        inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */
51
        proc_sys_refresh_inode(inode, table);
52
out:
53
        return inode;
54
}
55
 
56
static struct dentry *proc_sys_ancestor(struct dentry *dentry, int depth)
57
{
58
        for (;;) {
59
                struct proc_inode *ei;
60
 
61
                ei = PROC_I(dentry->d_inode);
62
                if (ei->fd == depth)
63
                        break; /* found */
64
 
65
                dentry = dentry->d_parent;
66
        }
67
        return dentry;
68
}
69
 
70
static struct ctl_table *proc_sys_lookup_table_one(struct ctl_table *table,
71
                                                        struct qstr *name)
72
{
73
        int len;
74
        for ( ; table->ctl_name || table->procname; table++) {
75
 
76
                if (!table->procname)
77
                        continue;
78
 
79
                len = strlen(table->procname);
80
                if (len != name->len)
81
                        continue;
82
 
83
                if (memcmp(table->procname, name->name, len) != 0)
84
                        continue;
85
 
86
                /* I have a match */
87
                return table;
88
        }
89
        return NULL;
90
}
91
 
92
static struct ctl_table *proc_sys_lookup_table(struct dentry *dentry,
93
                                                struct ctl_table *table)
94
{
95
        struct dentry *ancestor;
96
        struct proc_inode *ei;
97
        int depth, i;
98
 
99
        ei = PROC_I(dentry->d_inode);
100
        depth = ei->fd;
101
 
102
        if (depth == 0)
103
                return table;
104
 
105
        for (i = 1; table && (i <= depth); i++) {
106
                ancestor = proc_sys_ancestor(dentry, i);
107
                table = proc_sys_lookup_table_one(table, &ancestor->d_name);
108
                if (table)
109
                        table = table->child;
110
        }
111
        return table;
112
 
113
}
114
static struct ctl_table *proc_sys_lookup_entry(struct dentry *dparent,
115
                                                struct qstr *name,
116
                                                struct ctl_table *table)
117
{
118
        table = proc_sys_lookup_table(dparent, table);
119
        if (table)
120
                table = proc_sys_lookup_table_one(table, name);
121
        return table;
122
}
123
 
124
static struct ctl_table *do_proc_sys_lookup(struct dentry *parent,
125
                                                struct qstr *name,
126
                                                struct ctl_table_header **ptr)
127
{
128
        struct ctl_table_header *head;
129
        struct ctl_table *table = NULL;
130
 
131
        for (head = sysctl_head_next(NULL); head;
132
                        head = sysctl_head_next(head)) {
133
                table = proc_sys_lookup_entry(parent, name, head->ctl_table);
134
                if (table)
135
                        break;
136
        }
137
        *ptr = head;
138
        return table;
139
}
140
 
141
static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
142
                                        struct nameidata *nd)
143
{
144
        struct ctl_table_header *head;
145
        struct inode *inode;
146
        struct dentry *err;
147
        struct ctl_table *table;
148
 
149
        err = ERR_PTR(-ENOENT);
150
        table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
151
        if (!table)
152
                goto out;
153
 
154
        err = ERR_PTR(-ENOMEM);
155
        inode = proc_sys_make_inode(dir, table);
156
        if (!inode)
157
                goto out;
158
 
159
        err = NULL;
160
        dentry->d_op = &proc_sys_dentry_operations;
161
        d_add(dentry, inode);
162
 
163
out:
164
        sysctl_head_finish(head);
165
        return err;
166
}
167
 
168
static ssize_t proc_sys_read(struct file *filp, char __user *buf,
169
                                size_t count, loff_t *ppos)
170
{
171
        struct dentry *dentry = filp->f_dentry;
172
        struct ctl_table_header *head;
173
        struct ctl_table *table;
174
        ssize_t error;
175
        size_t res;
176
 
177
        table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
178
        /* Has the sysctl entry disappeared on us? */
179
        error = -ENOENT;
180
        if (!table)
181
                goto out;
182
 
183
        /* Has the sysctl entry been replaced by a directory? */
184
        error = -EISDIR;
185
        if (!table->proc_handler)
186
                goto out;
187
 
188
        /*
189
         * At this point we know that the sysctl was not unregistered
190
         * and won't be until we finish.
191
         */
192
        error = -EPERM;
193
        if (sysctl_perm(table, MAY_READ))
194
                goto out;
195
 
196
        /* careful: calling conventions are nasty here */
197
        res = count;
198
        error = table->proc_handler(table, 0, filp, buf, &res, ppos);
199
        if (!error)
200
                error = res;
201
out:
202
        sysctl_head_finish(head);
203
 
204
        return error;
205
}
206
 
207
static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
208
                                size_t count, loff_t *ppos)
209
{
210
        struct dentry *dentry = filp->f_dentry;
211
        struct ctl_table_header *head;
212
        struct ctl_table *table;
213
        ssize_t error;
214
        size_t res;
215
 
216
        table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
217
        /* Has the sysctl entry disappeared on us? */
218
        error = -ENOENT;
219
        if (!table)
220
                goto out;
221
 
222
        /* Has the sysctl entry been replaced by a directory? */
223
        error = -EISDIR;
224
        if (!table->proc_handler)
225
                goto out;
226
 
227
        /*
228
         * At this point we know that the sysctl was not unregistered
229
         * and won't be until we finish.
230
         */
231
        error = -EPERM;
232
        if (sysctl_perm(table, MAY_WRITE))
233
                goto out;
234
 
235
        /* careful: calling conventions are nasty here */
236
        res = count;
237
        error = table->proc_handler(table, 1, filp, (char __user *)buf,
238
                                    &res, ppos);
239
        if (!error)
240
                error = res;
241
out:
242
        sysctl_head_finish(head);
243
 
244
        return error;
245
}
246
 
247
 
248
static int proc_sys_fill_cache(struct file *filp, void *dirent,
249
                                filldir_t filldir, struct ctl_table *table)
250
{
251
        struct ctl_table_header *head;
252
        struct ctl_table *child_table = NULL;
253
        struct dentry *child, *dir = filp->f_path.dentry;
254
        struct inode *inode;
255
        struct qstr qname;
256
        ino_t ino = 0;
257
        unsigned type = DT_UNKNOWN;
258
        int ret;
259
 
260
        qname.name = table->procname;
261
        qname.len  = strlen(table->procname);
262
        qname.hash = full_name_hash(qname.name, qname.len);
263
 
264
        /* Suppress duplicates.
265
         * Only fill a directory entry if it is the value that
266
         * an ordinary lookup of that name returns.  Hide all
267
         * others.
268
         *
269
         * If we ever cache this translation in the dcache
270
         * I should do a dcache lookup first.  But for now
271
         * it is just simpler not to.
272
         */
273
        ret = 0;
274
        child_table = do_proc_sys_lookup(dir, &qname, &head);
275
        sysctl_head_finish(head);
276
        if (child_table != table)
277
                return 0;
278
 
279
        child = d_lookup(dir, &qname);
280
        if (!child) {
281
                struct dentry *new;
282
                new = d_alloc(dir, &qname);
283
                if (new) {
284
                        inode = proc_sys_make_inode(dir->d_inode, table);
285
                        if (!inode)
286
                                child = ERR_PTR(-ENOMEM);
287
                        else {
288
                                new->d_op = &proc_sys_dentry_operations;
289
                                d_add(new, inode);
290
                        }
291
                        if (child)
292
                                dput(new);
293
                        else
294
                                child = new;
295
                }
296
        }
297
        if (!child || IS_ERR(child) || !child->d_inode)
298
                goto end_instantiate;
299
        inode = child->d_inode;
300
        if (inode) {
301
                ino  = inode->i_ino;
302
                type = inode->i_mode >> 12;
303
        }
304
        dput(child);
305
end_instantiate:
306
        if (!ino)
307
                ino= find_inode_number(dir, &qname);
308
        if (!ino)
309
                ino = 1;
310
        return filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type);
311
}
312
 
313
static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir)
314
{
315
        struct dentry *dentry = filp->f_dentry;
316
        struct inode *inode = dentry->d_inode;
317
        struct ctl_table_header *head = NULL;
318
        struct ctl_table *table;
319
        unsigned long pos;
320
        int ret;
321
 
322
        ret = -ENOTDIR;
323
        if (!S_ISDIR(inode->i_mode))
324
                goto out;
325
 
326
        ret = 0;
327
        /* Avoid a switch here: arm builds fail with missing __cmpdi2 */
328
        if (filp->f_pos == 0) {
329
                if (filldir(dirent, ".", 1, filp->f_pos,
330
                                inode->i_ino, DT_DIR) < 0)
331
                        goto out;
332
                filp->f_pos++;
333
        }
334
        if (filp->f_pos == 1) {
335
                if (filldir(dirent, "..", 2, filp->f_pos,
336
                                parent_ino(dentry), DT_DIR) < 0)
337
                        goto out;
338
                filp->f_pos++;
339
        }
340
        pos = 2;
341
 
342
        /* - Find each instance of the directory
343
         * - Read all entries in each instance
344
         * - Before returning an entry to user space lookup the entry
345
         *   by name and if I find a different entry don't return
346
         *   this one because it means it is a buried dup.
347
         * For sysctl this should only happen for directory entries.
348
         */
349
        for (head = sysctl_head_next(NULL); head; head = sysctl_head_next(head)) {
350
                table = proc_sys_lookup_table(dentry, head->ctl_table);
351
 
352
                if (!table)
353
                        continue;
354
 
355
                for (; table->ctl_name || table->procname; table++, pos++) {
356
                        /* Can't do anything without a proc name */
357
                        if (!table->procname)
358
                                continue;
359
 
360
                        if (pos < filp->f_pos)
361
                                continue;
362
 
363
                        if (proc_sys_fill_cache(filp, dirent, filldir, table) < 0)
364
                                goto out;
365
                        filp->f_pos = pos + 1;
366
                }
367
        }
368
        ret = 1;
369
out:
370
        sysctl_head_finish(head);
371
        return ret;
372
}
373
 
374
static int proc_sys_permission(struct inode *inode, int mask, struct nameidata *nd)
375
{
376
        /*
377
         * sysctl entries that are not writeable,
378
         * are _NOT_ writeable, capabilities or not.
379
         */
380
        struct ctl_table_header *head;
381
        struct ctl_table *table;
382
        struct dentry *dentry;
383
        int mode;
384
        int depth;
385
        int error;
386
 
387
        head = NULL;
388
        depth = PROC_I(inode)->fd;
389
 
390
        /* First check the cached permissions, in case we don't have
391
         * enough information to lookup the sysctl table entry.
392
         */
393
        error = -EACCES;
394
        mode = inode->i_mode;
395
 
396
        if (current->euid == 0)
397
                mode >>= 6;
398
        else if (in_group_p(0))
399
                mode >>= 3;
400
 
401
        if ((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask)
402
                error = 0;
403
 
404
        /* If we can't get a sysctl table entry the permission
405
         * checks on the cached mode will have to be enough.
406
         */
407
        if (!nd || !depth)
408
                goto out;
409
 
410
        dentry = nd->dentry;
411
        table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
412
 
413
        /* If the entry does not exist deny permission */
414
        error = -EACCES;
415
        if (!table)
416
                goto out;
417
 
418
        /* Use the permissions on the sysctl table entry */
419
        error = sysctl_perm(table, mask);
420
out:
421
        sysctl_head_finish(head);
422
        return error;
423
}
424
 
425
static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
426
{
427
        struct inode *inode = dentry->d_inode;
428
        int error;
429
 
430
        if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
431
                return -EPERM;
432
 
433
        error = inode_change_ok(inode, attr);
434
        if (!error)
435
                error = inode_setattr(inode, attr);
436
 
437
        return error;
438
}
439
 
440
/* I'm lazy and don't distinguish between files and directories,
441
 * until access time.
442
 */
443
static const struct file_operations proc_sys_file_operations = {
444
        .read           = proc_sys_read,
445
        .write          = proc_sys_write,
446
        .readdir        = proc_sys_readdir,
447
};
448
 
449
static struct inode_operations proc_sys_inode_operations = {
450
        .lookup         = proc_sys_lookup,
451
        .permission     = proc_sys_permission,
452
        .setattr        = proc_sys_setattr,
453
};
454
 
455
static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd)
456
{
457
        struct ctl_table_header *head;
458
        struct ctl_table *table;
459
        table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
460
        proc_sys_refresh_inode(dentry->d_inode, table);
461
        sysctl_head_finish(head);
462
        return !!table;
463
}
464
 
465
static struct dentry_operations proc_sys_dentry_operations = {
466
        .d_revalidate   = proc_sys_revalidate,
467
};
468
 
469
static struct proc_dir_entry *proc_sys_root;
470
 
471
int proc_sys_init(void)
472
{
473
        proc_sys_root = proc_mkdir("sys", NULL);
474
        proc_sys_root->proc_iops = &proc_sys_inode_operations;
475
        proc_sys_root->proc_fops = &proc_sys_file_operations;
476
        proc_sys_root->nlink = 0;
477
        return 0;
478
}

powered by: WebSVN 2.1.0

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