github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/exp/ipmidump/ipmidump.go (about)

     1  // Copyright 2019-2020 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  // Synopsis:
     6  //
     7  //	ipmidump [-option]
     8  //
     9  // Description:
    10  //
    11  // Options:
    12  //
    13  //	-chassis : Print chassis power status.
    14  //	-sel     : Print SEL information.
    15  //	-lan     : Print IP information.
    16  //	-device  : Print device information.
    17  //	-raw     : Send raw command and print response.
    18  //	-help    : Print help message.
    19  package main
    20  
    21  import (
    22  	"flag"
    23  	"fmt"
    24  	"log"
    25  	"os"
    26  	"strconv"
    27  	"time"
    28  
    29  	"github.com/mvdan/u-root-coreutils/pkg/ipmi"
    30  )
    31  
    32  const cmd = "ipmidump [options] "
    33  
    34  var (
    35  	flagChassis = flag.Bool("chassis", false, "print chassis power status")
    36  	flagSEL     = flag.Bool("sel", false, "print SEL information")
    37  	flagLan     = flag.Bool("lan", false, "Print IP address")
    38  	flagRaw     = flag.Bool("raw", false, "Send IPMI raw command")
    39  	flagHelp    = flag.Bool("help", false, "print help message")
    40  	flagDev     = flag.Bool("device", false, "print device information")
    41  )
    42  
    43  func itob(i int) bool { return i != 0 }
    44  
    45  func init() {
    46  	defUsage := flag.Usage
    47  	flag.Usage = func() {
    48  		os.Args[0] = cmd
    49  		defUsage()
    50  	}
    51  }
    52  
    53  func main() {
    54  	flag.Parse()
    55  
    56  	if *flagHelp {
    57  		flag.Usage()
    58  		os.Exit(1)
    59  	}
    60  
    61  	if *flagChassis {
    62  		chassisInfo()
    63  	}
    64  
    65  	if *flagSEL {
    66  		selInfo()
    67  	}
    68  
    69  	if *flagLan {
    70  		lanConfig()
    71  	}
    72  
    73  	if *flagDev {
    74  		deviceID()
    75  	}
    76  
    77  	if *flagRaw {
    78  		sendRawCmd(flag.Args())
    79  	}
    80  }
    81  
    82  func chassisInfo() {
    83  	allow := map[bool]string{true: "allowed", false: "not allowed"}
    84  	act := map[bool]string{true: "active", false: "inactive"}
    85  	state := map[bool]string{true: "true", false: "false"}
    86  
    87  	policy := map[int]string{
    88  		0x0: "always-off",
    89  		0x1: "previous",
    90  		0x2: "always-on",
    91  		0x3: "unknown",
    92  	}
    93  
    94  	event := map[int]string{
    95  		0x10: "IPMI command",
    96  		0x08: "power fault",
    97  		0x04: "power interlock",
    98  		0x02: "power overload",
    99  		0x01: "AC failed",
   100  		0x00: "none",
   101  	}
   102  
   103  	ipmi, err := ipmi.Open(0)
   104  	if err != nil {
   105  		fmt.Printf("Failed to open ipmi device: %v\n", err)
   106  	}
   107  	defer ipmi.Close()
   108  
   109  	if status, err := ipmi.GetChassisStatus(); err != nil {
   110  		fmt.Printf("Failed to get chassis power status: %v\n", err)
   111  	} else {
   112  		// Current power status
   113  		data := int(status.CurrentPowerState)
   114  		fmt.Println("Chassis power status")
   115  		fmt.Println("Power Restore Policy:", policy[(data>>5)&0x03])
   116  		fmt.Println("Power Control Fault :", state[itob(data&0x10)])
   117  		fmt.Println("Power Fault         :", state[itob(data&0x08)])
   118  		fmt.Println("Power Interlock     :", act[itob(data&0x04)])
   119  		fmt.Println("Power Overload      :", state[itob(data&0x02)])
   120  		fmt.Printf("Power Status        : ")
   121  		if (data & 0x01) != 0 {
   122  			fmt.Println("on")
   123  		} else {
   124  			fmt.Println("off")
   125  		}
   126  
   127  		// Last power event
   128  		data = int(status.LastPowerEvent)
   129  		fmt.Println("Last Power Event    :", event[data&0x1F])
   130  
   131  		// Misc. chassis state
   132  		data = int(status.MiscChassisState)
   133  		fmt.Println("Misc. chassis state")
   134  		fmt.Println("Cooling/Fan Fault   :", state[itob(data&0x08)])
   135  		fmt.Println("Drive Fault         :", state[itob(data&0x04)])
   136  		fmt.Println("Front Panel Lockout :", act[itob(data&0x02)])
   137  		fmt.Println("Chass Intrusion     :", act[itob(data&0x01)])
   138  
   139  		// Front panel button (optional)
   140  		data = int(status.FrontPanelButton)
   141  		if status.FrontPanelButton != 0 {
   142  			fmt.Println("Front Panel Button")
   143  			fmt.Println("Standby Button Disable    :", allow[itob(data&0x80)])
   144  			fmt.Println("Diagnostic Buttton Disable:", allow[itob(data&0x40)])
   145  			fmt.Println("Reset Button Disable      :", allow[itob(data&0x20)])
   146  			fmt.Println("Power-off Button Disable  :", allow[itob(data&0x10)])
   147  
   148  			fmt.Println("Standby Button            :", state[itob(data&0x08)])
   149  			fmt.Println("Diagnostic Buttton        :", state[itob(data&0x04)])
   150  			fmt.Println("Reset Button              :", state[itob(data&0x02)])
   151  			fmt.Println("Power-off Button          :", state[itob(data&0x01)])
   152  		} else {
   153  			fmt.Println("Front Panel Button  : none")
   154  		}
   155  	}
   156  }
   157  
   158  func selInfo() {
   159  	support := map[bool]string{true: "supported", false: "unsupported"}
   160  
   161  	ipmi, err := ipmi.Open(0)
   162  	if err != nil {
   163  		fmt.Printf("Failed to open ipmi device: %v\n", err)
   164  	}
   165  	defer ipmi.Close()
   166  
   167  	if info, err := ipmi.GetSELInfo(); err != nil {
   168  		fmt.Printf("Failed to get SEL information: %v\n", err)
   169  	} else {
   170  		fmt.Println("SEL information")
   171  
   172  		switch info.Version {
   173  		case 0x51:
   174  			fallthrough
   175  		case 0x02:
   176  			fmt.Printf("Version        : %d.%d (1.5, 2.0 compliant)\n", info.Version&0x0F, info.Version>>4)
   177  		default:
   178  			fmt.Println("Version        : unknown")
   179  		}
   180  
   181  		fmt.Println("Entries        :", info.Entries)
   182  		fmt.Printf("Free Space     : %d bytes\n", info.FreeSpace)
   183  
   184  		// Most recent addition/erase timestamp
   185  		fmt.Printf("Last Add Time  : ")
   186  		if info.LastAddTime != 0xFFFFFFFF {
   187  			fmt.Println(time.Unix(int64(info.LastAddTime), 0))
   188  		} else {
   189  			fmt.Println("not available")
   190  		}
   191  
   192  		fmt.Printf("Last Del Time  : ")
   193  		if info.LastDelTime != 0xFFFFFFFF {
   194  			fmt.Println(time.Unix(int64(info.LastDelTime), 0))
   195  		} else {
   196  			fmt.Println("not available")
   197  		}
   198  
   199  		// Operation Support
   200  		fmt.Printf("Overflow       : ")
   201  		if (info.OpSupport & 0x80) != 0 {
   202  			fmt.Println("true")
   203  		} else {
   204  			fmt.Println("false")
   205  		}
   206  
   207  		data := int(info.OpSupport)
   208  		if (data & 0x0F) != 0 {
   209  			fmt.Println("Supported cmds")
   210  			fmt.Println("Delete         :", support[itob(data&0x08)])
   211  			fmt.Println("Partial Add    :", support[itob(data&0x04)])
   212  			fmt.Println("Reserve        :", support[itob(data&0x02)])
   213  			fmt.Println("Get Alloc Info :", support[itob(data&0x01)])
   214  		} else {
   215  			fmt.Println("Supported cmds : none")
   216  		}
   217  	}
   218  }
   219  
   220  func lanConfig() {
   221  	const (
   222  		setInProgress byte = iota
   223  		_
   224  		_
   225  		IPAddress
   226  		IPAddressSrc
   227  		MACAddress
   228  	)
   229  
   230  	setInProgressStr := []string{
   231  		"Set Complete", "Set In Progress", "Commit Write", "Reserved",
   232  	}
   233  
   234  	IPAddressSrcStr := []string{
   235  		"Unspecified", "Static Address", "DHCP Address", "BIOS Assigned Address",
   236  	}
   237  
   238  	ipmi, err := ipmi.Open(0)
   239  	if err != nil {
   240  		log.Fatal(err)
   241  	}
   242  	defer ipmi.Close()
   243  
   244  	// data 1	completion code
   245  	// data 2	parameter revision, 0x11
   246  	// data 3:N	data
   247  
   248  	// set in progress
   249  	if buf, err := ipmi.GetLanConfig(1, setInProgress); err != nil {
   250  		fmt.Printf("Failed to get LAN config: %v\n", err)
   251  	} else {
   252  		fmt.Printf("Set In Progress   : ")
   253  		if int(buf[2]) < len(setInProgressStr) {
   254  			fmt.Println(setInProgressStr[buf[2]])
   255  		} else {
   256  			fmt.Println("Unknown")
   257  			fmt.Printf("%v\n", buf)
   258  		}
   259  	}
   260  
   261  	// ip address source
   262  	if buf, err := ipmi.GetLanConfig(1, IPAddressSrc); err != nil {
   263  		fmt.Printf("Failed to get LAN config: %v\n", err)
   264  	} else {
   265  		fmt.Printf("IP Address Source : ")
   266  		if int(buf[2]) < len(IPAddressSrcStr) {
   267  			fmt.Println(IPAddressSrcStr[buf[2]])
   268  		} else {
   269  			fmt.Println("Other")
   270  			fmt.Printf("%v\n", buf)
   271  		}
   272  	}
   273  
   274  	// ip address
   275  	if buf, err := ipmi.GetLanConfig(1, IPAddress); err != nil {
   276  		fmt.Printf("Failed to get LAN config: %v\n", err)
   277  	} else {
   278  		fmt.Printf("IP Address        : ")
   279  		if len(buf) == 6 {
   280  			fmt.Printf("%d.%d.%d.%d\n", buf[2], buf[3], buf[4], buf[5])
   281  		} else {
   282  			fmt.Printf("Unknown\n")
   283  		}
   284  	}
   285  
   286  	// MAC address
   287  	if buf, err := ipmi.GetLanConfig(1, MACAddress); err != nil {
   288  		fmt.Printf("Failed to get LAN config: %v\n", err)
   289  	} else {
   290  		fmt.Printf("MAC Address       : ")
   291  		if len(buf) == 8 {
   292  			fmt.Printf("%02x:%02x:%02x:%02x:%02x:%02x\n", buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
   293  		} else {
   294  			fmt.Printf("Unknown\n")
   295  		}
   296  	}
   297  }
   298  
   299  func deviceID() {
   300  	status := map[byte]string{
   301  		0x80: "yes",
   302  		0x00: "no",
   303  	}
   304  
   305  	adtlDevSupport := []string{
   306  		"Sensor Device",         /* bit 0 */
   307  		"SDR Repository Device", /* bit 1 */
   308  		"SEL Device",            /* bit 2 */
   309  		"FRU Inventory Device",  /* bit 3 */
   310  		"IPMB Event Receiver",   /* bit 4 */
   311  		"IPMB Event Generator",  /* bit 5 */
   312  		"Bridge",                /* bit	6 */
   313  		"Chassis Device",        /* bit 7 */
   314  	}
   315  
   316  	ipmi, err := ipmi.Open(0)
   317  	if err != nil {
   318  		fmt.Printf("Failed to open ipmi device: %v\n", err)
   319  	}
   320  	defer ipmi.Close()
   321  
   322  	if info, err := ipmi.GetDeviceID(); err != nil {
   323  		fmt.Printf("Failed to get device ID information: %v\n", err)
   324  	} else {
   325  		fmt.Println("Device ID information")
   326  		fmt.Printf("%-26s: %d\n", "Device ID", info.DeviceID)
   327  		fmt.Printf("%-26s: %d\n", "Device Revision", (info.DeviceRevision & 0x0F))
   328  		fmt.Printf("%-26s: %d.%02x\n", "Firmware Revision",
   329  			(info.FwRev1 & 0x3F), info.FwRev2)
   330  
   331  		spec := uint8(info.IpmiVersion)
   332  		fmt.Printf("%-26s: %x.%x\n", "IPMI Version", spec&0x0F, (spec&0xF0)>>4)
   333  
   334  		var mid uint32
   335  		mid = uint32(info.ManufacturerID[2]) << 16
   336  		mid |= uint32(info.ManufacturerID[1]) << 8
   337  		mid |= uint32(info.ManufacturerID[0])
   338  
   339  		fmt.Printf("%-26s: %d (0x%04X)\n", "Manufacturer ID", mid, mid)
   340  
   341  		var pid uint16
   342  		pid = uint16(info.ProductID[1]) << 8
   343  		pid |= uint16(info.ProductID[0])
   344  
   345  		fmt.Printf("%-26s: %d (0x%04X)\n", "Product ID", pid, pid)
   346  
   347  		// bit 7 == 0 indicates normal operation
   348  		fmt.Printf("%-26s: %s\n", "Device Available", status[(^info.FwRev1&0x80)])
   349  		fmt.Printf("%-26s: %s\n", "Provides Device SDRs",
   350  			status[(info.DeviceRevision&0x80)])
   351  
   352  		fmt.Printf("%-26s:\n", "Additional Device Support")
   353  		for i := 0; i < 8; i++ {
   354  			if (info.AdtlDeviceSupport & (1 << i)) != 0 {
   355  				fmt.Printf("    %s\n", adtlDevSupport[i])
   356  			}
   357  		}
   358  
   359  		// This field is optional, 4 bytes.
   360  		fmt.Printf("%-26s:\n", "Aux Firmware Rev Info")
   361  		for _, val := range info.AuxFwRev {
   362  			fmt.Printf("    0x%02x\n", val)
   363  		}
   364  	}
   365  }
   366  
   367  func sendRawCmd(cmds []string) {
   368  	ipmi, err := ipmi.Open(0)
   369  	if err != nil {
   370  		log.Fatal(err)
   371  	}
   372  	defer ipmi.Close()
   373  
   374  	data := make([]byte, 0)
   375  
   376  	for _, cmd := range cmds {
   377  		val, err := strconv.ParseInt(cmd, 0, 8)
   378  		if err != nil {
   379  			fmt.Printf("Invalid syntax: \"%s\"\n", cmd)
   380  			return
   381  		}
   382  		data = append(data, byte(val))
   383  	}
   384  
   385  	if buf, err := ipmi.RawCmd(data); err != nil {
   386  		fmt.Printf("Unable to send RAW command: %v\n", err)
   387  	} else {
   388  		for i, x := range buf {
   389  			fmt.Printf("| 0x%-2x ", x)
   390  			if i%8 == 7 || i == len(buf)-1 {
   391  				fmt.Printf("|\n")
   392  			}
   393  		}
   394  	}
   395  }