summaryrefslogtreecommitdiff
path: root/sd_id128/get.go
diff options
context:
space:
mode:
Diffstat (limited to 'sd_id128/get.go')
-rw-r--r--sd_id128/get.go152
1 files changed, 152 insertions, 0 deletions
diff --git a/sd_id128/get.go b/sd_id128/get.go
new file mode 100644
index 0000000..d8cdcfa
--- /dev/null
+++ b/sd_id128/get.go
@@ -0,0 +1,152 @@
+// Copyright 2016 Luke Shumaker
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sd_id128
+
+import (
+ "crypto/rand"
+ "os"
+ "strings"
+)
+
+// GetRandomUUID generates a random UUID (122 random bits).
+//
+// For convenience when a valid UUID is needed, rather than returning
+// a totally random 128-bit number, this sets the UUID type
+// ("variant") to RFC 4122 format, and the sub-type ("version") to
+// "4", which is (pseudo) random generation. This leaves 122 random
+// bits.
+//
+// The pseudorandom number generator used is cryptographically secure.
+func GetRandomUUID() (ID128, error) {
+ var id ID128
+ _, err := rand.Read(id[:])
+ if err != nil {
+ return ID128{}, err
+ }
+
+ // Set the type ("variant") to RFC 4122 format
+ id[8] = (id[8] & 0x3F) | 0x80
+ // Set the sub-type ("version") to 4 (random generation).
+ id[6] = (id[6] & 0x0F) | 0x40
+
+ return id, nil
+}
+
+var cachedMachineID ID128
+
+// GetMachineID returns a unique identifier for this operating system
+// installation.
+//
+// This is read as a plain hexadecimal number (with an optional
+// trailing newline) from "/etc/machine-id".
+//
+// Note that unlike every other "Get*ID" function, the ID returned by
+// GetMachineID is not guaranteed to be a valid UUID, though values
+// generated by systemd v30 and later are valid UUIDs.
+//
+// See machine-id(5) for more information.
+//
+// machine-id(5): https://www.freedesktop.org/software/systemd/man/machine-id.html
+func GetMachineID() (ID128, error) {
+ if cachedMachineID == (ID128{}) {
+ str, err := readfile("/etc/machine-id")
+ if err != nil {
+ return ID128{}, err
+ }
+ id, err := ParsePlain(strings.TrimSuffix(str, "\n"))
+ if err != nil {
+ return ID128{}, err
+ }
+ if id == (ID128{}) {
+ return ID128{}, ErrInvalid
+ }
+ cachedMachineID = id
+ }
+ return cachedMachineID, nil
+}
+
+var cachedBootID ID128
+
+// GetBootUUID returns a UUID unique to this boot; it is generated by
+// the kernel once very early in the boot process.
+//
+// This is read as a UUID (with trailing newline) from
+// "/proc/sys/kernel/random/boot_id".
+//
+// It may be relied on that the Linux kernel sets boot_id to a UUID
+// with the UUID type ("variant") set to RFC 4122 format, and the
+// sub-type ("version") set appropriately.
+//
+// See random(4) for more information.
+//
+// random(4): http://man7.org/linux/man-pages/man4/random.4.html
+func GetBootUUID() (ID128, error) {
+ if cachedBootID == (ID128{}) {
+ str, err := readfile("/proc/sys/kernel/random/boot_id")
+ if err != nil {
+ return ID128{}, err
+ }
+ id, err := ParseUUID(strings.TrimSuffix(str, "\n"))
+ if err != nil {
+ return ID128{}, err
+ }
+ cachedBootID = id
+ }
+ return cachedBootID, nil
+}
+
+var cachedInvocationID ID128
+
+// GetInvocationUUID returns a UUID unique to this invocation of the
+// currently executed service.
+//
+// This is read from the "INVOCATION_ID" environment variable, which
+// is expected to be set by the service manager.
+//
+// It may be relied on that the service manager sets this to a UUID
+// with the UUID type ("variant") set to RFC 4122 format, and the
+// sub-type ("version") set appropriately.
+//
+// The error returned is ErrNone if the service manager did not set
+// INVOCATION_ID, or ErrInvalid if the value of INVOCATION_ID could
+// not be parsed.
+//
+// See sd_id128_get_invocation(3) for more information.
+//
+// sd_id128_get_invocation(3): https://www.freedesktop.org/software/systemd/man/sd_id128_get_invocation.html
+//
+// BUG(lukeshu): GetInvocationUUID uses a mechanism specified by "what
+// systemd currently does", rather than a stable specification.
+func GetInvocationUUID() (ID128, error) {
+ // BUG(lukeshu): GetInvocationUUID might logically belong in the
+ // sd_daemon package, but we defer to the C-language
+ // libsystemd's placement of sd_id128_get_invocation() in
+ // sd-id128.h.
+ if cachedInvocationID == (ID128{}) {
+ // BUG(lukeshu): GetInvocationUUID should distrust the
+ // environment in certain situations, similarly to GNU
+ // libc secure_getenv.
+ str, have := os.LookupEnv("INVOCATION_ID")
+ if !have {
+ return ID128{}, ErrNone
+ }
+ t, err := Parse(str)
+ if err != nil {
+ return ID128{}, err
+ }
+ cachedInvocationID = t
+ }
+ return cachedInvocationID, nil
+}