netlib.narod.ru< Назад | Оглавление | Далее >

kernel/printk.c

25610 /*
25611  *  linux/kernel/printk.c
25612  *
25613  *  Copyright (C) 1991, 1992  Linus Torvalds
25614  *
25615  * Modified to make sys_syslog() more flexible: added
25616  * commands to return the last 4k of kernel messages,
25617  * regardless of whether they've been read or not.  Added
25618  * option to suppress kernel printk's to the console.
25619  * Added hook for sending the console messages elsewhere,
25620  * in preparation for a serial line console (someday).
25621  * Ted Ts'o, 2/11/93.
25622  * Modified for sysctl support, 1/8/97, Chris Horn.
25623  */
25624 #include <linux/mm.h>
25625 #include <linux/tty_driver.h>
25626 #include <linux/smp_lock.h>
25627 #include <linux/console.h>
25628 #include <linux/init.h>
25629 
25630 #include <asm/uaccess.h>
25631 
25632 #define LOG_BUF_LEN     (16384)
25633 
25634 static char buf[1024];
25635 
25636 /* printk's without a loglevel use this.. */
25637 #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
25638 
25639 /* We show everything that is MORE important than
25640  * this.. */
25641 /* Minimum loglevel we let people use */
25642 #define MINIMUM_CONSOLE_LOGLEVEL 1
25643 /* anything MORE serious than KERN_DEBUG */
25644 #define DEFAULT_CONSOLE_LOGLEVEL 7
25645 
25646 unsigned long log_size = 0;
25647 struct wait_queue * log_wait = NULL;
25648 
25649 /* Keep together for sysctl support */
25650 int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
25651 int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL;
25652 int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
25653 int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
25654 
25655 struct console *console_drivers = NULL;
25656 static char log_buf[LOG_BUF_LEN];
25657 static unsigned long log_start = 0;
25658 static unsigned long logged_chars = 0;
25659 struct console_cmdline
25660   console_cmdline[MAX_CMDLINECONSOLES];
25661 static int preferred_console = -1;
25662 
25663 /* Setup a list of consoles. Called from init/main.c */
25664 void __init console_setup(char *str, int *ints)
25665 {
25666   struct console_cmdline *c;
25667   char name[sizeof(c->name)];
25668   char *s, *options;
25669   int i, idx;
25670 
25671   /* Decode str into name, index, options. */
25672   if (str[0] >= '0' && str[0] <= '9') {
25673     strcpy(name, "ttyS");
25674     strncpy(name + 4, str, sizeof(name) - 5);
25675   } else
25676     strncpy(name, str, sizeof(name) - 1);
25677   name[sizeof(name) - 1] = 0;
25678   if ((options = strchr(str, ',')) != NULL)
25679     *(options++) = 0;
25680 #ifdef __sparc__
25681   if (!strcmp(str, "ttya"))
25682     strcpy(name, "ttyS0");
25683   if (!strcmp(str, "ttyb"))
25684     strcpy(name, "ttyS1");
25685 #endif
25686   for(s = name; *s; s++)
25687     if (*s >= '0' && *s <= '9')
25688       break;
25689   idx = simple_strtoul(s, NULL, 10);
25690   *s = 0;
25691 
25692   /* See if this tty is not yet registered, and if we
25693    * have a slot free. */
25694   for(i = 0; i < MAX_CMDLINECONSOLES &&
25695         console_cmdline[i].name[0]; i++)
25696     if (strcmp(console_cmdline[i].name, name) == 0 &&
25697         console_cmdline[i].index == idx) {
25698         preferred_console = i;
25699         return;
25700     }
25701   if (i == MAX_CMDLINECONSOLES)
25702     return;
25703   preferred_console = i;
25704   c = &console_cmdline[i];
25705   memcpy(c->name, name, sizeof(c->name));
25706   c->options = options;
25707   c->index = idx;
25708 }
25709 
25710 /* Commands to do_syslog:
25711  *
25712  *  0 -- Close the log.  Currently a NOP.
25713  *  1 -- Open the log. Currently a NOP.
25714  *  2 -- Read from the log.
25715  *  3 -- Read up to the last 4k of messages in the
25716  *       ring buffer.
25717  *  4 -- Read and clear last 4k of messages in the
25718  *       ring buffer.
25719  *  5 -- Clear ring buffer.
25720  *  6 -- Disable printk's to console
25721  *  7 -- Enable printk's to console
25722  *  8 -- Set level of messages printed to console
25723  */
25724 int do_syslog(int type, char * buf, int len)
25725 {
25726   unsigned long i, j, count, flags;
25727   int do_clear = 0;
25728   char c;
25729   int error = -EPERM;
25730 
25731   lock_kernel();
25732   error = 0;
25733   switch (type) {
25734   case 0:         /* Close log */
25735     break;
25736   case 1:         /* Open log */
25737     break;
25738   case 2:         /* Read from log */
25739     error = -EINVAL;
25740     if (!buf || len < 0)
25741       goto out;
25742     error = 0;
25743     if (!len)
25744       goto out;
25745     error = verify_area(VERIFY_WRITE,buf,len);
25746     if (error)
25747       goto out;
25748     error = wait_event_interruptible(log_wait, log_size);
25749     if (error)
25750       goto out;
25751     i = 0;
25752     while (log_size && i < len) {
25753       c = *((char *) log_buf+log_start);
25754       log_start++;
25755       log_size--;
25756       log_start &= LOG_BUF_LEN-1;
25757       sti();
25758       __put_user(c,buf);
25759       buf++;
25760       i++;
25761       cli();
25762     }
25763     sti();
25764     error = i;
25765     break;
25766   case 4:         /* Read/clear last kernel messages */
25767     do_clear = 1;
25768     /* FALL THRU */
25769   case 3:         /* Read last kernel messages */
25770     error = -EINVAL;
25771     if (!buf || len < 0)
25772       goto out;
25773     error = 0;
25774     if (!len)
25775       goto out;
25776     error = verify_area(VERIFY_WRITE,buf,len);
25777     if (error)
25778       goto out;
25779     /* The logged_chars, log_start, and log_size values
25780      * may change from an interrupt, so we disable
25781      * interrupts.  */
25782     __save_flags(flags);
25783     __cli();
25784     count = len;
25785     if (count > LOG_BUF_LEN)
25786       count = LOG_BUF_LEN;
25787     if (count > logged_chars)
25788       count = logged_chars;
25789     j = log_start + log_size - count;
25790     __restore_flags(flags);
25791     for (i = 0; i < count; i++) {
25792       c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1)));
25793       __put_user(c, buf++);
25794     }
25795     if (do_clear)
25796       logged_chars = 0;
25797     error = i;
25798     break;
25799   case 5:         /* Clear ring buffer */
25800     logged_chars = 0;
25801     break;
25802   case 6:         /* Disable logging to console */
25803     console_loglevel = minimum_console_loglevel;
25804     break;
25805   case 7:         /* Enable logging to console */
25806     console_loglevel = default_console_loglevel;
25807     break;
25808   case 8:
25809     error = -EINVAL;
25810     if (len < 1 || len > 8)
25811       goto out;
25812     if (len < minimum_console_loglevel)
25813       len = minimum_console_loglevel;
25814     console_loglevel = len;
25815     error = 0;
25816     break;
25817   default:
25818     error = -EINVAL;
25819     break;
25820   }
25821 out:
25822   unlock_kernel();
25823   return error;
25824 }
25825 
25826 asmlinkage int sys_syslog(int type, char * buf, int len)
25827 {
25828   if ((type != 3) && !capable(CAP_SYS_ADMIN))
25829     return -EPERM;
25830   return do_syslog(type, buf, len);
25831 }
25832 
25833 
25834 spinlock_t console_lock;
25835 
 Комментарий
