github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/pkg/ulog/klog_linux.go (about)

     1  // Copyright 2019 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ulog
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"sync/atomic"
    11  
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  // KernelLog is a logger that prints to the kernel syslog buffer.
    16  //
    17  // If the syslog buffer cannot be written to, KernelLog falls back to Log.
    18  var KernelLog = &KLog{
    19  	// Default log level is Info.
    20  	LogLevel: uintptr(KLogInfo),
    21  }
    22  
    23  func init() {
    24  	KernelLog.Reinit()
    25  }
    26  
    27  // KLog is a logger to the kernel syslog buffer.
    28  type KLog struct {
    29  	// FD for /dev/kmsg if it was openable.
    30  	*os.File
    31  
    32  	// LogLevel is the LogLevel to print with.
    33  	//
    34  	// Should only be accessed atomically.
    35  	LogLevel uintptr
    36  }
    37  
    38  // Reinit reopens the /dev/kmsg file.
    39  func (k *KLog) Reinit() {
    40  	f, _ := os.OpenFile("/dev/kmsg", os.O_RDWR, 0)
    41  	KernelLog.File = f
    42  }
    43  
    44  // writeString returns true iff it was able to write the log to /dev/kmsg.
    45  func (k *KLog) writeString(s string) bool {
    46  	if k.File == nil {
    47  		return false
    48  	}
    49  	if _, err := k.File.WriteString(fmt.Sprintf("<%d>%s", atomic.LoadUintptr(&k.LogLevel), s)); err != nil {
    50  		return false
    51  	}
    52  	return true
    53  }
    54  
    55  // Printf formats according to a format specifier and writes to kernel logging.
    56  func (k *KLog) Printf(format string, v ...interface{}) {
    57  	if !k.writeString(fmt.Sprintf(format, v...)) {
    58  		Log.Printf(format, v...)
    59  	}
    60  }
    61  
    62  // Print formats using the default operands for v and writes to kernel logging.
    63  func (k *KLog) Print(v ...interface{}) {
    64  	if !k.writeString(fmt.Sprint(v...)) {
    65  		Log.Print(v...)
    66  	}
    67  }
    68  
    69  // KLogLevel are the log levels used by printk.
    70  type KLogLevel uintptr
    71  
    72  // These are the log levels used by printk as described in syslog(2).
    73  const (
    74  	KLogEmergency KLogLevel = 0
    75  	KLogAlert     KLogLevel = 1
    76  	KLogCritical  KLogLevel = 2
    77  	KLogError     KLogLevel = 3
    78  	KLogWarning   KLogLevel = 4
    79  	KLogNotice    KLogLevel = 5
    80  	KLogInfo      KLogLevel = 6
    81  	KLogDebug     KLogLevel = 7
    82  )
    83  
    84  const (
    85  	_SYSLOG_ACTION_READ_ALL      = 3
    86  	_SYSLOG_ACTION_READ_CLEAR    = 4
    87  	_SYSLOG_ACTION_CLEAR         = 5
    88  	_SYSLOG_ACTION_CONSOLE_LEVEL = 8
    89  )
    90  
    91  // SetConsoleLogLevel sets the console level with syslog(2).
    92  //
    93  // After this call, only messages with a level value lower than the one
    94  // specified will be printed to console by the kernel.
    95  func (k *KLog) SetConsoleLogLevel(level KLogLevel) error {
    96  	if _, _, err := unix.Syscall(unix.SYS_SYSLOG, _SYSLOG_ACTION_CONSOLE_LEVEL, 0, uintptr(level)); err != 0 {
    97  		return fmt.Errorf("could not set syslog level to %d: %v", level, err)
    98  	}
    99  	return nil
   100  }
   101  
   102  // SetLogLevel sets the level that Printf and Print log to syslog with.
   103  func (k *KLog) SetLogLevel(level KLogLevel) {
   104  	atomic.StoreUintptr(&k.LogLevel, uintptr(level))
   105  }
   106  
   107  // ClearLog clears kernel logs back to empty.
   108  func (k *KLog) ClearLog() error {
   109  	_, err := unix.Klogctl(_SYSLOG_ACTION_CLEAR, nil)
   110  	return err
   111  }
   112  
   113  // Read reads from the tail of the kernel log.
   114  func (k *KLog) Read(b []byte) (int, error) {
   115  	return unix.Klogctl(_SYSLOG_ACTION_READ_ALL, b)
   116  }
   117  
   118  // ReadClear reads from the tail of the kernel log and clears what was read.
   119  func (k *KLog) ReadClear(b []byte) (int, error) {
   120  	return unix.Klogctl(_SYSLOG_ACTION_READ_CLEAR, b)
   121  }