linux-bk/kernel/printk.c
<<
>>
Prefs
   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 * Modified for sysctl support, 1/8/97, Chris Horn.
  13 * Fixed SMP synchronization, 08/08/99, Manfred Spraul 
  14 *     manfreds@colorfullife.com
  15 * Rewrote bits to get rid of console_lock
  16 *      01Mar01 Andrew Morton <andrewm@uow.edu.au>
  17 */
  18
  19#include <linux/mm.h>
  20#include <linux/tty.h>
  21#include <linux/tty_driver.h>
  22#include <linux/smp_lock.h>
  23#include <linux/console.h>
  24#include <linux/init.h>
  25#include <linux/module.h>
  26#include <linux/interrupt.h>                    /* For in_interrupt() */
  27#include <linux/config.h>
  28#include <linux/slab.h>
  29#include <linux/delay.h>
  30
  31#include <asm/uaccess.h>
  32
  33#if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64)
  34#define LOG_BUF_LEN     (65536)
  35#elif defined(CONFIG_ARCH_S390)
  36#define LOG_BUF_LEN     (131072)
  37#elif defined(CONFIG_SMP)
  38#define LOG_BUF_LEN     (32768)
  39#else   
  40#define LOG_BUF_LEN     (16384)                 /* This must be a power of two */
  41#endif
  42
  43#define LOG_BUF_MASK    (LOG_BUF_LEN-1)
  44
  45#ifndef arch_consoles_callable
  46#define arch_consoles_callable() (1)
  47#endif
  48
  49/* printk's without a loglevel use this.. */
  50#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
  51
  52/* We show everything that is MORE important than this.. */
  53#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
  54#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
  55
  56DECLARE_WAIT_QUEUE_HEAD(log_wait);
  57
  58/* Keep together for sysctl support */
  59int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
  60int default_message_loglevel = DEFAULT_MESSAGE_LOGLEVEL;
  61int minimum_console_loglevel = MINIMUM_CONSOLE_LOGLEVEL;
  62int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;
  63
  64int oops_in_progress;
  65
  66/*
  67 * console_sem protects the console_drivers list, and also
  68 * provides serialisation for access to the entire console
  69 * driver system.
  70 */
  71static DECLARE_MUTEX(console_sem);
  72struct console *console_drivers;
  73
  74/*
  75 * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars
  76 * It is also used in interesting ways to provide interlocking in
  77 * release_console_sem().
  78 */
  79static spinlock_t logbuf_lock = SPIN_LOCK_UNLOCKED;
  80
  81static char log_buf[LOG_BUF_LEN];
  82#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
  83
  84/*
  85 * The indices into log_buf are not constrained to LOG_BUF_LEN - they
  86 * must be masked before subscripting
  87 */
  88static unsigned long log_start;                 /* Index into log_buf: next char to be read by syslog() */
  89static unsigned long con_start;                 /* Index into log_buf: next char to be sent to consoles */
  90static unsigned long log_end;                   /* Index into log_buf: most-recently-written-char + 1 */
  91static unsigned long logged_chars;              /* Number of chars produced since last read+clear operation */
  92
  93struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
  94static int preferred_console = -1;
  95
  96/* Flag: console code may call schedule() */
  97static int console_may_schedule;
  98
  99/*
 100 *      Setup a list of consoles. Called from init/main.c
 101 */
 102static int __init console_setup(char *str)
 103{
 104        struct console_cmdline *c;
 105        char name[sizeof(c->name)];
 106        char *s, *options;
 107        int i, idx;
 108
 109        /*
 110         *      Decode str into name, index, options.
 111         */
 112        if (str[0] >= '0' && str[0] <= '9') {
 113                strcpy(name, "ttyS");
 114                strncpy(name + 4, str, sizeof(name) - 5);
 115        } else
 116                strncpy(name, str, sizeof(name) - 1);
 117        name[sizeof(name) - 1] = 0;
 118        if ((options = strchr(str, ',')) != NULL)
 119                *(options++) = 0;
 120#ifdef __sparc__
 121        if (!strcmp(str, "ttya"))
 122                strcpy(name, "ttyS0");
 123        if (!strcmp(str, "ttyb"))
 124                strcpy(name, "ttyS1");
 125#endif
 126        for(s = name; *s; s++)
 127                if (*s >= '0' && *s <= '9')
 128                        break;
 129        idx = simple_strtoul(s, NULL, 10);
 130        *s = 0;
 131
 132        /*
 133         *      See if this tty is not yet registered, and
 134         *      if we have a slot free.
 135         */
 136        for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
 137                if (strcmp(console_cmdline[i].name, name) == 0 &&
 138                          console_cmdline[i].index == idx) {
 139                                preferred_console = i;
 140                                return 1;
 141                }
 142        if (i == MAX_CMDLINECONSOLES)
 143                return 1;
 144        preferred_console = i;
 145        c = &console_cmdline[i];
 146        memcpy(c->name, name, sizeof(c->name));
 147        c->options = options;
 148        c->index = idx;
 149        return 1;
 150}
 151
 152__setup("console=", console_setup);
 153
 154/*
 155 * Commands to do_syslog:
 156 *
 157 *      0 -- Close the log.  Currently a NOP.
 158 *      1 -- Open the log. Currently a NOP.
 159 *      2 -- Read from the log.
 160 *      3 -- Read all messages remaining in the ring buffer.
 161 *      4 -- Read and clear all messages remaining in the ring buffer
 162 *      5 -- Clear ring buffer.
 163 *      6 -- Disable printk's to console
 164 *      7 -- Enable printk's to console
 165 *      8 -- Set level of messages printed to console
 166 *      9 -- Return number of unread characters in the log buffer
 167 *     10 -- Printk from userspace.  Includes loglevel.  Returns number of
 168 *           chars printed.
 169 */
 170int do_syslog(int type, char * buf, int len)
 171{
 172        unsigned long i, j, limit, count;
 173        int do_clear = 0;
 174        char c;
 175        char *lbuf = NULL;
 176        int error = 0;
 177
 178        switch (type) {
 179        case 0:         /* Close log */
 180                break;
 181        case 1:         /* Open log */
 182                break;
 183        case 2:         /* Read from log */
 184                error = -EINVAL;
 185                if (!buf || len < 0)
 186                        goto out;
 187                error = 0;
 188                if (!len)
 189                        goto out;
 190                error = verify_area(VERIFY_WRITE,buf,len);
 191                if (error)
 192                        goto out;
 193                error = wait_event_interruptible(log_wait, (log_start - log_end));
 194                if (error)
 195                        goto out;
 196                i = 0;
 197                spin_lock_irq(&logbuf_lock);
 198                while ((log_start != log_end) && i < len) {
 199                        c = LOG_BUF(log_start);
 200                        log_start++;
 201                        spin_unlock_irq(&logbuf_lock);
 202                        __put_user(c,buf);
 203                        buf++;
 204                        i++;
 205                        spin_lock_irq(&logbuf_lock);
 206                }
 207                spin_unlock_irq(&logbuf_lock);
 208                error = i;
 209                break;
 210        case 4:         /* Read/clear last kernel messages */
 211                do_clear = 1; 
 212                /* FALL THRU */
 213        case 3:         /* Read last kernel messages */
 214                error = -EINVAL;
 215                if (!buf || len < 0)
 216                        goto out;
 217                error = 0;
 218                if (!len)
 219                        goto out;
 220                error = verify_area(VERIFY_WRITE,buf,len);
 221                if (error)
 222                        goto out;
 223                count = len;
 224                if (count > LOG_BUF_LEN)
 225                        count = LOG_BUF_LEN;
 226                spin_lock_irq(&logbuf_lock);
 227                if (count > logged_chars)
 228                        count = logged_chars;
 229                if (do_clear)
 230                        logged_chars = 0;
 231                limit = log_end;
 232                /*
 233                 * __put_user() could sleep, and while we sleep
 234                 * printk() could overwrite the messages 
 235                 * we try to copy to user space. Therefore
 236                 * the messages are copied in reverse. <manfreds>
 237                 */
 238                for(i=0;i < count;i++) {
 239                        j = limit-1-i;
 240                        if (j+LOG_BUF_LEN < log_end)
 241                                break;
 242                        c = LOG_BUF(j);
 243                        spin_unlock_irq(&logbuf_lock);
 244                        __put_user(c,&buf[count-1-i]);
 245                        spin_lock_irq(&logbuf_lock);
 246                }
 247                spin_unlock_irq(&logbuf_lock);
 248                error = i;
 249                if(i != count) {
 250                        int offset = count-error;
 251                        /* buffer overflow during copy, correct user buffer. */
 252                        for(i=0;i<error;i++) {
 253                                __get_user(c,&buf[i+offset]);
 254                                __put_user(c,&buf[i]);
 255                        }
 256                }
 257
 258                break;
 259        case 5:         /* Clear ring buffer */
 260                spin_lock_irq(&logbuf_lock);
 261                logged_chars = 0;
 262                spin_unlock_irq(&logbuf_lock);
 263                break;
 264        case 6:         /* Disable logging to console */
 265                spin_lock_irq(&logbuf_lock);
 266                console_loglevel = minimum_console_loglevel;
 267                spin_unlock_irq(&logbuf_lock);
 268                break;
 269        case 7:         /* Enable logging to console */
 270                spin_lock_irq(&logbuf_lock);
 271                console_loglevel = default_console_loglevel;
 272                spin_unlock_irq(&logbuf_lock);
 273                break;
 274        case 8:         /* Set level of messages printed to console */
 275                error = -EINVAL;
 276                if (len < 1 || len > 8)
 277                        goto out;
 278                if (len < minimum_console_loglevel)
 279                        len = minimum_console_loglevel;
 280                spin_lock_irq(&logbuf_lock);
 281                console_loglevel = len;
 282                spin_unlock_irq(&logbuf_lock);
 283                error = 0;
 284                break;
 285        case 9:         /* Number of chars in the log buffer */
 286                spin_lock_irq(&logbuf_lock);
 287                error = log_end - log_start;
 288                spin_unlock_irq(&logbuf_lock);
 289                break;
 290        case 10:
 291                lbuf = kmalloc(len + 1, GFP_KERNEL);
 292                error = -ENOMEM;
 293                if (lbuf == NULL)
 294                        break;
 295                error = -EFAULT;
 296                if (copy_from_user(lbuf, buf, len))
 297                        break;
 298                lbuf[len] = '\0';
 299                error = printk("%s", lbuf);
 300                break;
 301        default:
 302                error = -EINVAL;
 303                break;
 304        }
 305out:
 306        kfree(lbuf);
 307        return error;
 308}
 309
 310asmlinkage long sys_syslog(int type, char * buf, int len)
 311{
 312        if ((type != 3) && !capable(CAP_SYS_ADMIN))
 313                return -EPERM;
 314        return do_syslog(type, buf, len);
 315}
 316
 317/*
 318 * Call the console drivers on a range of log_buf
 319 */
 320static void __call_console_drivers(unsigned long start, unsigned long end)
 321{
 322        struct console *con;
 323
 324        for (con = console_drivers; con; con = con->next) {
 325                if ((con->flags & CON_ENABLED) && con->write)
 326                        con->write(con, &LOG_BUF(start), end - start);
 327        }
 328}
 329
 330/*
 331 * Write out chars from start to end - 1 inclusive
 332 */
 333static void _call_console_drivers(unsigned long start, unsigned long end, int msg_log_level)
 334{
 335        if (msg_log_level < console_loglevel && console_drivers && start != end) {
 336                if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
 337                        /* wrapped write */
 338                        __call_console_drivers(start & LOG_BUF_MASK, LOG_BUF_LEN);
 339                        __call_console_drivers(0, end & LOG_BUF_MASK);
 340                } else {
 341                        __call_console_drivers(start, end);
 342                }
 343        }
 344}
 345
 346/*
 347 * Call the console drivers, asking them to write out
 348 * log_buf[start] to log_buf[end - 1].
 349 * The console_sem must be held.
 350 */
 351static void call_console_drivers(unsigned long start, unsigned long end)
 352{
 353        unsigned long cur_index, start_print;
 354        static int msg_level = -1;
 355
 356        if (((long)(start - end)) > 0)
 357                BUG();
 358
 359        cur_index = start;
 360        start_print = start;
 361        while (cur_index != end) {
 362                if (    msg_level < 0 &&
 363                        ((end - cur_index) > 2) &&
 364                        LOG_BUF(cur_index + 0) == '<' &&
 365                        LOG_BUF(cur_index + 1) >= '0' &&
 366                        LOG_BUF(cur_index + 1) <= '7' &&
 367                        LOG_BUF(cur_index + 2) == '>')
 368                {
 369                        msg_level = LOG_BUF(cur_index + 1) - '0';
 370                        cur_index += 3;
 371                        start_print = cur_index;
 372                }
 373                while (cur_index != end) {
 374                        char c = LOG_BUF(cur_index);
 375                        cur_index++;
 376
 377                        if (c == '\n') {
 378                                if (msg_level < 0) {
 379                                        /*
 380                                         * printk() has already given us loglevel tags in
 381                                         * the buffer.  This code is here in case the
 382                                         * log buffer has wrapped right round and scribbled
 383                                         * on those tags
 384                                         */
 385                                        msg_level = default_message_loglevel;
 386                                }
 387                                _call_console_drivers(start_print, cur_index, msg_level);
 388                                msg_level = -1;
 389                                start_print = cur_index;
 390                                break;
 391                        }
 392                }
 393        }
 394        _call_console_drivers(start_print, end, msg_level);
 395}
 396
 397static void emit_log_char(char c)
 398{
 399        LOG_BUF(log_end) = c;
 400        log_end++;
 401        if (log_end - log_start > LOG_BUF_LEN)
 402                log_start = log_end - LOG_BUF_LEN;
 403        if (log_end - con_start > LOG_BUF_LEN)
 404                con_start = log_end - LOG_BUF_LEN;
 405        if (logged_chars < LOG_BUF_LEN)
 406                logged_chars++;
 407}
 408
 409/*
 410 * This is printk.  It can be called from any context.  We want it to work.
 411 * 
 412 * We try to grab the console_sem.  If we succeed, it's easy - we log the output and
 413 * call the console drivers.  If we fail to get the semaphore we place the output
 414 * into the log buffer and return.  The current holder of the console_sem will
 415 * notice the new output in release_console_sem() and will send it to the
 416 * consoles before releasing the semaphore.
 417 *
 418 * One effect of this deferred printing is that code which calls printk() and
 419 * then changes console_loglevel may break. This is because console_loglevel
 420 * is inspected when the actual printing occurs.
 421 */
 422asmlinkage int printk(const char *fmt, ...)
 423{
 424        va_list args;
 425        unsigned long flags;
 426        int printed_len;
 427        char *p;
 428        static char printk_buf[1024];
 429        static int log_level_unknown = 1;
 430
 431        if (oops_in_progress) {
 432                /* If a crash is occurring, make sure we can't deadlock */
 433                spin_lock_init(&logbuf_lock);
 434                /* And make sure that we print immediately */
 435                init_MUTEX(&console_sem);
 436        }
 437
 438        /* This stops the holder of console_sem just where we want him */
 439        spin_lock_irqsave(&logbuf_lock, flags);
 440
 441        /* Emit the output into the temporary buffer */
 442        va_start(args, fmt);
 443        printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
 444        va_end(args);
 445
 446        /*
 447         * Copy the output into log_buf.  If the caller didn't provide
 448         * appropriate log level tags, we insert them here
 449         */
 450        for (p = printk_buf; *p; p++) {
 451                if (log_level_unknown) {
 452                        if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') {
 453                                emit_log_char('<');
 454                                emit_log_char(default_message_loglevel + '0');
 455                                emit_log_char('>');
 456                        }
 457                        log_level_unknown = 0;
 458                }
 459                emit_log_char(*p);
 460                if (*p == '\n')
 461                        log_level_unknown = 1;
 462        }
 463
 464        if (!arch_consoles_callable()) {
 465                /*
 466                 * On some architectures, the consoles are not usable
 467                 * on secondary CPUs early in the boot process.
 468                 */
 469                spin_unlock_irqrestore(&logbuf_lock, flags);
 470                goto out;
 471        }
 472        if (!down_trylock(&console_sem)) {
 473                /*
 474                 * We own the drivers.  We can drop the spinlock and let
 475                 * release_console_sem() print the text
 476                 */
 477                spin_unlock_irqrestore(&logbuf_lock, flags);
 478                console_may_schedule = 0;
 479                release_console_sem();
 480        } else {
 481                /*
 482                 * Someone else owns the drivers.  We drop the spinlock, which
 483                 * allows the semaphore holder to proceed and to call the
 484                 * console drivers with the output which we just produced.
 485                 */
 486                spin_unlock_irqrestore(&logbuf_lock, flags);
 487        }
 488out:
 489        return printed_len;
 490}
 491EXPORT_SYMBOL(printk);
 492
 493/**
 494 * acquire_console_sem - lock the console system for exclusive use.
 495 *
 496 * Acquires a semaphore which guarantees that the caller has
 497 * exclusive access to the console system and the console_drivers list.
 498 *
 499 * Can sleep, returns nothing.
 500 */
 501void acquire_console_sem(void)
 502{
 503        if (in_interrupt())
 504                BUG();
 505        down(&console_sem);
 506        console_may_schedule = 1;
 507}
 508EXPORT_SYMBOL(acquire_console_sem);
 509
 510/**
 511 * release_console_sem - unlock the console system
 512 *
 513 * Releases the semaphore which the caller holds on the console system
 514 * and the console driver list.
 515 *
 516 * While the semaphore was held, console output may have been buffered
 517 * by printk().  If this is the case, release_console_sem() emits
 518 * the output prior to releasing the semaphore.
 519 *
 520 * If there is output waiting for klogd, we wake it up.
 521 *
 522 * release_console_sem() may be called from any context.
 523 */
 524void release_console_sem(void)
 525{
 526        unsigned long flags;
 527        unsigned long _con_start, _log_end;
 528        unsigned long wake_klogd = 0;
 529
 530        for ( ; ; ) {
 531                spin_lock_irqsave(&logbuf_lock, flags);
 532                wake_klogd |= log_start - log_end;
 533                if (con_start == log_end)
 534                        break;                  /* Nothing to print */
 535                _con_start = con_start;
 536                _log_end = log_end;
 537                con_start = log_end;            /* Flush */
 538                spin_unlock_irqrestore(&logbuf_lock, flags);
 539                call_console_drivers(_con_start, _log_end);
 540        }
 541        console_may_schedule = 0;
 542        up(&console_sem);
 543        spin_unlock_irqrestore(&logbuf_lock, flags);
 544        if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait))
 545                wake_up_interruptible(&log_wait);
 546}
 547
 548/** console_conditional_schedule - yield the CPU if required
 549 *
 550 * If the console code is currently allowed to sleep, and
 551 * if this CPU should yield the CPU to another task, do
 552 * so here.
 553 *
 554 * Must be called within acquire_console_sem().
 555 */
 556void console_conditional_schedule(void)
 557{
 558        if (console_may_schedule && need_resched()) {
 559                set_current_state(TASK_RUNNING);
 560                schedule();
 561        }
 562}
 563
 564void console_print(const char *s)
 565{
 566        printk(KERN_EMERG "%s", s);
 567}
 568EXPORT_SYMBOL(console_print);
 569
 570void console_unblank(void)
 571{
 572        struct console *c;
 573
 574        /*
 575         * Try to get the console semaphore. If someone else owns it
 576         * we have to return without unblanking because console_unblank
 577         * may be called in interrupt context.
 578         */
 579        if (down_trylock(&console_sem) != 0)
 580                return;
 581        console_may_schedule = 0;
 582        for (c = console_drivers; c != NULL; c = c->next)
 583                if ((c->flags & CON_ENABLED) && c->unblank)
 584                        c->unblank();
 585        release_console_sem();
 586}
 587EXPORT_SYMBOL(console_unblank);
 588
 589/*
 590 * The console driver calls this routine during kernel initialization
 591 * to register the console printing procedure with printk() and to
 592 * print any messages that were printed by the kernel before the
 593 * console driver was initialized.
 594 */
 595void register_console(struct console * console)
 596{
 597        int     i;
 598        unsigned long flags;
 599
 600        /*
 601         *      See if we want to use this console driver. If we
 602         *      didn't select a console we take the first one
 603         *      that registers here.
 604         */
 605        if (preferred_console < 0) {
 606                if (console->index < 0)
 607                        console->index = 0;
 608                if (console->setup == NULL ||
 609                    console->setup(console, NULL) == 0) {
 610                        console->flags |= CON_ENABLED | CON_CONSDEV;
 611                        preferred_console = 0;
 612                }
 613        }
 614
 615        /*
 616         *      See if this console matches one we selected on
 617         *      the command line.
 618         */
 619        for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) {
 620                if (strcmp(console_cmdline[i].name, console->name) != 0)
 621                        continue;
 622                if (console->index >= 0 &&
 623                    console->index != console_cmdline[i].index)
 624                        continue;
 625                if (console->index < 0)
 626                        console->index = console_cmdline[i].index;
 627                if (console->setup &&
 628                    console->setup(console, console_cmdline[i].options) != 0)
 629                        break;
 630                console->flags |= CON_ENABLED;
 631                console->index = console_cmdline[i].index;
 632                if (i == preferred_console)
 633                        console->flags |= CON_CONSDEV;
 634                break;
 635        }
 636
 637        if (!(console->flags & CON_ENABLED))
 638                return;
 639
 640        /*
 641         *      Put this console in the list - keep the
 642         *      preferred driver at the head of the list.
 643         */
 644        acquire_console_sem();
 645        if ((console->flags & CON_CONSDEV) || console_drivers == NULL) {
 646                console->next = console_drivers;
 647                console_drivers = console;
 648        } else {
 649                console->next = console_drivers->next;
 650                console_drivers->next = console;
 651        }
 652        if (console->flags & CON_PRINTBUFFER) {
 653                /*
 654                 * release_cosole_sem() will print out the buffered messages for us.
 655                 */
 656                spin_lock_irqsave(&logbuf_lock, flags);
 657                con_start = log_start;
 658                spin_unlock_irqrestore(&logbuf_lock, flags);
 659        }
 660        release_console_sem();
 661}
 662EXPORT_SYMBOL(register_console);
 663
 664int unregister_console(struct console * console)
 665{
 666        struct console *a,*b;
 667        int res = 1;
 668
 669        acquire_console_sem();
 670        if (console_drivers == console) {
 671                console_drivers=console->next;
 672                res = 0;
 673        } else {
 674                for (a=console_drivers->next, b=console_drivers ;
 675                     a; b=a, a=b->next) {
 676                        if (a == console) {
 677                                b->next = a->next;
 678                                res = 0;
 679                                break;
 680                        }  
 681                }
 682        }
 683        
 684        /* If last console is removed, we re-enable picking the first
 685         * one that gets registered. Without that, pmac early boot console
 686         * would prevent fbcon from taking over.
 687         */
 688        if (console_drivers == NULL)
 689                preferred_console = -1;
 690                
 691
 692        release_console_sem();
 693        return res;
 694}
 695EXPORT_SYMBOL(unregister_console);
 696        
 697/**
 698 * tty_write_message - write a message to a certain tty, not just the console.
 699 *
 700 * This is used for messages that need to be redirected to a specific tty.
 701 * We don't put it into the syslog queue right now maybe in the future if
 702 * really needed.
 703 */
 704void tty_write_message(struct tty_struct *tty, char *msg)
 705{
 706        if (tty && tty->driver.write)
 707                tty->driver.write(tty, 0, msg, strlen(msg));
 708        return;
 709}
 710
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.