ttyprintk.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * linux/drivers/char/ttyprintk.c
  4. *
  5. * Copyright (C) 2010 Samo Pogacnik
  6. */
  7. /*
  8. * This pseudo device allows user to make printk messages. It is possible
  9. * to store "console" messages inline with kernel messages for better analyses
  10. * of the boot process, for example.
  11. */
  12. #include <linux/device.h>
  13. #include <linux/serial.h>
  14. #include <linux/tty.h>
  15. #include <linux/module.h>
  16. #include <linux/spinlock.h>
  17. struct ttyprintk_port {
  18. struct tty_port port;
  19. spinlock_t spinlock;
  20. };
  21. static struct ttyprintk_port tpk_port;
  22. /*
  23. * Our simple preformatting supports transparent output of (time-stamped)
  24. * printk messages (also suitable for logging service):
  25. * - any cr is replaced by nl
  26. * - adds a ttyprintk source tag in front of each line
  27. * - too long message is fragmented, with '\'nl between fragments
  28. * - TPK_STR_SIZE isn't really the write_room limiting factor, because
  29. * it is emptied on the fly during preformatting.
  30. */
  31. #define TPK_STR_SIZE 508 /* should be bigger then max expected line length */
  32. #define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */
  33. #define TPK_PREFIX KERN_SOH __stringify(CONFIG_TTY_PRINTK_LEVEL)
  34. static int tpk_curr;
  35. static char tpk_buffer[TPK_STR_SIZE + 4];
  36. static void tpk_flush(void)
  37. {
  38. if (tpk_curr > 0) {
  39. tpk_buffer[tpk_curr] = '\0';
  40. printk(TPK_PREFIX "[U] %s\n", tpk_buffer);
  41. tpk_curr = 0;
  42. }
  43. }
  44. static int tpk_printk(const unsigned char *buf, int count)
  45. {
  46. int i = tpk_curr;
  47. if (buf == NULL) {
  48. tpk_flush();
  49. return i;
  50. }
  51. for (i = 0; i < count; i++) {
  52. if (tpk_curr >= TPK_STR_SIZE) {
  53. /* end of tmp buffer reached: cut the message in two */
  54. tpk_buffer[tpk_curr++] = '\\';
  55. tpk_flush();
  56. }
  57. switch (buf[i]) {
  58. case '\r':
  59. tpk_flush();
  60. if ((i + 1) < count && buf[i + 1] == '\n')
  61. i++;
  62. break;
  63. case '\n':
  64. tpk_flush();
  65. break;
  66. default:
  67. tpk_buffer[tpk_curr++] = buf[i];
  68. break;
  69. }
  70. }
  71. return count;
  72. }
  73. /*
  74. * TTY operations open function.
  75. */
  76. static int tpk_open(struct tty_struct *tty, struct file *filp)
  77. {
  78. tty->driver_data = &tpk_port;
  79. return tty_port_open(&tpk_port.port, tty, filp);
  80. }
  81. /*
  82. * TTY operations close function.
  83. */
  84. static void tpk_close(struct tty_struct *tty, struct file *filp)
  85. {
  86. struct ttyprintk_port *tpkp = tty->driver_data;
  87. unsigned long flags;
  88. spin_lock_irqsave(&tpkp->spinlock, flags);
  89. /* flush tpk_printk buffer */
  90. tpk_printk(NULL, 0);
  91. spin_unlock_irqrestore(&tpkp->spinlock, flags);
  92. tty_port_close(&tpkp->port, tty, filp);
  93. }
  94. /*
  95. * TTY operations write function.
  96. */
  97. static int tpk_write(struct tty_struct *tty,
  98. const unsigned char *buf, int count)
  99. {
  100. struct ttyprintk_port *tpkp = tty->driver_data;
  101. unsigned long flags;
  102. int ret;
  103. /* exclusive use of tpk_printk within this tty */
  104. spin_lock_irqsave(&tpkp->spinlock, flags);
  105. ret = tpk_printk(buf, count);
  106. spin_unlock_irqrestore(&tpkp->spinlock, flags);
  107. return ret;
  108. }
  109. /*
  110. * TTY operations write_room function.
  111. */
  112. static int tpk_write_room(struct tty_struct *tty)
  113. {
  114. return TPK_MAX_ROOM;
  115. }
  116. /*
  117. * TTY operations ioctl function.
  118. */
  119. static int tpk_ioctl(struct tty_struct *tty,
  120. unsigned int cmd, unsigned long arg)
  121. {
  122. struct ttyprintk_port *tpkp = tty->driver_data;
  123. if (!tpkp)
  124. return -EINVAL;
  125. switch (cmd) {
  126. /* Stop TIOCCONS */
  127. case TIOCCONS:
  128. return -EOPNOTSUPP;
  129. default:
  130. return -ENOIOCTLCMD;
  131. }
  132. return 0;
  133. }
  134. /*
  135. * TTY operations hangup function.
  136. */
  137. static void tpk_hangup(struct tty_struct *tty)
  138. {
  139. struct ttyprintk_port *tpkp = tty->driver_data;
  140. tty_port_hangup(&tpkp->port);
  141. }
  142. static const struct tty_operations ttyprintk_ops = {
  143. .open = tpk_open,
  144. .close = tpk_close,
  145. .write = tpk_write,
  146. .write_room = tpk_write_room,
  147. .ioctl = tpk_ioctl,
  148. .hangup = tpk_hangup,
  149. };
  150. static const struct tty_port_operations null_ops = { };
  151. static struct tty_driver *ttyprintk_driver;
  152. static int __init ttyprintk_init(void)
  153. {
  154. int ret;
  155. spin_lock_init(&tpk_port.spinlock);
  156. ttyprintk_driver = tty_alloc_driver(1,
  157. TTY_DRIVER_RESET_TERMIOS |
  158. TTY_DRIVER_REAL_RAW |
  159. TTY_DRIVER_UNNUMBERED_NODE);
  160. if (IS_ERR(ttyprintk_driver))
  161. return PTR_ERR(ttyprintk_driver);
  162. tty_port_init(&tpk_port.port);
  163. tpk_port.port.ops = &null_ops;
  164. ttyprintk_driver->driver_name = "ttyprintk";
  165. ttyprintk_driver->name = "ttyprintk";
  166. ttyprintk_driver->major = TTYAUX_MAJOR;
  167. ttyprintk_driver->minor_start = 3;
  168. ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
  169. ttyprintk_driver->init_termios = tty_std_termios;
  170. ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
  171. tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
  172. tty_port_link_device(&tpk_port.port, ttyprintk_driver, 0);
  173. ret = tty_register_driver(ttyprintk_driver);
  174. if (ret < 0) {
  175. printk(KERN_ERR "Couldn't register ttyprintk driver\n");
  176. goto error;
  177. }
  178. return 0;
  179. error:
  180. put_tty_driver(ttyprintk_driver);
  181. tty_port_destroy(&tpk_port.port);
  182. return ret;
  183. }
  184. static void __exit ttyprintk_exit(void)
  185. {
  186. tty_unregister_driver(ttyprintk_driver);
  187. put_tty_driver(ttyprintk_driver);
  188. tty_port_destroy(&tpk_port.port);
  189. }
  190. device_initcall(ttyprintk_init);
  191. module_exit(ttyprintk_exit);
  192. MODULE_LICENSE("GPL");