aboutsummaryrefslogtreecommitdiffstats
path: root/fs/devpts/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/devpts/inode.c')
-rw-r--r--fs/devpts/inode.c115
1 files changed, 110 insertions, 5 deletions
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 00530e82673..8ee9dc2f9e4 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -27,6 +27,13 @@
27#define DEVPTS_SUPER_MAGIC 0x1cd1 27#define DEVPTS_SUPER_MAGIC 0x1cd1
28 28
29#define DEVPTS_DEFAULT_MODE 0600 29#define DEVPTS_DEFAULT_MODE 0600
30/*
31 * ptmx is a new node in /dev/pts and will be unused in legacy (single-
32 * instance) mode. To prevent surprises in user space, set permissions of
33 * ptmx to 0. Use 'chmod' or remount with '-o ptmxmode' to set meaningful
34 * permissions.
35 */
36#define DEVPTS_DEFAULT_PTMX_MODE 0000
30#define PTMX_MINOR 2 37#define PTMX_MINOR 2
31 38
32extern int pty_limit; /* Config limit on Unix98 ptys */ 39extern int pty_limit; /* Config limit on Unix98 ptys */
@@ -40,10 +47,11 @@ struct pts_mount_opts {
40 uid_t uid; 47 uid_t uid;
41 gid_t gid; 48 gid_t gid;
42 umode_t mode; 49 umode_t mode;
50 umode_t ptmxmode;
43}; 51};
44 52
45enum { 53enum {
46 Opt_uid, Opt_gid, Opt_mode, 54 Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode,
47 Opt_err 55 Opt_err
48}; 56};
49 57
@@ -51,12 +59,16 @@ static const match_table_t tokens = {
51 {Opt_uid, "uid=%u"}, 59 {Opt_uid, "uid=%u"},
52 {Opt_gid, "gid=%u"}, 60 {Opt_gid, "gid=%u"},
53 {Opt_mode, "mode=%o"}, 61 {Opt_mode, "mode=%o"},
62#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
63 {Opt_ptmxmode, "ptmxmode=%o"},
64#endif
54 {Opt_err, NULL} 65 {Opt_err, NULL}
55}; 66};
56 67
57struct pts_fs_info { 68struct pts_fs_info {
58 struct ida allocated_ptys; 69 struct ida allocated_ptys;
59 struct pts_mount_opts mount_opts; 70 struct pts_mount_opts mount_opts;
71 struct dentry *ptmx_dentry;
60}; 72};
61 73
62static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb) 74static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
@@ -81,6 +93,7 @@ static int parse_mount_options(char *data, struct pts_mount_opts *opts)
81 opts->uid = 0; 93 opts->uid = 0;
82 opts->gid = 0; 94 opts->gid = 0;
83 opts->mode = DEVPTS_DEFAULT_MODE; 95 opts->mode = DEVPTS_DEFAULT_MODE;
96 opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
84 97
85 while ((p = strsep(&data, ",")) != NULL) { 98 while ((p = strsep(&data, ",")) != NULL) {
86 substring_t args[MAX_OPT_ARGS]; 99 substring_t args[MAX_OPT_ARGS];
@@ -109,6 +122,13 @@ static int parse_mount_options(char *data, struct pts_mount_opts *opts)
109 return -EINVAL; 122 return -EINVAL;
110 opts->mode = option & S_IALLUGO; 123 opts->mode = option & S_IALLUGO;
111 break; 124 break;
125#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
126 case Opt_ptmxmode:
127 if (match_octal(&args[0], &option))
128 return -EINVAL;
129 opts->ptmxmode = option & S_IALLUGO;
130 break;
131#endif
112 default: 132 default:
113 printk(KERN_ERR "devpts: called with bogus options\n"); 133 printk(KERN_ERR "devpts: called with bogus options\n");
114 return -EINVAL; 134 return -EINVAL;
@@ -118,12 +138,93 @@ static int parse_mount_options(char *data, struct pts_mount_opts *opts)
118 return 0; 138 return 0;
119} 139}
120 140
141#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
142static int mknod_ptmx(struct super_block *sb)
143{
144 int mode;
145 int rc = -ENOMEM;
146 struct dentry *dentry;
147 struct inode *inode;
148 struct dentry *root = sb->s_root;
149 struct pts_fs_info *fsi = DEVPTS_SB(sb);
150 struct pts_mount_opts *opts = &fsi->mount_opts;
151
152 mutex_lock(&root->d_inode->i_mutex);
153
154 /* If we have already created ptmx node, return */
155 if (fsi->ptmx_dentry) {
156 rc = 0;
157 goto out;
158 }
159
160 dentry = d_alloc_name(root, "ptmx");
161 if (!dentry) {
162 printk(KERN_NOTICE "Unable to alloc dentry for ptmx node\n");
163 goto out;
164 }
165
166 /*
167 * Create a new 'ptmx' node in this mount of devpts.
168 */
169 inode = new_inode(sb);
170 if (!inode) {
171 printk(KERN_ERR "Unable to alloc inode for ptmx node\n");
172 dput(dentry);
173 goto out;
174 }
175
176 inode->i_ino = 2;
177 inode->i_uid = inode->i_gid = 0;
178 inode->i_blocks = 0;
179 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
180
181 mode = S_IFCHR|opts->ptmxmode;
182 init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2));
183
184 d_add(dentry, inode);
185
186 fsi->ptmx_dentry = dentry;
187 rc = 0;
188
189 printk(KERN_DEBUG "Created ptmx node in devpts ino %lu\n",
190 inode->i_ino);
191out:
192 mutex_unlock(&root->d_inode->i_mutex);
193 return rc;
194}
195
196static void update_ptmx_mode(struct pts_fs_info *fsi)
197{
198 struct inode *inode;
199 if (fsi->ptmx_dentry) {
200 inode = fsi->ptmx_dentry->d_inode;
201 inode->i_mode = S_IFCHR|fsi->mount_opts.ptmxmode;
202 }
203}
204#else
205static inline void update_ptmx_mode(struct pts_fs_info *fsi)
206{
207 return;
208}
209#endif
210
121static int devpts_remount(struct super_block *sb, int *flags, char *data) 211static int devpts_remount(struct super_block *sb, int *flags, char *data)
122{ 212{
213 int err;
123 struct pts_fs_info *fsi = DEVPTS_SB(sb); 214 struct pts_fs_info *fsi = DEVPTS_SB(sb);
124 struct pts_mount_opts *opts = &fsi->mount_opts; 215 struct pts_mount_opts *opts = &fsi->mount_opts;
125 216
126 return parse_mount_options(data, opts); 217 err = parse_mount_options(data, opts);
218
219 /*
220 * parse_mount_options() restores options to default values
221 * before parsing and may have changed ptmxmode. So, update the
222 * mode in the inode too. Bogus options don't fail the remount,
223 * so do this even on error return.
224 */
225 update_ptmx_mode(fsi);
226
227 return err;
127} 228}
128 229
129static int devpts_show_options(struct seq_file *seq, struct vfsmount *vfs) 230static int devpts_show_options(struct seq_file *seq, struct vfsmount *vfs)
@@ -136,6 +237,9 @@ static int devpts_show_options(struct seq_file *seq, struct vfsmount *vfs)
136 if (opts->setgid) 237 if (opts->setgid)
137 seq_printf(seq, ",gid=%u", opts->gid); 238 seq_printf(seq, ",gid=%u", opts->gid);
138 seq_printf(seq, ",mode=%03o", opts->mode); 239 seq_printf(seq, ",mode=%03o", opts->mode);
240#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
241 seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode);
242#endif
139 243
140 return 0; 244 return 0;
141} 245}
@@ -156,6 +260,7 @@ static void *new_pts_fs_info(void)
156 260
157 ida_init(&fsi->allocated_ptys); 261 ida_init(&fsi->allocated_ptys);
158 fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE; 262 fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
263 fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
159 264
160 return fsi; 265 return fsi;
161} 266}
@@ -163,7 +268,7 @@ static void *new_pts_fs_info(void)
163static int 268static int
164devpts_fill_super(struct super_block *s, void *data, int silent) 269devpts_fill_super(struct super_block *s, void *data, int silent)
165{ 270{
166 struct inode * inode; 271 struct inode *inode;
167 272
168 s->s_blocksize = 1024; 273 s->s_blocksize = 1024;
169 s->s_blocksize_bits = 10; 274 s->s_blocksize_bits = 10;
@@ -190,7 +295,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
190 s->s_root = d_alloc_root(inode); 295 s->s_root = d_alloc_root(inode);
191 if (s->s_root) 296 if (s->s_root)
192 return 0; 297 return 0;
193 298
194 printk("devpts: get root dentry failed\n"); 299 printk("devpts: get root dentry failed\n");
195 iput(inode); 300 iput(inode);
196 301
@@ -211,7 +316,7 @@ static void devpts_kill_sb(struct super_block *sb)
211 struct pts_fs_info *fsi = DEVPTS_SB(sb); 316 struct pts_fs_info *fsi = DEVPTS_SB(sb);
212 317
213 kfree(fsi); 318 kfree(fsi);
214 kill_anon_super(sb); 319 kill_litter_super(sb);
215} 320}
216 321
217static struct file_system_type devpts_fs_type = { 322static struct file_system_type devpts_fs_type = {