This commit was manufactured by cvs2svn to create tag 'before-xenU'.
[linux-2.6.git] / fs / devpts / inode.c
1 /* -*- linux-c -*- --------------------------------------------------------- *
2  *
3  * linux/fs/devpts/inode.c
4  *
5  *  Copyright 1998-2004 H. Peter Anvin -- All Rights Reserved
6  *
7  * This file is part of the Linux kernel and is made available under
8  * the terms of the GNU General Public License, version 2, or at your
9  * option, any later version, incorporated herein by reference.
10  *
11  * ------------------------------------------------------------------------- */
12
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/fs.h>
16 #include <linux/sched.h>
17 #include <linux/namei.h>
18 #include <linux/mount.h>
19 #include <linux/tty.h>
20 #include <linux/devpts_fs.h>
21 #include <linux/vs_base.h>
22 #include <linux/xattr.h>
23
24 extern struct xattr_handler devpts_xattr_security_handler;
25
26 static struct xattr_handler *devpts_xattr_handlers[] = {
27 #ifdef CONFIG_DEVPTS_FS_SECURITY
28         &devpts_xattr_security_handler,
29 #endif
30         NULL
31 };
32
33 static int devpts_permission(struct inode *inode, int mask, struct nameidata *nd)
34 {
35         int ret = -EACCES;
36
37         if (vx_check(inode->i_xid, VX_IDENT))
38                 ret = generic_permission(inode, mask, NULL);
39         return ret;
40 }
41
42 static struct inode_operations devpts_file_inode_operations = {
43 #ifdef CONFIG_DEVPTS_FS_XATTR
44         .setxattr       = generic_setxattr,
45         .getxattr       = generic_getxattr,
46         .listxattr      = generic_listxattr,
47         .removexattr    = generic_removexattr,
48 #endif
49         .permission     = devpts_permission,
50 };
51
52 static struct vfsmount *devpts_mnt;
53 static struct dentry *devpts_root;
54
55 static struct {
56         int setuid;
57         int setgid;
58         uid_t   uid;
59         gid_t   gid;
60         umode_t mode;
61 } config = {.mode = 0600};
62
63 static int devpts_remount(struct super_block *sb, int *flags, char *data)
64 {
65         int setuid = 0;
66         int setgid = 0;
67         uid_t uid = 0;
68         gid_t gid = 0;
69         umode_t mode = 0600;
70         char *this_char;
71
72         this_char = NULL;
73         while ((this_char = strsep(&data, ",")) != NULL) {
74                 int n;
75                 char dummy;
76                 if (!*this_char)
77                         continue;
78                 if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) {
79                         setuid = 1;
80                         uid = n;
81                 } else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) {
82                         setgid = 1;
83                         gid = n;
84                 } else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1)
85                         mode = n & ~S_IFMT;
86                 else {
87                         printk("devpts: called with bogus options\n");
88                         return -EINVAL;
89                 }
90         }
91         config.setuid  = setuid;
92         config.setgid  = setgid;
93         config.uid     = uid;
94         config.gid     = gid;
95         config.mode    = mode;
96
97         return 0;
98 }
99
100 static int devpts_filter(struct dentry *de)
101 {
102         return vx_check(de->d_inode->i_xid, VX_IDENT);
103 }
104
105 static int devpts_readdir(struct file * filp, void * dirent, filldir_t filldir)
106 {
107         return dcache_readdir_filter(filp, dirent, filldir, devpts_filter);
108 }
109
110 static struct file_operations devpts_dir_operations = {
111         .open           = dcache_dir_open,
112         .release        = dcache_dir_close,
113         .llseek         = dcache_dir_lseek,
114         .read           = generic_read_dir,
115         .readdir        = devpts_readdir,
116 };
117
118 static struct super_operations devpts_sops = {
119         .statfs         = simple_statfs,
120         .remount_fs     = devpts_remount,
121 };
122
123 static int
124 devpts_fill_super(struct super_block *s, void *data, int silent)
125 {
126         struct inode * inode;
127
128         s->s_blocksize = 1024;
129         s->s_blocksize_bits = 10;
130         s->s_magic = DEVPTS_SUPER_MAGIC;
131         s->s_op = &devpts_sops;
132         s->s_xattr = devpts_xattr_handlers;
133         s->s_time_gran = 1;
134
135         inode = new_inode(s);
136         if (!inode)
137                 goto fail;
138         inode->i_ino = 1;
139         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
140         inode->i_blocks = 0;
141         inode->i_blksize = 1024;
142         inode->i_uid = inode->i_gid = 0;
143         inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
144         inode->i_op = &simple_dir_inode_operations;
145         inode->i_fop = &devpts_dir_operations;
146         inode->i_nlink = 2;
147         inode->i_xid = vx_current_xid();
148
149         devpts_root = s->s_root = d_alloc_root(inode);
150         if (s->s_root)
151                 return 0;
152         
153         printk("devpts: get root dentry failed\n");
154         iput(inode);
155 fail:
156         return -ENOMEM;
157 }
158
159 static struct super_block *devpts_get_sb(struct file_system_type *fs_type,
160         int flags, const char *dev_name, void *data)
161 {
162         return get_sb_single(fs_type, flags, data, devpts_fill_super);
163 }
164
165 static struct file_system_type devpts_fs_type = {
166         .owner          = THIS_MODULE,
167         .name           = "devpts",
168         .get_sb         = devpts_get_sb,
169         .kill_sb        = kill_anon_super,
170 };
171
172 /*
173  * The normal naming convention is simply /dev/pts/<number>; this conforms
174  * to the System V naming convention
175  */
176
177 static struct dentry *get_node(int num)
178 {
179         char s[12];
180         struct dentry *root = devpts_root;
181         down(&root->d_inode->i_sem);
182         return lookup_one_len(s, root, sprintf(s, "%d", num));
183 }
184
185
186 int devpts_pty_new(struct tty_struct *tty)
187 {
188         int number = tty->index;
189         struct tty_driver *driver = tty->driver;
190         dev_t device = MKDEV(driver->major, driver->minor_start+number);
191         struct dentry *dentry;
192         struct inode *inode = new_inode(devpts_mnt->mnt_sb);
193
194         /* We're supposed to be given the slave end of a pty */
195         BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY);
196         BUG_ON(driver->subtype != PTY_TYPE_SLAVE);
197
198         if (!inode)
199                 return -ENOMEM;
200
201         inode->i_ino = number+2;
202         inode->i_blksize = 1024;
203         inode->i_uid = config.setuid ? config.uid : current->fsuid;
204         inode->i_gid = config.setgid ? config.gid : current->fsgid;
205         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
206         init_special_inode(inode, S_IFCHR|config.mode, device);
207         inode->i_xid = vx_current_xid();
208         inode->i_op = &devpts_file_inode_operations;
209         inode->u.generic_ip = tty;
210
211         dentry = get_node(number);
212         if (!IS_ERR(dentry) && !dentry->d_inode)
213                 d_instantiate(dentry, inode);
214
215         up(&devpts_root->d_inode->i_sem);
216
217         return 0;
218 }
219
220 struct tty_struct *devpts_get_tty(int number)
221 {
222         struct dentry *dentry = get_node(number);
223         struct tty_struct *tty;
224
225         tty = NULL;
226         if (!IS_ERR(dentry)) {
227                 if (dentry->d_inode)
228                         tty = dentry->d_inode->u.generic_ip;
229                 dput(dentry);
230         }
231
232         up(&devpts_root->d_inode->i_sem);
233
234         return tty;
235 }
236
237 void devpts_pty_kill(int number)
238 {
239         struct dentry *dentry = get_node(number);
240
241         if (!IS_ERR(dentry)) {
242                 struct inode *inode = dentry->d_inode;
243                 if (inode) {
244                         inode->i_nlink--;
245                         d_delete(dentry);
246                         dput(dentry);
247                 }
248                 dput(dentry);
249         }
250         up(&devpts_root->d_inode->i_sem);
251 }
252
253 static int __init init_devpts_fs(void)
254 {
255         int err = register_filesystem(&devpts_fs_type);
256         if (!err) {
257                 devpts_mnt = kern_mount(&devpts_fs_type);
258                 if (IS_ERR(devpts_mnt))
259                         err = PTR_ERR(devpts_mnt);
260         }
261         return err;
262 }
263
264 static void __exit exit_devpts_fs(void)
265 {
266         unregister_filesystem(&devpts_fs_type);
267         mntput(devpts_mnt);
268 }
269
270 module_init(init_devpts_fs)
271 module_exit(exit_devpts_fs)
272 MODULE_LICENSE("GPL");