home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / kernel / printk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  5.3 KB  |  233 lines

  1. /*
  2.  *  linux/kernel/printk.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  *
  6.  * Modified to make sys_syslog() more flexible: added commands to
  7.  * return the last 4k of kernel messages, regardless of whether
  8.  * they've been read or not.  Added option to suppress kernel printk's
  9.  * to the console.  Added hook for sending the console messages
  10.  * elsewhere, in preparation for a serial line console (someday).
  11.  * Ted Ts'o, 2/11/93.
  12.  *
  13.  * This file is subject to the terms and conditions of the GNU General Public
  14.  * License.  See the file README.legal in the main directory of this archive
  15.  * for more details.
  16.  */
  17.  
  18. #include <stdarg.h>
  19.  
  20. #include <asm/segment.h>
  21. #include <asm/system.h>
  22.  
  23. #include <linux/errno.h>
  24. #include <linux/sched.h>
  25. #include <linux/kernel.h>
  26.  
  27. #define LOG_BUF_LEN    4096
  28.  
  29. static char buf[1024];
  30.  
  31. extern int vsprintf(char * buf, const char * fmt, va_list args);
  32. extern void console_print(const char *);
  33.  
  34. #define DEFAULT_MESSAGE_LOGLEVEL 7 /* KERN_DEBUG */
  35. #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything more serious than KERN_DEBUG */
  36.  
  37. unsigned long log_size = 0;
  38. struct wait_queue * log_wait = NULL;
  39. int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
  40.  
  41. static void (*console_print_proc)(const char *) = 0;
  42. static char log_buf[LOG_BUF_LEN];
  43. static unsigned long log_start = 0;
  44. static unsigned long logged_chars = 0;
  45.  
  46. /*
  47.  * Commands to sys_syslog:
  48.  *
  49.  *     0 -- Close the log.  Currently a NOP.
  50.  *     1 -- Open the log. Currently a NOP.
  51.  *     2 -- Read from the log.
  52.  *     3 -- Read up to the last 4k of messages in the ring buffer.
  53.  *     4 -- Read and clear last 4k of messages in the ring buffer
  54.  *     5 -- Clear ring buffer.
  55.  *     6 -- Disable printk's to console
  56.  *     7 -- Enable printk's to console
  57.  *    8 -- Set level of messages printed to console
  58.  */
  59. asmlinkage int sys_syslog(int type, char * buf, int len)
  60. {
  61.     unsigned long i, j, count;
  62.     int do_clear = 0;
  63.     char c;
  64.     int error;
  65.  
  66.     if ((type != 3) && !suser())
  67.         return -EPERM;
  68.     switch (type) {
  69.         case 0:        /* Close log */
  70.             return 0;
  71.         case 1:        /* Open log */
  72.             return 0;
  73.         case 2:        /* Read from log */
  74.             if (!buf || len < 0)
  75.                 return -EINVAL;
  76.             if (!len)
  77.                 return 0;
  78.             error = verify_area(VERIFY_WRITE,buf,len);
  79.             if (error)
  80.                 return error;
  81.             cli();
  82.             while (!log_size) {
  83.                 if (current->signal & ~current->blocked) {
  84.                     sti();
  85.                     return -ERESTARTSYS;
  86.                 }
  87.                     interruptible_sleep_on(&log_wait);
  88.             }
  89.             i = 0;
  90.             while (log_size && i < len) {
  91.                 c = *((char *) log_buf+log_start);
  92.                 log_start++;
  93.                 log_size--;
  94.                 log_start &= LOG_BUF_LEN-1;
  95.                 put_fs_byte(c,buf);
  96.                 buf++;
  97.                 i++;
  98.             }
  99.             sti();
  100.             return i;
  101.         case 4:        /* Read/clear last kernel messages */
  102.             do_clear = 1; 
  103.             /* FALL THRU */
  104.         case 3:        /* Read last kernel messages */
  105.             if (!buf || len < 0)
  106.                 return -EINVAL;
  107.             if (!len)
  108.                 return 0;
  109.             error = verify_area(VERIFY_WRITE,buf,len);
  110.             if (error)
  111.                 return error;
  112.             count = len;
  113.             if (count > LOG_BUF_LEN)
  114.                 count = LOG_BUF_LEN;
  115.             if (count > logged_chars)
  116.                 count = logged_chars;
  117.             j = log_start + log_size - count;
  118.             for (i = 0; i < count; i++) {
  119.                 c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
  120.                 put_fs_byte(c, buf++);
  121.             }
  122.             if (do_clear)
  123.                 logged_chars = 0;
  124.             return i;
  125.         case 5:        /* Clear ring buffer */
  126.             logged_chars = 0;
  127.             return 0;
  128.         case 6:        /* Disable logging to console */
  129.             console_loglevel = 1; /* only panic messages shown */
  130.             return 0;
  131.         case 7:        /* Enable logging to console */
  132.             console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
  133.             return 0;
  134.         case 8:
  135.             if (len < 0 || len > 8)
  136.                 return -EINVAL;
  137.             console_loglevel = len;
  138.             return 0;
  139.     }
  140.     return -EINVAL;
  141. }
  142.  
  143.  
  144. asmlinkage int printk(const char *fmt, ...)
  145. {
  146.     va_list args;
  147.     int i;
  148.     char *msg, *p, *buf_end;
  149.     static char msg_level = -1;
  150.     long flags;
  151.  
  152.     save_flags(flags);
  153.     cli();
  154.     va_start(args, fmt);
  155.     i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
  156.     buf_end = buf + 3 + i;
  157.     va_end(args);
  158.     for (p = buf + 3; p < buf_end; p++) {
  159.         msg = p;
  160.         if (msg_level < 0) {
  161.             if (
  162.                 p[0] != '<' ||
  163.                 p[1] < '0' || 
  164.                 p[1] > '7' ||
  165.                 p[2] != '>'
  166.             ) {
  167.                 p -= 3;
  168.                 p[0] = '<';
  169.                 p[1] = DEFAULT_MESSAGE_LOGLEVEL - 1 + '0';
  170.                 p[2] = '>';
  171.             } else
  172.                 msg += 3;
  173.             msg_level = p[1] - '0';
  174.         }
  175.         for (; p < buf_end; p++) {
  176.             log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p;
  177.             if (log_size < LOG_BUF_LEN)
  178.                 log_size++;
  179.             else
  180.                 log_start++;
  181.             logged_chars++;
  182.             if (*p == '\n')
  183.                 break;
  184.         }
  185.         if (msg_level < console_loglevel && console_print_proc) {
  186.             char tmp = p[1];
  187.             p[1] = '\0';
  188.             (*console_print_proc)(msg);
  189.             p[1] = tmp;
  190.         }
  191.         if (*p == '\n')
  192.             msg_level = -1;
  193.     }
  194.     restore_flags(flags);
  195.     wake_up_interruptible(&log_wait);
  196.     return i;
  197. }
  198.  
  199. /*
  200.  * The console driver calls this routine during kernel initialization
  201.  * to register the console printing procedure with printk() and to
  202.  * print any messages that were printed by the kernel before the
  203.  * console driver was initialized.
  204.  */
  205. void register_console(void (*proc)(const char *))
  206. {
  207.     int    i,j;
  208.     int    p = log_start;
  209.     char    buf[16];
  210.     char    msg_level = -1;
  211.     char    *q;
  212.  
  213.     console_print_proc = proc;
  214.  
  215.     for (i=0,j=0; i < log_size; i++) {
  216.         buf[j++] = log_buf[p];
  217.         p++; p &= LOG_BUF_LEN-1;
  218.         if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
  219.             continue;
  220.         buf[j] = 0;
  221.         q = buf;
  222.         if (msg_level < 0) {
  223.             msg_level = buf[1] - '0';
  224.             q = buf + 3;
  225.         }
  226.         if (msg_level < console_loglevel)
  227.             (*proc)(q);
  228.         if (buf[j-1] == '\n')
  229.             msg_level = -1;
  230.         j = 0;
  231.     }
  232. }
  233.