Commit | Line | Data |
---|---|---|
59d8053f | 1 | /* Internal procfs definitions |
1da177e4 LT |
2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | |
4 | * Written by David Howells (dhowells@redhat.com) | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the License, or (at your option) any later version. | |
10 | */ | |
11 | ||
12 | #include <linux/proc_fs.h> | |
59d8053f DH |
13 | #include <linux/proc_ns.h> |
14 | #include <linux/spinlock.h> | |
15 | #include <linux/atomic.h> | |
e579d2c2 | 16 | #include <linux/binfmts.h> |
1da177e4 | 17 | |
59d8053f DH |
18 | struct ctl_table_header; |
19 | struct mempolicy; | |
77b14db5 | 20 | |
59d8053f DH |
21 | /* |
22 | * This is not completely implemented yet. The idea is to | |
23 | * create an in-memory tree (like the actual /proc filesystem | |
24 | * tree) of these proc_dir_entries, so that we can dynamically | |
25 | * add new files to /proc. | |
26 | * | |
27 | * The "next" pointer creates a linked list of one /proc directory, | |
28 | * while parent/subdir create the directory structure (every | |
29 | * /proc file has a parent, but "subdir" is NULL for all | |
30 | * non-directory entries). | |
31 | */ | |
32 | struct proc_dir_entry { | |
33 | unsigned int low_ino; | |
34 | umode_t mode; | |
35 | nlink_t nlink; | |
36 | kuid_t uid; | |
37 | kgid_t gid; | |
38 | loff_t size; | |
39 | const struct inode_operations *proc_iops; | |
40 | const struct file_operations *proc_fops; | |
41 | struct proc_dir_entry *next, *parent, *subdir; | |
42 | void *data; | |
43 | atomic_t count; /* use count */ | |
44 | atomic_t in_use; /* number of callers into module in progress; */ | |
45 | /* negative -> it's going away RSN */ | |
46 | struct completion *pde_unload_completion; | |
47 | struct list_head pde_openers; /* who did ->open, but not ->release */ | |
48 | spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */ | |
49 | u8 namelen; | |
50 | char name[]; | |
1da177e4 | 51 | }; |
1da177e4 | 52 | |
59d8053f DH |
53 | union proc_op { |
54 | int (*proc_get_link)(struct dentry *, struct path *); | |
55 | int (*proc_read)(struct task_struct *task, char *page); | |
56 | int (*proc_show)(struct seq_file *m, | |
57 | struct pid_namespace *ns, struct pid *pid, | |
58 | struct task_struct *task); | |
59 | }; | |
99f89551 | 60 | |
59d8053f | 61 | struct proc_inode { |
f2beb798 | 62 | struct pid *pid; |
59d8053f DH |
63 | int fd; |
64 | union proc_op op; | |
65 | struct proc_dir_entry *pde; | |
66 | struct ctl_table_header *sysctl; | |
67 | struct ctl_table *sysctl_entry; | |
68 | struct proc_ns ns; | |
69 | struct inode vfs_inode; | |
f2beb798 SW |
70 | }; |
71 | ||
c30480b9 DH |
72 | /* |
73 | * General functions | |
74 | */ | |
75 | static inline struct proc_inode *PROC_I(const struct inode *inode) | |
76 | { | |
77 | return container_of(inode, struct proc_inode, vfs_inode); | |
78 | } | |
79 | ||
80 | static inline struct proc_dir_entry *PDE(const struct inode *inode) | |
81 | { | |
82 | return PROC_I(inode)->pde; | |
83 | } | |
84 | ||
85 | static inline void *__PDE_DATA(const struct inode *inode) | |
86 | { | |
87 | return PDE(inode)->data; | |
88 | } | |
fee781e6 | 89 | |
13b41b09 | 90 | static inline struct pid *proc_pid(struct inode *inode) |
99f89551 | 91 | { |
13b41b09 | 92 | return PROC_I(inode)->pid; |
99f89551 EB |
93 | } |
94 | ||
95 | static inline struct task_struct *get_proc_task(struct inode *inode) | |
1da177e4 | 96 | { |
13b41b09 | 97 | return get_pid_task(proc_pid(inode), PIDTYPE_PID); |
1da177e4 LT |
98 | } |
99 | ||
faf60af1 CG |
100 | static inline int task_dumpable(struct task_struct *task) |
101 | { | |
102 | int dumpable = 0; | |
103 | struct mm_struct *mm; | |
104 | ||
105 | task_lock(task); | |
106 | mm = task->mm; | |
107 | if (mm) | |
108 | dumpable = get_dumpable(mm); | |
109 | task_unlock(task); | |
e579d2c2 | 110 | if (dumpable == SUID_DUMP_USER) |
faf60af1 CG |
111 | return 1; |
112 | return 0; | |
113 | } | |
114 | ||
faf60af1 CG |
115 | static inline unsigned name_to_int(struct dentry *dentry) |
116 | { | |
117 | const char *name = dentry->d_name.name; | |
118 | int len = dentry->d_name.len; | |
119 | unsigned n = 0; | |
120 | ||
121 | if (len > 1 && *name == '0') | |
122 | goto out; | |
123 | while (len-- > 0) { | |
124 | unsigned c = *name++ - '0'; | |
125 | if (c > 9) | |
126 | goto out; | |
127 | if (n >= (~0U-9)/10) | |
128 | goto out; | |
129 | n *= 10; | |
130 | n += c; | |
131 | } | |
132 | return n; | |
133 | out: | |
134 | return ~0U; | |
135 | } | |
136 | ||
1dd704b6 | 137 | /* |
59d8053f | 138 | * Offset of the first process in the /proc root directory.. |
1dd704b6 | 139 | */ |
59d8053f | 140 | #define FIRST_PROCESS_ENTRY 256 |
1dd704b6 | 141 | |
59d8053f DH |
142 | /* Worst case buffer size needed for holding an integer. */ |
143 | #define PROC_NUMBUF 13 | |
881adb85 | 144 | |
59d8053f DH |
145 | /* |
146 | * array.c | |
147 | */ | |
148 | extern const struct file_operations proc_tid_children_operations; | |
3174c21b | 149 | |
59d8053f DH |
150 | extern int proc_tid_stat(struct seq_file *, struct pid_namespace *, |
151 | struct pid *, struct task_struct *); | |
152 | extern int proc_tgid_stat(struct seq_file *, struct pid_namespace *, | |
153 | struct pid *, struct task_struct *); | |
154 | extern int proc_pid_status(struct seq_file *, struct pid_namespace *, | |
155 | struct pid *, struct task_struct *); | |
156 | extern int proc_pid_statm(struct seq_file *, struct pid_namespace *, | |
157 | struct pid *, struct task_struct *); | |
158 | ||
159 | /* | |
160 | * base.c | |
161 | */ | |
162 | extern const struct dentry_operations pid_dentry_operations; | |
163 | extern int pid_getattr(struct vfsmount *, struct dentry *, struct kstat *); | |
164 | extern int proc_setattr(struct dentry *, struct iattr *); | |
165 | extern struct inode *proc_pid_make_inode(struct super_block *, struct task_struct *); | |
166 | extern int pid_revalidate(struct dentry *, unsigned int); | |
167 | extern int pid_delete_dentry(const struct dentry *); | |
f0c3b509 | 168 | extern int proc_pid_readdir(struct file *, struct dir_context *); |
59d8053f DH |
169 | extern struct dentry *proc_pid_lookup(struct inode *, struct dentry *, unsigned int); |
170 | extern loff_t mem_lseek(struct file *, loff_t, int); | |
866ad9a7 | 171 | |
59d8053f | 172 | /* Lookups */ |
c52a47ac | 173 | typedef int instantiate_t(struct inode *, struct dentry *, |
59d8053f | 174 | struct task_struct *, const void *); |
f0c3b509 | 175 | extern bool proc_fill_cache(struct file *, struct dir_context *, const char *, int, |
59d8053f | 176 | instantiate_t, struct task_struct *, const void *); |
3174c21b | 177 | |
59d8053f DH |
178 | /* |
179 | * generic.c | |
180 | */ | |
3174c21b AV |
181 | extern spinlock_t proc_subdir_lock; |
182 | ||
59d8053f DH |
183 | extern struct dentry *proc_lookup(struct inode *, struct dentry *, unsigned int); |
184 | extern struct dentry *proc_lookup_de(struct proc_dir_entry *, struct inode *, | |
185 | struct dentry *); | |
f0c3b509 AV |
186 | extern int proc_readdir(struct file *, struct dir_context *); |
187 | extern int proc_readdir_de(struct proc_dir_entry *, struct file *, struct dir_context *); | |
3174c21b | 188 | |
135d5655 AD |
189 | static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) |
190 | { | |
191 | atomic_inc(&pde->count); | |
192 | return pde; | |
193 | } | |
59d8053f | 194 | extern void pde_put(struct proc_dir_entry *); |
3174c21b AV |
195 | |
196 | /* | |
59d8053f | 197 | * inode.c |
3174c21b | 198 | */ |
59d8053f DH |
199 | struct pde_opener { |
200 | struct file *file; | |
201 | struct list_head lh; | |
202 | int closing; | |
203 | struct completion *c; | |
204 | }; | |
6b4e306a | 205 | |
59d8053f | 206 | extern const struct inode_operations proc_pid_link_inode_operations; |
6b4e306a | 207 | |
59d8053f DH |
208 | extern void proc_init_inodecache(void); |
209 | extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); | |
210 | extern int proc_fill_super(struct super_block *); | |
211 | extern void proc_entry_rundown(struct proc_dir_entry *); | |
6b4e306a | 212 | |
59d8053f DH |
213 | /* |
214 | * proc_devtree.c | |
215 | */ | |
216 | #ifdef CONFIG_PROC_DEVICETREE | |
217 | extern void proc_device_tree_init(void); | |
218 | #endif | |
6b4e306a | 219 | |
59d8053f DH |
220 | /* |
221 | * proc_namespaces.c | |
222 | */ | |
6b4e306a EB |
223 | extern const struct inode_operations proc_ns_dir_inode_operations; |
224 | extern const struct file_operations proc_ns_dir_operations; | |
225 | ||
59d8053f DH |
226 | /* |
227 | * proc_net.c | |
228 | */ | |
229 | extern const struct file_operations proc_net_operations; | |
230 | extern const struct inode_operations proc_net_inode_operations; | |
231 | ||
232 | #ifdef CONFIG_NET | |
233 | extern int proc_net_init(void); | |
234 | #else | |
235 | static inline int proc_net_init(void) { return 0; } | |
236 | #endif | |
237 | ||
238 | /* | |
239 | * proc_self.c | |
240 | */ | |
021ada7d | 241 | extern int proc_setup_self(struct super_block *); |
34db8aaf DH |
242 | |
243 | /* | |
59d8053f | 244 | * proc_sysctl.c |
34db8aaf | 245 | */ |
59d8053f DH |
246 | #ifdef CONFIG_PROC_SYSCTL |
247 | extern int proc_sys_init(void); | |
248 | extern void sysctl_head_put(struct ctl_table_header *); | |
249 | #else | |
250 | static inline void proc_sys_init(void) { } | |
251 | static inline void sysctl_head_put(struct ctl_table_header *head) { } | |
252 | #endif | |
34db8aaf DH |
253 | |
254 | /* | |
255 | * proc_tty.c | |
256 | */ | |
257 | #ifdef CONFIG_TTY | |
258 | extern void proc_tty_init(void); | |
259 | #else | |
260 | static inline void proc_tty_init(void) {} | |
261 | #endif | |
59d8053f DH |
262 | |
263 | /* | |
264 | * root.c | |
265 | */ | |
266 | extern struct proc_dir_entry proc_root; | |
267 | ||
268 | extern void proc_self_init(void); | |
269 | extern int proc_remount(struct super_block *, int *, char *); | |
270 | ||
271 | /* | |
272 | * task_[no]mmu.c | |
273 | */ | |
274 | struct proc_maps_private { | |
275 | struct pid *pid; | |
276 | struct task_struct *task; | |
277 | #ifdef CONFIG_MMU | |
278 | struct vm_area_struct *tail_vma; | |
279 | #endif | |
280 | #ifdef CONFIG_NUMA | |
281 | struct mempolicy *task_mempolicy; | |
282 | #endif | |
283 | }; | |
284 | ||
285 | extern const struct file_operations proc_pid_maps_operations; | |
286 | extern const struct file_operations proc_tid_maps_operations; | |
287 | extern const struct file_operations proc_pid_numa_maps_operations; | |
288 | extern const struct file_operations proc_tid_numa_maps_operations; | |
289 | extern const struct file_operations proc_pid_smaps_operations; | |
290 | extern const struct file_operations proc_tid_smaps_operations; | |
291 | extern const struct file_operations proc_clear_refs_operations; | |
292 | extern const struct file_operations proc_pagemap_operations; | |
293 | ||
294 | extern unsigned long task_vsize(struct mm_struct *); | |
295 | extern unsigned long task_statm(struct mm_struct *, | |
296 | unsigned long *, unsigned long *, | |
297 | unsigned long *, unsigned long *); | |
298 | extern void task_mem(struct seq_file *, struct mm_struct *); |