proc_tty.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * proc_tty.c -- handles /proc/tty
  3. *
  4. * Copyright 1997, Theodore Ts'o
  5. */
  6. #include <asm/uaccess.h>
  7. #include <linux/module.h>
  8. #include <linux/init.h>
  9. #include <linux/errno.h>
  10. #include <linux/time.h>
  11. #include <linux/proc_fs.h>
  12. #include <linux/stat.h>
  13. #include <linux/tty.h>
  14. #include <linux/tty_driver.h>
  15. #include <linux/console.h>
  16. #include <linux/seq_file.h>
  17. #include <linux/fdtable.h>
  18. #include <linux/bitops.h>
  19. /*
  20. * The /proc/tty directory inodes...
  21. */
  22. static struct proc_dir_entry *proc_tty_ldisc, *proc_tty_driver;
  23. /*
  24. * This is the handler for /proc/tty/drivers
  25. */
  26. static void show_tty_range(struct seq_file *m, struct tty_driver *p,
  27. dev_t from, int num)
  28. {
  29. seq_printf(m, "%-20s ", p->driver_name ? p->driver_name : "unknown");
  30. seq_printf(m, "/dev/%-8s ", p->name);
  31. if (p->num > 1) {
  32. seq_printf(m, "%3d %d-%d ", MAJOR(from), MINOR(from),
  33. MINOR(from) + num - 1);
  34. } else {
  35. seq_printf(m, "%3d %7d ", MAJOR(from), MINOR(from));
  36. }
  37. switch (p->type) {
  38. case TTY_DRIVER_TYPE_SYSTEM:
  39. seq_printf(m, "system");
  40. if (p->subtype == SYSTEM_TYPE_TTY)
  41. seq_printf(m, ":/dev/tty");
  42. else if (p->subtype == SYSTEM_TYPE_SYSCONS)
  43. seq_printf(m, ":console");
  44. else if (p->subtype == SYSTEM_TYPE_CONSOLE)
  45. seq_printf(m, ":vtmaster");
  46. break;
  47. case TTY_DRIVER_TYPE_CONSOLE:
  48. seq_printf(m, "console");
  49. break;
  50. case TTY_DRIVER_TYPE_SERIAL:
  51. seq_printf(m, "serial");
  52. break;
  53. case TTY_DRIVER_TYPE_PTY:
  54. if (p->subtype == PTY_TYPE_MASTER)
  55. seq_printf(m, "pty:master");
  56. else if (p->subtype == PTY_TYPE_SLAVE)
  57. seq_printf(m, "pty:slave");
  58. else
  59. seq_printf(m, "pty");
  60. break;
  61. default:
  62. seq_printf(m, "type:%d.%d", p->type, p->subtype);
  63. }
  64. seq_putc(m, '\n');
  65. }
  66. static int show_tty_driver(struct seq_file *m, void *v)
  67. {
  68. struct tty_driver *p = list_entry(v, struct tty_driver, tty_drivers);
  69. dev_t from = MKDEV(p->major, p->minor_start);
  70. dev_t to = from + p->num;
  71. if (&p->tty_drivers == tty_drivers.next) {
  72. /* pseudo-drivers first */
  73. seq_printf(m, "%-20s /dev/%-8s ", "/dev/tty", "tty");
  74. seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 0);
  75. seq_printf(m, "system:/dev/tty\n");
  76. seq_printf(m, "%-20s /dev/%-8s ", "/dev/console", "console");
  77. seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 1);
  78. seq_printf(m, "system:console\n");
  79. #ifdef CONFIG_UNIX98_PTYS
  80. seq_printf(m, "%-20s /dev/%-8s ", "/dev/ptmx", "ptmx");
  81. seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 2);
  82. seq_printf(m, "system\n");
  83. #endif
  84. #ifdef CONFIG_VT
  85. seq_printf(m, "%-20s /dev/%-8s ", "/dev/vc/0", "vc/0");
  86. seq_printf(m, "%3d %7d ", TTY_MAJOR, 0);
  87. seq_printf(m, "system:vtmaster\n");
  88. #endif
  89. }
  90. while (MAJOR(from) < MAJOR(to)) {
  91. dev_t next = MKDEV(MAJOR(from)+1, 0);
  92. show_tty_range(m, p, from, next - from);
  93. from = next;
  94. }
  95. if (from != to)
  96. show_tty_range(m, p, from, to - from);
  97. return 0;
  98. }
  99. /* iterator */
  100. static void *t_start(struct seq_file *m, loff_t *pos)
  101. {
  102. mutex_lock(&tty_mutex);
  103. return seq_list_start(&tty_drivers, *pos);
  104. }
  105. static void *t_next(struct seq_file *m, void *v, loff_t *pos)
  106. {
  107. return seq_list_next(v, &tty_drivers, pos);
  108. }
  109. static void t_stop(struct seq_file *m, void *v)
  110. {
  111. mutex_unlock(&tty_mutex);
  112. }
  113. static const struct seq_operations tty_drivers_op = {
  114. .start = t_start,
  115. .next = t_next,
  116. .stop = t_stop,
  117. .show = show_tty_driver
  118. };
  119. static int tty_drivers_open(struct inode *inode, struct file *file)
  120. {
  121. return seq_open(file, &tty_drivers_op);
  122. }
  123. static const struct file_operations proc_tty_drivers_operations = {
  124. .open = tty_drivers_open,
  125. .read = seq_read,
  126. .llseek = seq_lseek,
  127. .release = seq_release,
  128. };
  129. /*
  130. * The device ID of file descriptor 0 of the current reading
  131. * task if a character device...
  132. */
  133. static dev_t current_dev;
  134. /*
  135. * This is the handler for /proc/tty/consoles
  136. */
  137. static int show_console_dev(struct seq_file *m, void *v)
  138. {
  139. const struct tty_driver *driver;
  140. struct console *con;
  141. int index, len;
  142. char flags[10];
  143. dev_t dev;
  144. if (v == SEQ_START_TOKEN)
  145. return 0;
  146. con = (struct console *)v;
  147. if (!con)
  148. return 0;
  149. driver = con->device(con, &index);
  150. if (!driver)
  151. return 0;
  152. dev = MKDEV(driver->major, driver->minor_start) + index;
  153. index = 0;
  154. if (con->flags & CON_ENABLED)
  155. flags[index++] = 'E';
  156. if (con->flags & CON_CONSDEV)
  157. flags[index++] = 'C';
  158. if (con->flags & CON_BOOT)
  159. flags[index++] = 'B';
  160. if (con->flags & CON_PRINTBUFFER)
  161. flags[index++] = 'p';
  162. if (con->flags & CON_BRL)
  163. flags[index++] = 'b';
  164. if (con->flags & CON_ANYTIME)
  165. flags[index++] = 'a';
  166. if (current_dev == dev)
  167. flags[index++] = '*';
  168. flags[index] = 0;
  169. seq_printf(m, "%s%d%n", con->name, con->index, &len);
  170. len = 21 - len;
  171. if (len < 1)
  172. len = 1;
  173. seq_printf(m, "%*c", len, ' ');
  174. seq_printf(m, "%c%c%c (%s)%n", con->read ? 'R' : '-',
  175. con->write ? 'W' : '-', con->unblank ? 'U' : '-',
  176. flags, &len);
  177. len = 13 - len;
  178. if (len < 1)
  179. len = 1;
  180. seq_printf(m, "%*c%4d:%d\n", len, ' ', MAJOR(dev), MINOR(dev));
  181. return 0;
  182. }
  183. /* iterator for consoles */
  184. static void *c_start(struct seq_file *m, loff_t *pos)
  185. {
  186. struct console *con;
  187. loff_t off = 0;
  188. if (*pos == 0)
  189. return SEQ_START_TOKEN;
  190. acquire_console_sem();
  191. for (con = console_drivers; con; con = con->next) {
  192. if (!con->device)
  193. continue;
  194. if (++off == *pos)
  195. break;
  196. }
  197. release_console_sem();
  198. return con;
  199. }
  200. static void *c_next(struct seq_file *m, void *v, loff_t *pos)
  201. {
  202. struct console *con;
  203. acquire_console_sem();
  204. if (v == SEQ_START_TOKEN)
  205. con = console_drivers;
  206. else
  207. con = ((struct console *)v)->next;
  208. for (; con; con = con->next) {
  209. if (!con->device)
  210. continue;
  211. ++*pos;
  212. break;
  213. }
  214. release_console_sem();
  215. return con;
  216. }
  217. static void c_stop(struct seq_file *m, void *v)
  218. {
  219. }
  220. static const struct seq_operations tty_consoles_op = {
  221. .start = c_start,
  222. .next = c_next,
  223. .stop = c_stop,
  224. .show = show_console_dev
  225. };
  226. /*
  227. * Used for open /proc/tty/consoles. Before this detect
  228. * the device ID of file descriptor 0 of the current
  229. * reading task if a character device...
  230. */
  231. static int tty_consoles_open(struct inode *inode, struct file *file)
  232. {
  233. struct files_struct *curfiles;
  234. current_dev = 0;
  235. curfiles = get_files_struct(current);
  236. if (curfiles) {
  237. const struct file *curfp;
  238. spin_lock(&curfiles->file_lock);
  239. curfp = fcheck_files(curfiles, 0);
  240. if (curfp && curfp->private_data) {
  241. const struct inode *inode;
  242. dget(curfp->f_dentry);
  243. inode = curfp->f_dentry->d_inode;
  244. if (S_ISCHR(inode->i_mode)) {
  245. struct tty_struct *tty;
  246. tty = (struct tty_struct *)curfp->private_data;
  247. if (tty && tty->magic == TTY_MAGIC) {
  248. tty = tty_pair_get_tty(tty);
  249. current_dev = tty_devnum(tty);
  250. }
  251. }
  252. dput(curfp->f_dentry);
  253. }
  254. spin_unlock(&curfiles->file_lock);
  255. put_files_struct(curfiles);
  256. }
  257. return seq_open(file, &tty_consoles_op);
  258. }
  259. static const struct file_operations proc_tty_consoles_operations = {
  260. .open = tty_consoles_open,
  261. .read = seq_read,
  262. .llseek = seq_lseek,
  263. .release = seq_release,
  264. };
  265. /*
  266. * This function is called by tty_register_driver() to handle
  267. * registering the driver's /proc handler into /proc/tty/driver/<foo>
  268. */
  269. void proc_tty_register_driver(struct tty_driver *driver)
  270. {
  271. struct proc_dir_entry *ent;
  272. if (!driver->driver_name || driver->proc_entry ||
  273. !driver->ops->proc_fops)
  274. return;
  275. ent = proc_create_data(driver->driver_name, 0, proc_tty_driver,
  276. driver->ops->proc_fops, driver);
  277. driver->proc_entry = ent;
  278. }
  279. /*
  280. * This function is called by tty_unregister_driver()
  281. */
  282. void proc_tty_unregister_driver(struct tty_driver *driver)
  283. {
  284. struct proc_dir_entry *ent;
  285. ent = driver->proc_entry;
  286. if (!ent)
  287. return;
  288. remove_proc_entry(driver->driver_name, proc_tty_driver);
  289. driver->proc_entry = NULL;
  290. }
  291. /*
  292. * Called by proc_root_init() to initialize the /proc/tty subtree
  293. */
  294. void __init proc_tty_init(void)
  295. {
  296. if (!proc_mkdir("tty", NULL))
  297. return;
  298. proc_tty_ldisc = proc_mkdir("tty/ldisc", NULL);
  299. /*
  300. * /proc/tty/driver/serial reveals the exact character counts for
  301. * serial links which is just too easy to abuse for inferring
  302. * password lengths and inter-keystroke timings during password
  303. * entry.
  304. */
  305. proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL);
  306. proc_create("tty/ldiscs", 0, NULL, &tty_ldiscs_proc_fops);
  307. proc_create("tty/drivers", 0, NULL, &proc_tty_drivers_operations);
  308. proc_create("tty/consoles", 0, NULL, &proc_tty_consoles_operations);
  309. }