ares-install: stop reporting a successful install as a failure - #20
Merged
Conversation
A run whose session drops mid-install printed the cleanup failure first
and the reason second:
Failed to delete /media/developer/temp/ares_install_fca561c25f.ipk:
Ssh(Fatal("Inappropriate ioctl for device"))
Failed to install: Fatal: Socket error: disconnected
The delete is attempted on the way out, before the install result is
propagated, so its failure always lands ahead of the error that explains
the run. Worse, the ENOTTY is meaningless - it is a stale errno libssh
reports through a session that is already gone, and it reads like a
permission or path problem on the device.
Check the session before cleaning up. When it is gone, say what was left
behind - the upload had already succeeded, so the package really is still
sitting in /media/developer/temp - and let the real error through on its
own. "Deleting uploaded package..." moves inside the same branch, so it is
no longer announced for a delete that cannot happen.
Verified that libssh reports a vanished peer as `is_connected() == false`
against a throwaway sshd: killing the child holding the session flips it,
which is the condition this relies on.
Errors here are printed with Display rather than Debug now, so the
remaining two say what went wrong instead of dumping a variant.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gde2tcn5SbUHKhesuTNB7a
`dev/install` is subscribed to, and the loop takes the first message that says "installed" or that names a failure. If the stream ends having said neither, `.next()` returns None - and that was mapped to `Ok(String::new())`, so ares-install printed "Installed package !" and exited 0 for an install whose outcome it never learned. A subscription can end that way whenever the channel closes early: the device's session going down, luna-send exiting, appinstalld stopping mid report. Claiming success there puts a package on the device that may not be on it. Report it instead. The device having stopped talking is not evidence either way, and the message says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gde2tcn5SbUHKhesuTNB7a
The install request goes out over an exec channel, and the device starts work on it before it answers. A connection that dies in that window leaves `request_exec` returning "Socket error: disconnected" - while the device carries on and installs the package. On a set that drops SSH connections around install time this is not a corner case. A peer session hit it four runs out of four: every one printed "Failed to install: Fatal: Socket error: disconnected", and every one succeeded on the device, confirmed against appinstalld's NL_APP_INSTALLED and the Installed-Time in opkg's status file. Anyone reading that output reinstalls, or goes hunting for a device fault that is not there. A dead connection is not evidence of a failed install. Say what is actually known - the connection went down mid-install, the package may well be on the device, and `ares-install --list` will settle it - and skip the "Failed to install" prefix, which contradicts the only thing the message has to say. The exit status stays non-zero: an unknown outcome is not a success either. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gde2tcn5SbUHKhesuTNB7a
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three fixes to how ares-install reports what happened. The first is a correctness bug: on some sets it reports a successful install as a failure.
1. A successful install reported as a failure
The install request goes out over an exec channel, and the device starts work on it before it answers. A connection that dies in that window leaves
request_execreturningSocket error: disconnected— while the device carries on and installs the package.On a set that drops SSH connections around install time this is not a corner case. It reproduced four runs out of four on a UP7560: every one printed
and every one succeeded on the device, confirmed against appinstalld's
NL_APP_INSTALLEDand theInstalled-Timein opkg's status file. Caught in the act with a changed binary, so checksums could tell the builds apart:The device was still writing the package while ares-install had already given up. Anyone checking the moment it exits sees the old app and is told the install failed — wrong twice over, and it sends people hunting for a device fault that isn't there.
A dead connection is not evidence of a failed install. It now says what is actually known:
--listfullbecause it serialisesversion; plain--listprints ids only, so it answers "is this app on the device", not "did this build land" — a distinction that cost real debugging time. TheFailed to installprefix is dropped for this case, since it contradicts the one thing the message has to say. Exit status stays non-zero: an unknown outcome is not a success.2. A silent install stream reported as success
dev/installis subscribed to, and the loop takes the first message saying "installed" or naming a failure. If the stream ends having said neither,.next()returnsNone— and that was mapped toOk(String::new()), so ares-install printedInstalled package !and exited 0 for an install whose outcome it never learned. That is now an error.3. Cleanup noise in front of the real error
Deleting the uploaded ipk happens on the way out, before the install result is propagated, so its failure always landed ahead of the error that explains the run:
The
ENOTTYis meaningless — a stale errno libssh reports through a session that is already gone — and it reads like a permission or path problem on the device. Cleanup now checks the session first and, when it is gone, names what was left behind instead:Errors in this file print with
Displayrather thanDebug, so the remaining two say what went wrong instead of dumping a variant.Verification
Fixes 1 and 3 were built and run against a UP7560 on the exact case that produced the false failure six times: output accurate, leftover ipk named, cleanup noise gone, exit status non-zero, and the package confirmed on the device by checksum. Fix 2 is not reachable on demand and was not exercised on hardware.
Workspace builds clean; 79 tests pass; clippy warnings for the crate drop from 36 to 34.
Not addressed here: why the socket dies. That was chased a long way — dropbear 2022.83 with no channel cap, listener pid and start time unchanged across installs, an idle reverse tunnel surviving untouched, no OOM kill, and a clean dmesg over a window verified to cover the event. It is narrowed to something on the device deliberately ending that process, and it is a device-side question that does not block this.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Gde2tcn5SbUHKhesuTNB7a