Skip to content

Change /bin/sh from bash to BusyBox ash - #1579

Open
troglobit wants to merge 7 commits into
mainfrom
binsh
Open

Change /bin/sh from bash to BusyBox ash#1579
troglobit wants to merge 7 commits into
mainfrom
binsh

Conversation

@troglobit

@troglobit troglobit commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Description

  • Fix bashism in #!/bin/sh scripts
  • Switch /bin/sh from bash to BusyBox ash

TODO: profiling

Checklist

Tick relevant boxes, this PR is-a or has-a:

  • Bugfix
    • Regression tests
    • ChangeLog updates (for next release)
  • Feature
    • YANG model change => revision updated?
    • Regression tests added?
    • ChangeLog updates (for next release)
    • Documentation added?
  • Test changes
    • Checked in changed Readme.adoc (make test-spec)
    • Added new test to group Readme.adoc and yaml file
  • Code style update (formatting, renaming)
  • Refactoring (please detail in commit messages)
  • Build related changes
  • Documentation content changes
    • ChangeLog updated (for major changes)
  • Other (please describe):

Minimal images log the following on every boot and initctl reload,
e.g., when the regression test framework reconfigures the system:

finit[1]: Skipping /etc/finit.d/enabled/netbrowse.conf, dangling symlink: No such file or directory
finit[1]: service_register():/etc/finit.d/enabled/ttyd.conf: skipping ttyd: No such file or directory
finit[1]: Skipping /etc/finit.d/enabled/webui.conf, dangling symlink: No such file or directory

The web services are enabled in the default configuration, so confd's
finit_enable() creates enabled/ symlinks also on images where the
service was never installed.  svc_enable() already guards its nginx
symlinks with the corresponding check.  The ttyd case differs: its
conf ships unconditionally in the common rootfs skeleton while the
daemon itself is an optional package.

Skip enable, with a log message at INFO, when the service conf is not
available in the image.  At build time, drop the ttyd confs when ttyd
is not selected, and prune any dangling enabled/*.conf symlinks.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Preparation for switching /bin/sh from bash to busybox ash, issue #961.
All of these only work today because /bin/sh is bash:

  - wait-interface used '&>', which POSIX sh parses as backgrounding
    the command, making the interface-exists check always true and
    the boot-time wait a no-op
  - the generated ethtool-flow-control.sh and ethtool-aneg.sh scripts
    used '[[', not available in POSIX sh: the not-supported guard can
    never fire, and the failing ethtool command that follows aborts
    the whole dagger generation
  - dagger used 'echo -ne', which plain sh echo does not implement

Found with checkbashisms(1).

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Every system(3) call, dagger action script, and Finit run-parts spawns
/bin/sh: bash pays start-up and memory costs that BusyBox ash does not.
Same rationale as Debian's dash-as-/bin/sh.

Busybox' default shell is the buildroot choice default, and the BusyBox
config already sets CONFIG_SH_IS_ASH.  Bash remains, now explicitly
selected, for interactive shells and scripts using #!/bin/bash.

Fixes #961

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The interface quirk check spawns a shell per interface on every
interface configuration change, and at boot, one of the few remaining
bash spawns on the configuration hot path after issue #961.

The only bash dependency was the process substitution feeding grep
both the ethtool -i output and the expected key=val lines.  Replace
with a single awk over the ethtool output, checking that all pairs of
the pattern match; splitting on the first '=' like before.

Verified against the bash version with a stubbed ethtool: interface
name match, ethtool pattern match/mismatch, unknown quirk, and missing
quirks file all agree, under both dash and busybox ash.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
infamy's runsh() feeds the script to /bin/sh on the DUT, and with the
switch to busybox ash bashisms no longer work:

  - brace expansion degrades to a literal argument, so the syslog
    tests' log file cleanup removed nothing, leaving stale files that
    skew message counts in later runs
  - the watchdog test's '&>' backgrounded the lockup with stdout and
    stderr still attached to the SSH session, hanging the test until
    TCP timeout, long after the DUT had rebooted as intended

Shell fragments in the infamy netns helpers are unaffected, they run
on the test host where /bin/sh was already a POSIX shell.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Every quirk lookup spawns three processes -- the shell from system(3),
its command substitution, and has-quirk itself -- to read a file confd
already holds in memory.  Four lookups per port, plus the one in
25-mqprio, is ~420 processes per boot on a 28-port switch, and the same
again on every interface configuration change.

confd loads /etc/product/interface-quirks.json into confd.ifquirks at
startup, but nothing has ever read it.  Match the interface name there
instead.  @ethtool: patterns need driver info, so those still go out to
has-quirk; boards with no quirks file, or with only interface name
patterns, no longer spawn anything.  25-mqprio hoists the file check out
of its per-interface loop for the same reason.

Verified against has-quirk across all product quirks files, four
interface names and six quirk names, with a stubbed ethtool: 192 cases,
no differences.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Quirks are read from /etc/product/interface-quirks.json, so the copy at
the product directory root is never found.  The one below etc/product/
already carries the same two quirks.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
@troglobit
troglobit marked this pull request as ready for review September 7, 2026 07:38
@troglobit
troglobit requested a review from mattiaswal September 7, 2026 07:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant