2 * proc_tty.c -- handles /proc/tty
4 * Copyright 1997, Theodore Ts'o
7 #include <asm/uaccess.h>
8 #include <linux/module.h>
9 #include <linux/init.h>
10 #include <linux/errno.h>
11 #include <linux/time.h>
12 #include <linux/proc_fs.h>
13 #include <linux/stat.h>
14 #include <linux/tty.h>
15 #include <linux/tty_driver.h>
16 #include <linux/console.h>
17 #include <linux/seq_file.h>
18 #include <linux/fdtable.h>
19 #include <linux/bitops.h>
22 * The /proc/tty directory inodes...
24 static struct proc_dir_entry
*proc_tty_ldisc
, *proc_tty_driver
;
27 * This is the handler for /proc/tty/drivers
29 static void show_tty_range(struct seq_file
*m
, struct tty_driver
*p
,
32 seq_printf(m
, "%-20s ", p
->driver_name
? p
->driver_name
: "unknown");
33 seq_printf(m
, "/dev/%-8s ", p
->name
);
35 seq_printf(m
, "%3d %d-%d ", MAJOR(from
), MINOR(from
),
36 MINOR(from
) + num
- 1);
38 seq_printf(m
, "%3d %7d ", MAJOR(from
), MINOR(from
));
41 case TTY_DRIVER_TYPE_SYSTEM
:
42 seq_printf(m
, "system");
43 if (p
->subtype
== SYSTEM_TYPE_TTY
)
44 seq_printf(m
, ":/dev/tty");
45 else if (p
->subtype
== SYSTEM_TYPE_SYSCONS
)
46 seq_printf(m
, ":console");
47 else if (p
->subtype
== SYSTEM_TYPE_CONSOLE
)
48 seq_printf(m
, ":vtmaster");
50 case TTY_DRIVER_TYPE_CONSOLE
:
51 seq_printf(m
, "console");
53 case TTY_DRIVER_TYPE_SERIAL
:
54 seq_printf(m
, "serial");
56 case TTY_DRIVER_TYPE_PTY
:
57 if (p
->subtype
== PTY_TYPE_MASTER
)
58 seq_printf(m
, "pty:master");
59 else if (p
->subtype
== PTY_TYPE_SLAVE
)
60 seq_printf(m
, "pty:slave");
65 seq_printf(m
, "type:%d.%d", p
->type
, p
->subtype
);
70 static int show_tty_driver(struct seq_file
*m
, void *v
)
72 struct tty_driver
*p
= list_entry(v
, struct tty_driver
, tty_drivers
);
73 dev_t from
= MKDEV(p
->major
, p
->minor_start
);
74 dev_t to
= from
+ p
->num
;
76 if (&p
->tty_drivers
== tty_drivers
.next
) {
77 /* pseudo-drivers first */
78 seq_printf(m
, "%-20s /dev/%-8s ", "/dev/tty", "tty");
79 seq_printf(m
, "%3d %7d ", TTYAUX_MAJOR
, 0);
80 seq_printf(m
, "system:/dev/tty\n");
81 seq_printf(m
, "%-20s /dev/%-8s ", "/dev/console", "console");
82 seq_printf(m
, "%3d %7d ", TTYAUX_MAJOR
, 1);
83 seq_printf(m
, "system:console\n");
84 #ifdef CONFIG_UNIX98_PTYS
85 seq_printf(m
, "%-20s /dev/%-8s ", "/dev/ptmx", "ptmx");
86 seq_printf(m
, "%3d %7d ", TTYAUX_MAJOR
, 2);
87 seq_printf(m
, "system\n");
90 seq_printf(m
, "%-20s /dev/%-8s ", "/dev/vc/0", "vc/0");
91 seq_printf(m
, "%3d %7d ", TTY_MAJOR
, 0);
92 seq_printf(m
, "system:vtmaster\n");
96 while (MAJOR(from
) < MAJOR(to
)) {
97 dev_t next
= MKDEV(MAJOR(from
)+1, 0);
98 show_tty_range(m
, p
, from
, next
- from
);
102 show_tty_range(m
, p
, from
, to
- from
);
107 static void *t_start(struct seq_file
*m
, loff_t
*pos
)
109 mutex_lock(&tty_mutex
);
110 return seq_list_start(&tty_drivers
, *pos
);
113 static void *t_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
115 return seq_list_next(v
, &tty_drivers
, pos
);
118 static void t_stop(struct seq_file
*m
, void *v
)
120 mutex_unlock(&tty_mutex
);
123 static const struct seq_operations tty_drivers_op
= {
127 .show
= show_tty_driver
130 static int tty_drivers_open(struct inode
*inode
, struct file
*file
)
132 return seq_open(file
, &tty_drivers_op
);
135 static const struct file_operations proc_tty_drivers_operations
= {
136 .open
= tty_drivers_open
,
139 .release
= seq_release
,
143 * The device ID of file descriptor 0 of the current reading
144 * task if a character device...
146 static dev_t current_dev
;
149 * This is the handler for /proc/tty/consoles
151 static int show_console_dev(struct seq_file
*m
, void *v
)
153 const struct tty_driver
*driver
;
159 if (v
== SEQ_START_TOKEN
)
161 con
= (struct console
*)v
;
164 driver
= con
->device(con
, &index
);
167 dev
= MKDEV(driver
->major
, driver
->minor_start
) + index
;
170 if (con
->flags
& CON_ENABLED
)
171 flags
[index
++] = 'E';
172 if (con
->flags
& CON_CONSDEV
)
173 flags
[index
++] = 'C';
174 if (con
->flags
& CON_BOOT
)
175 flags
[index
++] = 'B';
176 if (con
->flags
& CON_PRINTBUFFER
)
177 flags
[index
++] = 'p';
178 if (con
->flags
& CON_BRL
)
179 flags
[index
++] = 'b';
180 if (con
->flags
& CON_ANYTIME
)
181 flags
[index
++] = 'a';
182 if (current_dev
== dev
)
183 flags
[index
++] = '*';
186 seq_printf(m
, "%s%d%n", con
->name
, con
->index
, &len
);
190 seq_printf(m
, "%*c", len
, ' ');
191 seq_printf(m
, "%c%c%c (%s)%n", con
->read
? 'R' : '-',
192 con
->write
? 'W' : '-', con
->unblank
? 'U' : '-',
197 seq_printf(m
, "%*c%4d:%d\n", len
, ' ', MAJOR(dev
), MINOR(dev
));
202 /* iterator for consoles */
203 static void *c_start(struct seq_file
*m
, loff_t
*pos
)
209 return SEQ_START_TOKEN
;
211 acquire_console_sem();
212 for (con
= console_drivers
; con
; con
= con
->next
) {
218 release_console_sem();
223 static void *c_next(struct seq_file
*m
, void *v
, loff_t
*pos
)
227 acquire_console_sem();
228 if (v
== SEQ_START_TOKEN
)
229 con
= console_drivers
;
231 con
= ((struct console
*)v
)->next
;
232 for (; con
; con
= con
->next
) {
238 release_console_sem();
243 static void c_stop(struct seq_file
*m
, void *v
)
247 static const struct seq_operations tty_consoles_op
= {
251 .show
= show_console_dev
255 * Used for open /proc/tty/consoles. Before this detect
256 * the device ID of file descriptor 0 of the current
257 * reading task if a character device...
259 static int tty_consoles_open(struct inode
*inode
, struct file
*file
)
261 struct files_struct
*curfiles
;
264 curfiles
= get_files_struct(current
);
266 const struct file
*curfp
;
267 spin_lock(&curfiles
->file_lock
);
268 curfp
= fcheck_files(curfiles
, 0);
269 if (curfp
&& curfp
->private_data
) {
270 const struct inode
*inode
;
271 dget(curfp
->f_dentry
);
272 inode
= curfp
->f_dentry
->d_inode
;
273 if (S_ISCHR(inode
->i_mode
)) {
274 struct tty_struct
*tty
;
275 tty
= (struct tty_struct
*)curfp
->private_data
;
276 if (tty
&& tty
->magic
== TTY_MAGIC
) {
277 tty
= tty_pair_get_tty(tty
);
278 current_dev
= tty_devnum(tty
);
281 dput(curfp
->f_dentry
);
283 spin_unlock(&curfiles
->file_lock
);
284 put_files_struct(curfiles
);
286 return seq_open(file
, &tty_consoles_op
);
289 static const struct file_operations proc_tty_consoles_operations
= {
290 .open
= tty_consoles_open
,
293 .release
= seq_release
,
297 * This function is called by tty_register_driver() to handle
298 * registering the driver's /proc handler into /proc/tty/driver/<foo>
300 void proc_tty_register_driver(struct tty_driver
*driver
)
302 struct proc_dir_entry
*ent
;
304 if (!driver
->driver_name
|| driver
->proc_entry
||
305 !driver
->ops
->proc_fops
)
308 ent
= proc_create_data(driver
->driver_name
, 0, proc_tty_driver
,
309 driver
->ops
->proc_fops
, driver
);
310 driver
->proc_entry
= ent
;
314 * This function is called by tty_unregister_driver()
316 void proc_tty_unregister_driver(struct tty_driver
*driver
)
318 struct proc_dir_entry
*ent
;
320 ent
= driver
->proc_entry
;
324 remove_proc_entry(driver
->driver_name
, proc_tty_driver
);
326 driver
->proc_entry
= NULL
;
330 * Called by proc_root_init() to initialize the /proc/tty subtree
332 void __init
proc_tty_init(void)
334 if (!proc_mkdir("tty", NULL
))
336 proc_tty_ldisc
= proc_mkdir("tty/ldisc", NULL
);
338 * /proc/tty/driver/serial reveals the exact character counts for
339 * serial links which is just too easy to abuse for inferring
340 * password lengths and inter-keystroke timings during password
343 proc_tty_driver
= proc_mkdir_mode("tty/driver", S_IRUSR
|S_IXUSR
, NULL
);
344 proc_create("tty/ldiscs", 0, NULL
, &tty_ldiscs_proc_fops
);
345 proc_create("tty/drivers", 0, NULL
, &proc_tty_drivers_operations
);
346 proc_create("tty/consoles", 0, NULL
, &proc_tty_consoles_operations
);