From 1a45274d4c45ec805e6d0cffd5da33e8e15643fd Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 18 Sep 2022 10:28:00 -0700 Subject: [PATCH] version/distro: detect Ubuntu separately from Debian (for an upcoming change where I wanted to easily distinguish these two) Change-Id: Icb6a0144275cc9bf8978a7cb96b601d516d8da46 Signed-off-by: Brad Fitzpatrick --- net/tstun/tun_linux.go | 9 +++++---- version/distro/distro.go | 21 ++++++++++++++++++++- version/distro/distro_test.go | 5 +++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/net/tstun/tun_linux.go b/net/tstun/tun_linux.go index 112d16b85..3e70fc10e 100644 --- a/net/tstun/tun_linux.go +++ b/net/tstun/tun_linux.go @@ -59,8 +59,9 @@ func diagnoseLinuxTUNFailure(tunName string, logf logger.Logf, createErr error) } logf("is CONFIG_TUN enabled in your kernel? `modprobe tun` failed with: %s", modprobeOut) - switch distro.Get() { - case distro.Debian: + dist := distro.Get() + switch { + case dist.LikeDebian(): dpkgOut, err := exec.Command("dpkg", "-S", "kernel/drivers/net/tun.ko").CombinedOutput() if len(bytes.TrimSpace(dpkgOut)) == 0 || err != nil { logf("tun module not loaded nor found on disk") @@ -69,7 +70,7 @@ func diagnoseLinuxTUNFailure(tunName string, logf logger.Logf, createErr error) if !bytes.Contains(dpkgOut, []byte(kernel)) { logf("kernel/drivers/net/tun.ko found on disk, but not for current kernel; are you in middle of a system update and haven't rebooted? found: %s", dpkgOut) } - case distro.Arch: + case dist == distro.Arch: findOut, err := exec.Command("find", "/lib/modules/", "-path", "*/net/tun.ko*").CombinedOutput() if len(bytes.TrimSpace(findOut)) == 0 || err != nil { logf("tun module not loaded nor found on disk") @@ -78,7 +79,7 @@ func diagnoseLinuxTUNFailure(tunName string, logf logger.Logf, createErr error) if !bytes.Contains(findOut, []byte(kernel)) { logf("kernel/drivers/net/tun.ko found on disk, but not for current kernel; are you in middle of a system update and haven't rebooted? found: %s", findOut) } - case distro.OpenWrt: + case dist == distro.OpenWrt: out, err := exec.Command("opkg", "list-installed").CombinedOutput() if err != nil { logf("error querying OpenWrt installed packages: %s", out) diff --git a/version/distro/distro.go b/version/distro/distro.go index 3b1d36378..ca7a761fa 100644 --- a/version/distro/distro.go +++ b/version/distro/distro.go @@ -10,13 +10,16 @@ "runtime" "strconv" + "go4.org/mem" "tailscale.com/syncs" + "tailscale.com/util/lineread" ) type Distro string const ( Debian = Distro("debian") + Ubuntu = Distro("ubuntu") Arch = Distro("arch") Synology = Distro("synology") OpenWrt = Distro("openwrt") @@ -62,9 +65,20 @@ func linuxDistro() Distro { case haveDir("/usr/syno"): return Synology case have("/usr/local/bin/freenas-debug"): - // TrueNAS Scale runs on debian + // TrueNAS Scale runs on debian so test for it before Debian. return TrueNAS case have("/etc/debian_version"): + // Ubuntu also has an /etc/debian_version file, so see if it's actually Ubuntu. + isUbuntu := false + lineread.File("/etc/os-release", func(line []byte) error { + if mem.HasPrefix(mem.B(line), mem.S("ID=ubuntu")) { + isUbuntu = true + } + return nil + }) + if isUbuntu { + return Ubuntu + } return Debian case have("/etc/arch-release"): return Arch @@ -110,3 +124,8 @@ func DSMVersion() int { v, _ := strconv.Atoi(os.Getenv("SYNOPKG_DSM_VERSION_MAJOR")) return v } + +// LikeDebian reports whether d is Debian-derived. +func (d Distro) LikeDebian() bool { + return d == Debian || d == Ubuntu +} diff --git a/version/distro/distro_test.go b/version/distro/distro_test.go index bc4e8c5b4..1f91d97f2 100644 --- a/version/distro/distro_test.go +++ b/version/distro/distro_test.go @@ -14,3 +14,8 @@ func BenchmarkGet(b *testing.B) { } _ = d } + +func TestGet(t *testing.T) { + d := Get() + t.Logf("Get = %q", d) +}