Merge tag 'zstd-linus-v6.2' of https://github.com/terrelln/linux
[platform/kernel/linux-starfive.git] / fs / proc / consoles.c
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  */
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
37                 /*
38                  * Take console_lock to serialize device() callback with
39                  * other console operations. For example, fg_console is
40                  * modified under console_lock when switching vt.
41                  */
42                 console_lock();
43                 driver = con->device(con, &index);
44                 console_unlock();
45
46                 if (driver) {
47                         dev = MKDEV(driver->major, driver->minor_start);
48                         dev += index;
49                 }
50         }
51
52         for (a = 0; a < ARRAY_SIZE(con_flags); a++)
53                 flags[a] = (con->flags & con_flags[a].flag) ?
54                         con_flags[a].name : ' ';
55         flags[a] = 0;
56
57         seq_setwidth(m, 21 - 1);
58         seq_printf(m, "%s%d", con->name, con->index);
59         seq_pad(m, ' ');
60         seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-',
61                         con->write ? 'W' : '-', con->unblank ? 'U' : '-',
62                         flags);
63         if (dev)
64                 seq_printf(m, " %4d:%d", MAJOR(dev), MINOR(dev));
65
66         seq_putc(m, '\n');
67         return 0;
68 }
69
70 static void *c_start(struct seq_file *m, loff_t *pos)
71 {
72         struct console *con;
73         loff_t off = 0;
74
75         /*
76          * Hold the console_list_lock to guarantee safe traversal of the
77          * console list. SRCU cannot be used because there is no
78          * place to store the SRCU cookie.
79          */
80         console_list_lock();
81         for_each_console(con)
82                 if (off++ == *pos)
83                         break;
84
85         return con;
86 }
87
88 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
89 {
90         struct console *con = v;
91
92         ++*pos;
93         return hlist_entry_safe(con->node.next, struct console, node);
94 }
95
96 static void c_stop(struct seq_file *m, void *v)
97 {
98         console_list_unlock();
99 }
100
101 static const struct seq_operations consoles_op = {
102         .start  = c_start,
103         .next   = c_next,
104         .stop   = c_stop,
105         .show   = show_console_dev
106 };
107
108 static int __init proc_consoles_init(void)
109 {
110         proc_create_seq("consoles", 0, NULL, &consoles_op);
111         return 0;
112 }
113 fs_initcall(proc_consoles_init);