Skip to content

Commit

Permalink
Extend the logic for linux
Browse files Browse the repository at this point in the history
The machine id is looked in "canonical" locations. If not value is found, one is generated and persisted.
The machine id is looked in:
  - the file pointed by the `MACHINE_ID_FILE` env var
  - `/var/lib/dbus/machine-id`
  - `/etc/machine-id`
  - `$HOME/.config/machine-id`

If no such file is found, a random uuid is generated and persisted in the first
writable file among `$MACHINE_ID_FILE`, `/var/lib/dbus/machine-id`, `/etc/machine-id`, `$HOME/.config/machine-id`.

If there is an error reading _all_ the files an empty string is returned.

The logic implemented is a variation of the one described in denisbrodbeck#5 (comment)
  • Loading branch information
panta committed Dec 30, 2020
1 parent 865ab5f commit c2fe0d5
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 5 deletions.
18 changes: 18 additions & 0 deletions helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func readFile(filename string) ([]byte, error) {
return ioutil.ReadFile(filename)
}

func writeFile(filename string, data []byte) error {
return ioutil.WriteFile(filename, data, 0644)
}

// readFirstFile tries all the pathnames listed and returns the contents of the first readable file.
func readFirstFile(pathnames []string) ([]byte, error) {
contents := []byte{}
Expand All @@ -46,6 +50,20 @@ func readFirstFile(pathnames []string) ([]byte, error) {
return contents, err
}

// writeFirstFile writes to the first file that "works" between all pathnames listed.
func writeFirstFile(pathnames []string, data []byte) error {
var err error
for _, pathname := range pathnames {
if pathname != "" {
err = writeFile(pathname, data)
if err == nil {
return nil
}
}
}
return err
}

func trim(s string) string {
return strings.TrimSpace(strings.Trim(s, "\n"))
}
38 changes: 33 additions & 5 deletions id_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

package machineid

import "os"
import (
"os"
"path"
)

const (
// the environment variable name pointing to the machine id pathname
Expand All @@ -14,16 +17,41 @@ const (
// Some systems (like Fedora 20) only know this path.
// Sometimes it's the other way round.
dbusPathEtc = "/etc/machine-id"

// this returns a random uuid each time it's read
linuxRandomUuid = "/proc/sys/kernel/random/uuid"
)

// machineID returns the uuid specified at `/var/lib/dbus/machine-id` or `/etc/machine-id`.
// If there is an error reading the files an empty string is returned.
// See https://unix.stackexchange.com/questions/144812/generate-consistent-machine-unique-id
// machineID returns the uuid specified in the "canonical" locations. If not such value is found, one is generated and persisted.
// The machine id is looked in:
// - the file pointed by the `MACHINE_ID_FILE` env var
// - `/var/lib/dbus/machine-id`
// - `/etc/machine-id`
// - `$HOME/.config/machine-id`
//
// If no such file is found, a random uuid is generated and persisted in the first
// writable file among `$MACHINE_ID_FILE`, `/var/lib/dbus/machine-id`, `/etc/machine-id`, `$HOME/.config/machine-id`.
//
// If there is an error reading _all_ the files an empty string is returned.
// The logic implemented is a variation of the one described in https://github.com/denisbrodbeck/machineid/issues/5#issuecomment-523803164
// See also https://unix.stackexchange.com/questions/144812/generate-consistent-machine-unique-id
func machineID() (string, error) {
env_pathname := os.Getenv(ENV_VARNAME)

home := os.Getenv("HOME")
userMachineId := path.Join(home, ".config", "machine-id")

id, err := readFirstFile([]string{
env_pathname, dbusPath, dbusPathEtc,
env_pathname, dbusPath, dbusPathEtc, userMachineId,
})
if err != nil {
id, err = readFile(uuid)
if err == nil {
writeFirstFile([]string{
env_pathname, dbusPathEtc, dbusPath, userMachineId,
}, id)
}
}
if err != nil {
return "", err
}
Expand Down

0 comments on commit c2fe0d5

Please sign in to comment.