luci-base: resolve symlinks for PCI hardware
authorPaul Donald <redacted>
Mon, 16 Mar 2026 14:54:07 +0000 (15:54 +0100)
committerPaul Donald <redacted>
Mon, 16 Mar 2026 14:54:07 +0000 (15:54 +0100)
getBuiltinEthernetPorts crashed with "Unknown error"
on hardware where NICs have PCI subsystem symlinks at
different sysfs depths (e.g. onboard NIC vs PCIe card NIC).

The getBuiltinEthernetPorts x86_64 workaround block
needs realpath() to resolve PCI subsystem symlinks.

readlink() returns different strings ("../../../bus/pci" vs
"../../../../bus/pci") even though both resolve to /sys/bus/pci,
causing eth1 and eth2 to be incorrectly excluded from the result.

E.g.:

  eth0: /sys/class/net/eth0/device/subsystem -> ../../../bus/pci
  eth1: /sys/class/net/eth1/device/subsystem -> ../../../../bus/pci
  eth2: /sys/class/net/eth2/device/subsystem -> ../../../../bus/pci

1. Add realpath to the 'fs' module import statement
2. Use realpath() to normalize paths

Closes #8425
Reported-by: @MI2-2
Signed-off-by: Paul Donald <redacted>
modules/luci-base/root/usr/share/rpcd/ucode/luci

index c7796197455463cdef5bf094224f5a5d0ede935b..00e2b51474b20bd0963121240d55bfe76cac4dca 100644 (file)
@@ -3,7 +3,7 @@
 
 'use strict';
 
-import { stdin, access, dirname, basename, open, popen, glob, lsdir, readfile, readlink, error } from 'fs';
+import { stdin, access, dirname, basename, open, popen, glob, lsdir, readfile, readlink, realpath, error } from 'fs';
 import { cursor } from 'uci';
 
 import { init_list, init_index, init_enabled, init_action, conntrack_list, process_list } from 'luci.sys';
@@ -636,7 +636,7 @@ const methods = {
                        /* Workaround for targets that do not enumerate  all netdevs in board.json */
                        if (uname().machine in [ 'x86_64' ] &&
                            match(ports[0]?.device, /^eth\d+$/)) {
-                               let bus = readlink(`/sys/class/net/${ports[0].device}/device/subsystem`);
+                               let bus = realpath(`/sys/class/net/${ports[0].device}/device/subsystem`);
 
                                for (let netdev in lsdir('/sys/class/net')) {
                                        if (!match(netdev, /^eth\d+$/))
@@ -645,7 +645,7 @@ const methods = {
                                        if (length(filter(ports, port => port.device == netdev)))
                                                continue;
 
-                                       if (readlink(`/sys/class/net/${netdev}/device/subsystem`) != bus)
+                                       if (realpath(`/sys/class/net/${netdev}/device/subsystem`) != bus)
                                                continue;
 
                                        push(ports, { role: 'unknown', device: netdev });
git clone https://git.99rst.org/PROJECT