LCOV - code coverage report
Current view: top level - drivers/char - ttyprintk.c (source / functions) Hit Total Coverage
Test: Real Lines: 17 70 24.3 %
Date: 2020-10-17 15:46:43 Functions: 0 9 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

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

Generated by: LCOV version 1.14