25836 asmlinkage int printk(const char *fmt, ...)
25837 {
25838   va_list args;
25839   int i;
25840   char *msg, *p, *buf_end;
25841   int line_feed;
25842   static signed char msg_level = -1;
25843   long flags;
25844 
25845   spin_lock_irqsave(&console_lock, flags);
25846   va_start(args, fmt);
25847   /* hopefully i < sizeof(buf)-4 */
25848   i = vsprintf(buf + 3, fmt, args);
25849   buf_end = buf + 3 + i;
25850   va_end(args);
25851   for (p = buf + 3; p < buf_end; p++) {
25852     msg = p;
25853     if (msg_level < 0) {
25854       if (
25855         p[0] != '<' ||
25856         p[1] < '0' ||
25857         p[1] > '7' ||
25858         p[2] != '>'
25859       ) {
25860         p -= 3;
25861         p[0] = '<';
25862         p[1] = default_message_loglevel + '0';
25863         p[2] = '>';
25864       } else
25865         msg += 3;
25866       msg_level = p[1] - '0';
25867     }
25868     line_feed = 0;
25869     for (; p < buf_end; p++) {
25870       log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)]
25871         = *p;
25872       if (log_size < LOG_BUF_LEN)
25873         log_size++;
25874       else {
25875         log_start++;
25876         log_start &= LOG_BUF_LEN-1;
25877       }
25878       logged_chars++;
25879       if (*p == '\n') {
25880         line_feed = 1;
25881         break;
25882       }
25883     }
25884     if (msg_level < console_loglevel && console_drivers){
25885       struct console *c = console_drivers;
25886       while(c) {
25887         if ((c->flags & CON_ENABLED) && c->write)
25888           c->write(c, msg, p - msg + line_feed);
25889         c = c->next;
25890       }
25891     }
25892     if (line_feed)
25893       msg_level = -1;
25894   }
25895   spin_unlock_irqrestore(&console_lock, flags);
25896   wake_up_interruptible(&log_wait);
25897   return i;
25898 }
25899 
25900 void console_print(const char *s)
25901 {
25902   struct console *c = console_drivers;
25903   int len = strlen(s);
25904 
25905   while(c) {
25906     if ((c->flags & CON_ENABLED) && c->write)
25907       c->write(c, s, len);
25908     c = c->next;
25909   }
25910 }
25911 
25912 void unblank_console(void)
25913 {
25914   struct console *c = console_drivers;
25915   while(c) {
25916     if ((c->flags & CON_ENABLED) && c->unblank)
25917       c->unblank();
25918     c = c->next;
25919   }
25920 }
25921 
25922 /* The console driver calls this routine during kernel
25923  * initialization to register the console printing
25924  * procedure with printk() and to print any messages that
25925  * were printed by the kernel before the console driver
25926  * was initialized.  */
25927 void register_console(struct console * console)
25928 {
25929   int     i,j,len;
25930   int     p = log_start;
25931   char    buf[16];
25932   signed char msg_level = -1;
25933   char    *q;
25934 
25935   /* See if we want to use this console driver. If we
25936    * didn't select a console we take the first one that
25937    * registers here.  */
25938   if (preferred_console < 0) {
25939     if (console->index < 0)
25940       console->index = 0;
25941     if (console->setup == NULL ||
25942         console->setup(console, NULL) == 0) {
25943       console->flags |= CON_ENABLED | CON_CONSDEV;
25944       preferred_console = 0;
25945     }
25946   }
25947 
25948   /* See if this console matches one we selected on the
25949    * command line.  */
25950   for (i = 0;
25951        i < MAX_CMDLINECONSOLES &&
25952          console_cmdline[i].name[0];
25953        i++) {
25954     if (strcmp(console_cmdline[i].name, console->name))
25955       continue;
25956     if (console->index >= 0 &&
25957         console->index != console_cmdline[i].index)
25958       continue;
25959     if (console->index < 0)
25960       console->index = console_cmdline[i].index;
25961     if (console->setup &&
25962         console->setup(console,
25963                        console_cmdline[i].options) != 0)
25964       break;
25965     console->flags |= CON_ENABLED;
25966     console->index = console_cmdline[i].index;
25967     if (i == preferred_console)
25968       console->flags |= CON_CONSDEV;
25969     break;
25970   }
25971 
25972   if (!(console->flags & CON_ENABLED))
25973     return;
25974 
25975   /* Put this console in the list - keep the preferred
25976    * driver at the head of the list.  */
25977   if ((console->flags & CON_CONSDEV) ||
25978       console_drivers == NULL) {
25979     console->next = console_drivers;
25980     console_drivers = console;
25981   } else {
25982     console->next = console_drivers->next;
25983     console_drivers->next = console;
25984   }
25985   if ((console->flags & CON_PRINTBUFFER) == 0) return;
25986 
25987   /* Print out buffered log messages.  */
25988   for (i=0,j=0; i < log_size; i++) {
25989     buf[j++] = log_buf[p];
25990     p++; p &= LOG_BUF_LEN-1;
25991     if (buf[j-1] != '\n' && i < log_size - 1 &&
25992         j < sizeof(buf)-1)
25993       continue;
25994     buf[j] = 0;
25995     q = buf;
25996     len = j;
25997     if (msg_level < 0) {
25998       msg_level = buf[1] - '0';
25999       q = buf + 3;
26000       len -= 3;
26001     }
26002     if (msg_level < console_loglevel)
26003       console->write(console, q, len);
26004     if (buf[j-1] == '\n')
26005       msg_level = -1;
26006     j = 0;
26007   }
26008 }
26009 
26010 
26011 int unregister_console(struct console * console)
26012 {
26013   struct console *a,*b;
26014 
26015   if (console_drivers == console) {
26016     console_drivers=console->next;
26017     return (0);
26018   }
26019   for (a = console_drivers->next, b = console_drivers;
26020        a; b = a, a = b->next) {
26021     if (a == console) {
26022       b->next = a->next;
26023       return 0;
26024     }
26025   }
26026 
26027   return (1);
26028 }
26029 
26030 /* Write a message to a certain tty, not just the
26031  * console. This is used for messages that need to be
26032  * redirected to a specific tty.  We don't put it into
26033  * the syslog queue right now maybe in the future if
26034  * really needed.  */
26035 void tty_write_message(struct tty_struct *tty, char *msg)
26036 {
26037   if (tty && tty->driver.write)
26038     tty->driver.write(tty, 0, msg, strlen(msg));
26039   return;
26040 }

netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz