8fdd30c625ce5e2444243527ca9e64d09c92e4bd
[linux-2.6.git] / kernel / vserver / inode.c
1 /*
2  *  linux/kernel/vserver/inode.c
3  *
4  *  Virtual Server: File System Support
5  *
6  *  Copyright (C) 2004  Herbert Pötzl
7  *
8  *  V0.01  separated from vcontext V0.05
9  *
10  */
11
12 #include <linux/config.h>
13 #include <linux/sched.h>
14 #include <linux/vs_context.h>
15 #include <linux/proc_fs.h>
16 #include <linux/devpts_fs.h>
17 #include <linux/namei.h>
18 #include <linux/mount.h>
19 #include <linux/parser.h>
20 #include <linux/vserver/inode.h>
21 #include <linux/vserver/xid.h>
22
23 #include <asm/errno.h>
24 #include <asm/uaccess.h>
25
26
27 static int __vc_get_iattr(struct inode *in, uint32_t *xid, uint32_t *flags, uint32_t *mask)
28 {
29         struct proc_dir_entry *entry;
30
31         if (!in || !in->i_sb)
32                 return -ESRCH;
33
34         *flags = IATTR_XID
35                 | (IS_BARRIER(in) ? IATTR_BARRIER : 0)
36                 | (IS_IUNLINK(in) ? IATTR_IUNLINK : 0)
37                 | (IS_IMMUTABLE(in) ? IATTR_IMMUTABLE : 0);
38         *mask = IATTR_IUNLINK | IATTR_IMMUTABLE;
39
40         if (S_ISDIR(in->i_mode))
41                 *mask |= IATTR_BARRIER;
42
43         if (in->i_sb->s_flags & MS_TAGXID) {
44                 *xid = in->i_xid;
45                 *mask |= IATTR_XID;
46         }
47
48         switch (in->i_sb->s_magic) {
49         case PROC_SUPER_MAGIC:
50                 entry = PROC_I(in)->pde;
51
52                 // check for specific inodes ?
53                 if (entry)
54                         *mask |= IATTR_FLAGS;
55                 if (entry)
56                         *flags |= (entry->vx_flags & IATTR_FLAGS);
57                 else
58                         *flags |= (PROC_I(in)->vx_flags & IATTR_FLAGS);
59                 break;
60
61         case DEVPTS_SUPER_MAGIC:
62                 *xid = in->i_xid;
63                 *mask |= IATTR_XID;
64                 break;
65
66         default:
67                 break;
68         }
69         return 0;
70 }
71
72 int vc_get_iattr(uint32_t id, void __user *data)
73 {
74         struct nameidata nd;
75         struct vcmd_ctx_iattr_v1 vc_data = { .xid = -1 };
76         int ret;
77
78         if (!vx_check(0, VX_ADMIN))
79                 return -ENOSYS;
80         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
81                 return -EFAULT;
82
83         ret = user_path_walk_link(vc_data.name, &nd);
84         if (!ret) {
85                 ret = __vc_get_iattr(nd.dentry->d_inode,
86                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
87                 path_release(&nd);
88         }
89
90         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
91                 ret = -EFAULT;
92         return ret;
93 }
94
95 static int __vc_set_iattr(struct dentry *de, uint32_t *xid, uint32_t *flags, uint32_t *mask)
96 {
97         struct inode *in = de->d_inode;
98         int error = 0, is_proc = 0, has_xid = 0;
99
100         if (!in || !in->i_sb)
101                 return -ESRCH;
102
103         is_proc = (in->i_sb->s_magic == PROC_SUPER_MAGIC);
104         if ((*mask & IATTR_FLAGS) && !is_proc)
105                 return -EINVAL;
106
107         has_xid = (in->i_sb->s_flags & MS_TAGXID) ||
108                 (in->i_sb->s_magic == DEVPTS_SUPER_MAGIC);
109         if ((*mask & IATTR_XID) && !has_xid)
110                 return -EINVAL;
111
112         down(&in->i_sem);
113         if (*mask & IATTR_XID)
114                 in->i_xid = *xid;
115
116         if (*mask & IATTR_FLAGS) {
117                 struct proc_dir_entry *entry = PROC_I(in)->pde;
118                 unsigned int iflags = PROC_I(in)->vx_flags;
119
120                 iflags = (iflags & ~(*mask & IATTR_FLAGS))
121                         | (*flags & IATTR_FLAGS);
122                 PROC_I(in)->vx_flags = iflags;
123                 if (entry)
124                         entry->vx_flags = iflags;
125         }
126
127         if (*mask & (IATTR_BARRIER | IATTR_IUNLINK | IATTR_IMMUTABLE)) {
128                 struct iattr attr;
129
130                 attr.ia_valid = ATTR_ATTR_FLAG;
131                 attr.ia_attr_flags =
132                         (IS_IMMUTABLE(in) ? ATTR_FLAG_IMMUTABLE : 0) |
133                         (IS_IUNLINK(in) ? ATTR_FLAG_IUNLINK : 0) |
134                         (IS_BARRIER(in) ? ATTR_FLAG_BARRIER : 0);
135
136                 if (*mask & IATTR_IMMUTABLE) {
137                         if (*flags & IATTR_IMMUTABLE)
138                                 attr.ia_attr_flags |= ATTR_FLAG_IMMUTABLE;
139                         else
140                                 attr.ia_attr_flags &= ~ATTR_FLAG_IMMUTABLE;
141                 }
142                 if (*mask & IATTR_IUNLINK) {
143                         if (*flags & IATTR_IUNLINK)
144                                 attr.ia_attr_flags |= ATTR_FLAG_IUNLINK;
145                         else
146                                 attr.ia_attr_flags &= ~ATTR_FLAG_IUNLINK;
147                 }
148                 if (S_ISDIR(in->i_mode) && (*mask & IATTR_BARRIER)) {
149                         if (*flags & IATTR_BARRIER)
150                                 attr.ia_attr_flags |= ATTR_FLAG_BARRIER;
151                         else
152                                 attr.ia_attr_flags &= ~ATTR_FLAG_BARRIER;
153                 }
154                 if (in->i_op && in->i_op->setattr)
155                         error = in->i_op->setattr(de, &attr);
156                 else {
157                         error = inode_change_ok(in, &attr);
158                         if (!error)
159                                 error = inode_setattr(in, &attr);
160                 }
161         }
162
163         mark_inode_dirty(in);
164         up(&in->i_sem);
165         return 0;
166 }
167
168 int vc_set_iattr(uint32_t id, void __user *data)
169 {
170         struct nameidata nd;
171         struct vcmd_ctx_iattr_v1 vc_data;
172         int ret;
173
174         if (!capable(CAP_SYS_ADMIN) || !capable(CAP_LINUX_IMMUTABLE))
175                 return -EPERM;
176         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
177                 return -EFAULT;
178
179         ret = user_path_walk_link(vc_data.name, &nd);
180         if (!ret) {
181                 ret = __vc_set_iattr(nd.dentry,
182                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
183                 path_release(&nd);
184         }
185
186         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
187                 ret = -EFAULT;
188         return ret;
189 }
190
191
192 #ifdef  CONFIG_VSERVER_LEGACY
193
194 #define PROC_DYNAMIC_FIRST 0xF0000000UL
195
196 int vx_proc_ioctl(struct inode * inode, struct file * filp,
197         unsigned int cmd, unsigned long arg)
198 {
199         struct proc_dir_entry *entry;
200         int error = 0;
201         int flags;
202
203         if (inode->i_ino < PROC_DYNAMIC_FIRST)
204                 return -ENOTTY;
205
206         entry = PROC_I(inode)->pde;
207         if (!entry)
208                 return -ENOTTY;
209
210         switch(cmd) {
211         case FIOC_GETXFLG: {
212                 /* fixme: if stealth, return -ENOTTY */
213                 error = -EPERM;
214                 flags = entry->vx_flags;
215                 if (capable(CAP_CONTEXT))
216                         error = put_user(flags, (int *) arg);
217                 break;
218         }
219         case FIOC_SETXFLG: {
220                 /* fixme: if stealth, return -ENOTTY */
221                 error = -EPERM;
222                 if (!capable(CAP_CONTEXT))
223                         break;
224                 error = -EROFS;
225                 if (IS_RDONLY(inode))
226                         break;
227                 error = -EFAULT;
228                 if (get_user(flags, (int *) arg))
229                         break;
230                 error = 0;
231                 entry->vx_flags = flags;
232                 break;
233         }
234         default:
235                 return -ENOTTY;
236         }
237         return error;
238 }
239 #endif
240
241
242 int vx_parse_xid(char *string, xid_t *xid, int remove)
243 {
244         static match_table_t tokens = {
245                 {1, "xid=%u"},
246                 {0, NULL}
247         };
248         substring_t args[MAX_OPT_ARGS];
249         int token, option = 0;
250
251         if (!string)
252                 return 0;
253
254         token = match_token(string, tokens, args);
255         if (token && xid && !match_int(args, &option))
256                 *xid = option;
257
258         vxdprintk(VXD_CBIT(xid, 7),
259                 "vx_parse_xid(»%s«): %d:#%d",
260                 string, token, option);
261
262         if (token && remove) {
263                 char *p = strstr(string, "xid=");
264                 char *q = p;
265
266                 if (p) {
267                         while (*q != '\0' && *q != ',')
268                                 q++;
269                         while (*q)
270                                 *p++ = *q++;
271                         while (*p)
272                                 *p++ = '\0';
273                 }
274         }
275         return token;
276 }
277
278 void vx_propagate_xid(struct nameidata *nd, struct inode *inode)
279 {
280         xid_t new_xid = 0;
281         struct vfsmount *mnt;
282         int propagate;
283
284         if (!nd)
285                 return;
286         mnt = nd->mnt;
287         if (!mnt)
288                 return;
289
290         propagate = (mnt->mnt_flags & MNT_XID);
291         if (propagate)
292                 new_xid = mnt->mnt_xid;
293
294         vxdprintk(VXD_CBIT(xid, 7),
295                 "vx_propagate_xid(%p[#%lu.%d]): %d,%d",
296                 inode, inode->i_ino, inode->i_xid,
297                 new_xid, (propagate)?1:0);
298
299         if (propagate)
300                 inode->i_xid = new_xid;
301 }
302
303 #include <linux/module.h>
304
305 EXPORT_SYMBOL_GPL(vx_propagate_xid);
306