1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2010 Werner Fink, Jiri Slaby
4  */
5 
6 #include <linux/console.h>
7 #include <linux/kernel.h>
8 #include <linux/proc_fs.h>
9 #include <linux/seq_file.h>
10 #include <linux/tty_driver.h>
11 
12 /*
13  * This is handler for /proc/consoles
14  */
show_console_dev(struct seq_file * m,void * v)15 static int show_console_dev(struct seq_file *m, void *v)
16 {
17 	static const struct {
18 		short flag;
19 		char name;
20 	} con_flags[] = {
21 		{ CON_ENABLED,		'E' },
22 		{ CON_CONSDEV,		'C' },
23 		{ CON_BOOT,		'B' },
24 		{ CON_PRINTBUFFER,	'p' },
25 		{ CON_BRL,		'b' },
26 		{ CON_ANYTIME,		'a' },
27 	};
28 	char flags[ARRAY_SIZE(con_flags) + 1];
29 	struct console *con = v;
30 	unsigned int a;
31 	dev_t dev = 0;
32 
33 	if (con->device) {
34 		const struct tty_driver *driver;
35 		int index;
36 		driver = con->device(con, &index);
37 		if (driver) {
38 			dev = MKDEV(driver->major, driver->minor_start);
39 			dev += index;
40 		}
41 	}
42 
43 	for (a = 0; a < ARRAY_SIZE(con_flags); a++)
44 		flags[a] = (con->flags & con_flags[a].flag) ?
45 			con_flags[a].name : ' ';
46 	flags[a] = 0;
47 
48 	seq_setwidth(m, 21 - 1);
49 	seq_printf(m, "%s%d", con->name, con->index);
50 	seq_pad(m, ' ');
51 	seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-',
52 			con->write ? 'W' : '-', con->unblank ? 'U' : '-',
53 			flags);
54 	if (dev)
55 		seq_printf(m, " %4d:%d", MAJOR(dev), MINOR(dev));
56 
57 	seq_putc(m, '\n');
58 	return 0;
59 }
60 
c_start(struct seq_file * m,loff_t * pos)61 static void *c_start(struct seq_file *m, loff_t *pos)
62 {
63 	struct console *con;
64 	loff_t off = 0;
65 
66 	console_lock();
67 	for_each_console(con)
68 		if (off++ == *pos)
69 			break;
70 
71 	return con;
72 }
73 
c_next(struct seq_file * m,void * v,loff_t * pos)74 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
75 {
76 	struct console *con = v;
77 	++*pos;
78 	return con->next;
79 }
80 
c_stop(struct seq_file * m,void * v)81 static void c_stop(struct seq_file *m, void *v)
82 {
83 	console_unlock();
84 }
85 
86 static const struct seq_operations consoles_op = {
87 	.start	= c_start,
88 	.next	= c_next,
89 	.stop	= c_stop,
90 	.show	= show_console_dev
91 };
92 
proc_consoles_init(void)93 static int __init proc_consoles_init(void)
94 {
95 	proc_create_seq("consoles", 0, NULL, &consoles_op);
96 	return 0;
97 }
98 fs_initcall(proc_consoles_init);
99