proc_tty.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * proc_tty.c -- handles /proc/tty
  4. *
  5. * Copyright 1997, Theodore Ts'o
  6. */
  7. #include <linux/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/seq_file.h>
  16. #include <linux/bitops.h>
  17. #include "internal.h"
  18. /*
  19. * The /proc/tty directory inodes...
  20. */
  21. static struct proc_dir_entry *proc_tty_driver;
  22. /*
  23. * This is the handler for /proc/tty/drivers
  24. */
  25. static void show_tty_range(struct seq_file *m, struct tty_driver *p,
  26. dev_t from, int num)
  27. {
  28. seq_printf(m, "%-20s ", p->driver_name ? p->driver_name : "unknown");
  29. seq_printf(m, "/dev/%-8s ", p->name);
  30. if (p->num > 1) {
  31. seq_printf(m, "%3d %d-%d ", MAJOR(from), MINOR(from),
  32. MINOR(from) + num - 1);
  33. } else {
  34. seq_printf(m, "%3d %7d ", MAJOR(from), MINOR(from));
  35. }
  36. switch (p->type) {
  37. case TTY_DRIVER_TYPE_SYSTEM:
  38. seq_puts(m, "system");
  39. if (p->subtype == SYSTEM_TYPE_TTY)
  40. seq_puts(m, ":/dev/tty");
  41. else if (p->subtype == SYSTEM_TYPE_SYSCONS)
  42. seq_puts(m, ":console");
  43. else if (p->subtype == SYSTEM_TYPE_CONSOLE)
  44. seq_puts(m, ":vtmaster");
  45. break;
  46. case TTY_DRIVER_TYPE_CONSOLE:
  47. seq_puts(m, "console");
  48. break;
  49. case TTY_DRIVER_TYPE_SERIAL:
  50. seq_puts(m, "serial");
  51. break;
  52. case TTY_DRIVER_TYPE_PTY:
  53. if (p->subtype == PTY_TYPE_MASTER)
  54. seq_puts(m, "pty:master");
  55. else if (p->subtype == PTY_TYPE_SLAVE)
  56. seq_puts(m, "pty:slave");
  57. else
  58. seq_puts(m, "pty");
  59. break;
  60. default:
  61. seq_printf(m, "type:%d.%d", p->type, p->subtype);
  62. }
  63. seq_putc(m, '\n');
  64. }
  65. static int show_tty_driver(struct seq_file *m, void *v)
  66. {
  67. struct tty_driver *p = list_entry(v, struct tty_driver, tty_drivers);
  68. dev_t from = MKDEV(p->major, p->minor_start);
  69. dev_t to = from + p->num;
  70. if (&p->tty_drivers == tty_drivers.next) {
  71. /* pseudo-drivers first */
  72. seq_printf(m, "%-20s /dev/%-8s ", "/dev/tty", "tty");
  73. seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 0);
  74. seq_puts(m, "system:/dev/tty\n");
  75. seq_printf(m, "%-20s /dev/%-8s ", "/dev/console", "console");
  76. seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 1);
  77. seq_puts(m, "system:console\n");
  78. #ifdef CONFIG_UNIX98_PTYS
  79. seq_printf(m, "%-20s /dev/%-8s ", "/dev/ptmx", "ptmx");
  80. seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 2);
  81. seq_puts(m, "system\n");
  82. #endif
  83. #ifdef CONFIG_VT
  84. seq_printf(m, "%-20s /dev/%-8s ", "/dev/vc/0", "vc/0");
  85. seq_printf(m, "%3d %7d ", TTY_MAJOR, 0);
  86. seq_puts(m, "system:vtmaster\n");
  87. #endif
  88. }
  89. while (MAJOR(from) < MAJOR(to)) {
  90. dev_t next = MKDEV(MAJOR(from)+1, 0);
  91. show_tty_range(m, p, from, next - from);
  92. from = next;
  93. }
  94. if (from != to)
  95. show_tty_range(m, p, from, to - from);
  96. return 0;
  97. }
  98. /* iterator */
  99. static void *t_start(struct seq_file *m, loff_t *pos)
  100. {
  101. mutex_lock(&tty_mutex);
  102. return seq_list_start(&tty_drivers, *pos);
  103. }
  104. static void *t_next(struct seq_file *m, void *v, loff_t *pos)
  105. {
  106. return seq_list_next(v, &tty_drivers, pos);
  107. }
  108. static void t_stop(struct seq_file *m, void *v)
  109. {
  110. mutex_unlock(&tty_mutex);
  111. }
  112. static const struct seq_operations tty_drivers_op = {
  113. .start = t_start,
  114. .next = t_next,
  115. .stop = t_stop,
  116. .show = show_tty_driver
  117. };
  118. /*
  119. * This function is called by tty_register_driver() to handle
  120. * registering the driver's /proc handler into /proc/tty/driver/<foo>
  121. */
  122. void proc_tty_register_driver(struct tty_driver *driver)
  123. {
  124. struct proc_dir_entry *ent;
  125. if (!driver->driver_name || driver->proc_entry ||
  126. !driver->ops->proc_show)
  127. return;
  128. ent = proc_create_single_data(driver->driver_name, 0, proc_tty_driver,
  129. driver->ops->proc_show, driver);
  130. driver->proc_entry = ent;
  131. }
  132. /*
  133. * This function is called by tty_unregister_driver()
  134. */
  135. void proc_tty_unregister_driver(struct tty_driver *driver)
  136. {
  137. struct proc_dir_entry *ent;
  138. ent = driver->proc_entry;
  139. if (!ent)
  140. return;
  141. remove_proc_entry(ent->name, proc_tty_driver);
  142. driver->proc_entry = NULL;
  143. }
  144. /*
  145. * Called by proc_root_init() to initialize the /proc/tty subtree
  146. */
  147. void __init proc_tty_init(void)
  148. {
  149. if (!proc_mkdir("tty", NULL))
  150. return;
  151. proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */
  152. /*
  153. * /proc/tty/driver/serial reveals the exact character counts for
  154. * serial links which is just too easy to abuse for inferring
  155. * password lengths and inter-keystroke timings during password
  156. * entry.
  157. */
  158. proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL);
  159. proc_create_seq("tty/ldiscs", 0, NULL, &tty_ldiscs_seq_ops);
  160. proc_create_seq("tty/drivers", 0, NULL, &tty_drivers_op);
  161. }