Commit | Line | Data |
---|---|---|
e656d8a6 EB |
1 | #include <linux/proc_fs.h> |
2 | #include <linux/sched.h> | |
3 | #include <linux/namei.h> | |
4 | ||
5 | /* | |
6 | * /proc/self: | |
7 | */ | |
8 | static int proc_self_readlink(struct dentry *dentry, char __user *buffer, | |
9 | int buflen) | |
10 | { | |
11 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; | |
12 | pid_t tgid = task_tgid_nr_ns(current, ns); | |
13 | char tmp[PROC_NUMBUF]; | |
14 | if (!tgid) | |
15 | return -ENOENT; | |
16 | sprintf(tmp, "%d", tgid); | |
17 | return vfs_readlink(dentry,buffer,buflen,tmp); | |
18 | } | |
19 | ||
20 | static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) | |
21 | { | |
22 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; | |
23 | pid_t tgid = task_tgid_nr_ns(current, ns); | |
24 | char *name = ERR_PTR(-ENOENT); | |
25 | if (tgid) { | |
26 | /* 11 for max length of signed int in decimal + NULL term */ | |
27 | name = kmalloc(12, GFP_KERNEL); | |
28 | if (!name) | |
29 | name = ERR_PTR(-ENOMEM); | |
30 | else | |
31 | sprintf(name, "%d", tgid); | |
32 | } | |
33 | nd_set_link(nd, name); | |
34 | return NULL; | |
35 | } | |
36 | ||
37 | static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd, | |
38 | void *cookie) | |
39 | { | |
40 | char *s = nd_get_link(nd); | |
41 | if (!IS_ERR(s)) | |
42 | kfree(s); | |
43 | } | |
44 | ||
45 | static const struct inode_operations proc_self_inode_operations = { | |
46 | .readlink = proc_self_readlink, | |
47 | .follow_link = proc_self_follow_link, | |
48 | .put_link = proc_self_put_link, | |
49 | }; | |
50 | ||
51 | void __init proc_self_init(void) | |
52 | { | |
53 | struct proc_dir_entry *proc_self_symlink; | |
0ecc833b | 54 | umode_t mode; |
e656d8a6 EB |
55 | |
56 | mode = S_IFLNK | S_IRWXUGO; | |
57 | proc_self_symlink = proc_create("self", mode, NULL, NULL ); | |
58 | proc_self_symlink->proc_iops = &proc_self_inode_operations; | |
59 | } |