Skip to content

Conversation

@twilly
Copy link

@twilly twilly commented Dec 6, 2025

/var/run has been depreciated for a while and some Linux filesystem layouts no longer include the backwards-compatibility link from /var/run to /run.

This changes Linux's getSystemBusPlatformAddress to probe for the system bus address in /var/run followed by in /run. This maintains compatibility with distributions where /run and /var/run are different (very rare) and somehow have two system buses (!) while also supporting distributions where /var/run is not linked.

References:

Fixes: #423

`/var/run` has been depreciated for a while and some Linux filesystem
layouts no longer include the backwards-compatibility link from
`/var/run` to `/run`.

This changes Linux's `getSystemBusPlatformAddress` to probe for the
system bus address in `/var/run` followed by in `/run`. This maintains
compatibility with distributions where /run and /var/run are different
(very rare) and somehow have two system buses (!) while also supporting
distributions where `/var/run` is not linked.

References:
 - [dbus: Use ${runstatedir} for system bus instead of ${localstatedir}/run](https://gitlab.freedesktop.org/dbus/dbus/-/issues/180)
 - [gdbus: gdbusaddress: Use runstatedir rather than localstatedir](https://gitlab.gnome.org/GNOME/glib/-/commit/b7b9f89417ab547b96dc5000ef5c6be9d0a307d5)

Fixes: godbus#423
@guelfey guelfey force-pushed the linux-system-bus-address branch from 9420658 to 5e24245 Compare December 19, 2025 15:37
Copy link
Contributor

@kolyshkin kolyshkin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably simplify things by returning "" from getSystemBusPlatformAddress and having a caller error out if the string is empty.

IOW something like

address := getSystemBusPlatformAddress()
if address == "" {
   return nil, errors.New("system bus not found")
}

@twilly
Copy link
Author

twilly commented Dec 23, 2025

You can probably simplify things by returning "" from getSystemBusPlatformAddress and having a caller error out if the string is empty.

IOW something like

address := getSystemBusPlatformAddress()
if address == "" {
   return nil, errors.New("system bus not found")
}

Thanks for taking a look and spending your time on this small feature. :)

I don't mind making the change, however there are some consequences. Returning the empty string instead of an error limits to a singular error, departs from the sister call getSessionBusAddress's return signature, and doesn't reduce the caller's complexity IMHO.

The empty string conveying not-found limits the number of possible error reasons. For example, DBUS_SYSTEM_ADDRESS being an invalid value versus missing in the environment entirely. It would be useful in debugging integrations if getSystemBusPlatformAddress would validate the environment value and doubly so if it could return why.

func getSystemBusPlatformAddress() (string, error) {
    if address, ok := os.LookupEnv("DBUS_SYSTEM_BUS_ADDRESS"); ok {
        if !validAddress(address) { // assume this does some checks (os.Stat, transport type availability, etc)
            return "", errors.New("misconfigured DBUS_SYSTEM_BUS_ADDRESS environment variable")
        }
        return address, nil
    }
    for _, path := range defaultSystemBusPaths {
        if _, err := os.Stat(path); err == nil {
            return "unix:path=" + path, nil
        }
    }
    return "", errors.New("system bus not found")
}

Using getSessionBusAddress's return type means a refactor simplifying dialing further is possible:

// SessionBusPrivate returns a new private connection to the session bus.
func SessionBusPrivate(opts ...ConnOption) (*Conn, error) {
    return busDial(func() (string, error) { return getSessionBusAddress(true) }, opts...)
}

// SessionBusPrivateNoAutoStartup returns a new private connection to the session bus.  If
// the session bus is not already open, do not attempt to launch it.
func SessionBusPrivateNoAutoStartup(opts ...ConnOption) (*Conn, error) {
    return busDial(func() (string, error) { return getSessionBusAddress(false) }, opts...)
}
        
// SystemBusPrivate returns a new private connection to the system bus.
// Note: this connection is not ready to use. One must perform Auth and Hello
// on the connection before it is usable.
func SystemBusPrivate(opts ...ConnOption) (*Conn, error) {
    return busDial(getSystemBusPlatformAddress, opts...)
}   
    
func busDial(addrFunc func() (string, error), opts ...ConnOption) (*Conn, error) {
    address, err := addrFunc()
    if err != nil {
        return nil, err
    }
    
    return Dial(address, opts...)
}   

The same refactor goes with ConnectSessionBus and ConnectSystemBus. Here's a direct link within this PR showing how structurally similar they now are:

dbus/conn.go

Line 137 in 5e24245

func ConnectSessionBus(opts ...ConnOption) (*Conn, error) {

And in regard to the caller's complexity, checking for error versus the empty string is a zero-line difference. IMHO, they're equally complex: same line count, both add one conditional, and both return an error.

--- a/conn.go
+++ b/conn.go
@@ -175,9 +175,9 @@ func Connect(address string, opts ...ConnOption) (*Conn, error) {
 // Note: this connection is not ready to use. One must perform Auth and Hello
 // on the connection before it is usable.
 func SystemBusPrivate(opts ...ConnOption) (*Conn, error) {
-       address, err := getSystemBusPlatformAddress()
-       if err != nil {
-               return nil, err
+       address := getSystemBusPlatformAddress()
+       if address = "" {
+               return nil, errors.New("system bus not found")
        }
        return Dial(address, opts...)
 }

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.

Linux: support system bus located at /run/dbus/system_bus_socket

2 participants