Repository navigation
ipmicli: wrong message for a repeated -p/-k, redirected runs taken for a terminal on Java 22-24, false --no-escape banner, PowerUp hint, no owner in sensors and fru output #218
Description
Five small defects of ipmicli, all in the CLI layer (org.metricshub.ipmi.cli): two misleading messages, a terminal detection that is wrong on Java 22 to 24, a banner that names a way out that does not exist, and an output that drops the owner of sensors and FRUs. None of them affects the library API.
What happens:
-
A repeated
-por-kis reported as mutually exclusive with the file option. Each of-p/--passwordand-pf/--password-filecallsexclusive(passwordOption, "--password and --password-file"), which fails as soon as any password option was given before, the same one included (CliArguments.java:182-198, :481-485). The key options do the same (:199-212). Reproduced offline:$ ipmicli -h bmc.example.com -u monitor --password=a -p b chassis ipmicli: --password and --password-file are mutually exclusive (exit 64) $ ipmicli -h bmc.example.com -u monitor -k 01 -k 02 -p x chassis ipmicli: --bmc-key and --bmc-key-file are mutually exclusive (exit 64)Neither command line has a file option. Refusing the repetition is right (a secret given twice is likely a mistake), but the message sends the user looking for an option they did not type. Other repeated options, such as
-h, silently take the last value. -
On Java 22 to 24, redirected runs are taken for a terminal.
main()passesSystem.console() != nullasterminal(IpmiCli.java:124), and the password prompt relies on a null console to refuse (:1346-1351). Up to Java 21,System.console()is null when stdin or stdout is redirected. Java 22 made the JLine provider (jdk.internal.le) the default (JDK-8308591), andSystem.console()then returns aConsoleeven when both streams are redirected;Console.isTerminal()was added to tell. Java 25 went back to thejava.baseconsole (JDK-8351435). The launcher accepts any Java 8 or later.- Password: reproduced offline on Java 21.0.2 with
-Djdk.console=jdk.internal.le, the default provider of 22 to 24.ipmicli -h bmc.example.com -u monitor chassis </dev/null >out.txtprintsPassword: ipmicli: no password was entered, andecho secret | ipmicli -h <host> -u monitor chassisprintsPassword:and goes on to log in withsecret, the first line of the piped input, as the password. Java 21 and 25 printno interactive console to ask the password: use --password-file(exit 64) in both cases, as cli.md:142-145 says. - SOL: with
terminaltrue,soltakes the interactive path for a piped input (IpmiCli.java:907, :923-941): it runsstty raw -echoon/dev/ttywhen there is one (:1140) and prints the banner; where raw mode cannot be set (no/dev/tty: cron, CI) it falls back to line mode, which re-reads the input line by line throughConsole.readPassword(), appends a CR to every line and turns LF into CR (SolBridge.java:186-196). cli.md:500-501 promises that a redirected input is "forwarded as they come". The SOL part is traced from the code, not run (no Java 22 to 24 installed).
- Password: reproduced offline on Java 21.0.2 with
-
--no-escapeon a terminal: the banner says "the end of the input closes it", but nothing does. The banner is printed wheneverterminalis true, and with--no-escapeit ends with that sentence (IpmiCli.java:923-935). In raw mode, Ctrl+D and Ctrl+C are bytes for the BMC (stty raw -echo; the Windows key reader treats Ctrl+C as input), so no end of input ever comes, andSolBridgecloses only on the end of the input or on an escape sequence. The way out is a kill from another terminal on Linux and macOS, Ctrl+Break on Windows. The sentence is right only in the line-mode fallback (Ctrl+D endsreadPassword()) and for a redirected input, the case cli.md:487-488 describes ("for binary transfers"). -
power cycleof a system that is off names a Java constant.IpmiClient.chassisControl()refuses the cycle withIllegalStateException("The system is off: a power cycle would power it up on some BMCs, use PowerUp to power it up")(IpmiClient.java:302-305), andIpmiCliprints it unchanged with exit 70 (IpmiCli.java:282-290, :193-195; asserted in IpmiCliTest.java:251-253). The CLI user seesPowerUpwhere the action ispower on.completionCodeFailure()already replaces the Java-oriented hint ofD4hwith CLI options (IpmiCli.java:208-224); this message was left out. -
sensors --jsonandfruprint no owner.sensorFields()writes the name, number, type and entity of a sensor, but not the owner of its SDR record (IpmiCli.java:592-614), althoughSensor.record()gives it (AbstractSensorRecord.getSensorOwnerId(),getAddressType(),getChannelNumber(),getSensorOwnerLun()).sel --jsonprintsgeneratorId, andSelEntry.isFrom()matches it against that owner and LUN as well as the number (SelEntry.java:315-328), but cli.md:442-444 can only tell scripts to joinsensorNumberwithnumber. Sensor numbers are unique per owner and LUN, not per BMC (IPMI 2.0 table 43-1, byte 8; sensors.md:54): when a satellite controller or system software (iLO 5 satellites, Dell BIOS sensors atB1h, see Read each sensor from its owner: Send Message bridging, LUN and Device SDRs (#84, #105) #192) uses a number the BMC also uses, the join returns two sensors, or the wrong one. Not checked against lab SDRs for an actual collision.- The
frutext header isFRU <id>: <name> (<entity> <instance>)(IpmiCli.java:654-657), the JSON object hasidbut no address (:745-750), and the problems are reported asFRU <id>: ...(:640-642). Since FRUs on other controllers than the BMC are read from the BMC: FRU Device Locator access address and LUN ignored #193, two FRUs with the same ID on different controllers or LUNs are both returned (upgrading.md:22-23), and the output does not tell them apart.Fru.locator()has what is needed (getDeviceAccessAddress(),getAccessLun(),getManagementChannelNumber()). No lab BMC has such a FRU (see FRUs on other controllers than the BMC are read from the BMC: FRU Device Locator access address and LUN ignored #193): this half is by the specification.
What should happen: a repeated option is reported as repeated; a run whose standard streams are redirected never prompts and forwards its SOL input byte for byte, on every Java version the launcher accepts; the SOL banner names a way out that works; CLI messages name CLI actions; and the JSON output carries what a script needs to tell two sensors or two FRUs apart and to match a SEL entry to its sensor as SelEntry.isFrom() does.
Impact: all low. (1) and (4) mislead a user at the command line. (2) affects only Java 22, 23 and 24, all non-LTS releases superseded by 25, but there it breaks the documented scripting cases: a redirected run takes the first line of its input as the password instead of failing fast, and a scripted sol alters its input. (3) leaves a terminal user with no way out but a kill. (5) makes the SEL-to-sensor join of the manual unreliable on BMCs with satellite controllers or software sensors.
Suggested fix:
- In
CliArguments, when the option given before is the same one (-pand--passwordcount as the same), throw<option> is given twice; keep the mutual-exclusion message for-pwith-pfand-kwith-kf. - In
IpmiCli.main(), take a console as a terminal only when it is one:Console console = System.console(); boolean terminal = console != null && isTerminal(console);, whereisTerminal()callsConsole.isTerminal()by reflection when it exists (Java 22+) and returns true otherwise (Java 8 to 21, where a non-null console is a terminal). MakereadConsolePassword()refuse a non-terminal console with the same "no interactive console" message. (Settingjdk.console=java.basebefore the firstSystem.console()call would also do, but depends on when the JDK initializes the console.) - Refuse
--no-escapewhen the input is a terminal:--no-escape needs a redirected input: on a terminal, ~. is the only way out (use --escape to pick another character). If keeping it, word the banner for raw mode instead ("nothing typed closes it: kill the program from another terminal, or press Ctrl+Break on Windows"). - In the
POWERcase ofIpmiCli, catch theIllegalStateExceptionof aPowerCycleand printipmicli: the system is off: a power cycle would power it up on some BMCs, use 'power on'(exit 70), ascompletionCodeFailure()does forD4h. Update the assertion of IpmiCliTest.java:253. - Add the owner to each
sensors --jsonobject:ownerIdencoded like the low byte of the SELgeneratorId(7-bit address shifted left, bit 0 set for a system software ID),ownerLunandownerChannel. Addaddress,lunandchannelto thefru --jsonobject, and put them in the text header and the problem lines when the FRU is not the BMC's (20h, LUN 0). Then update cli.md:442-444 to join on the owner as well as the number, and thefrusection of cli.md.
Found during the documentation review of #201.
Activity