1 // Copyright 2015 CoreOS, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package util contains utility functions related to systemd that applications 16 // can use to check things like whether systemd is running. Note that some of 17 // these functions attempt to manually load systemd libraries at runtime rather 18 // than linking against them. 19 package util 20 21 import ( 22 "fmt" 23 "io/ioutil" 24 "os" 25 "strings" 26 ) 27 28 var ( 29 ErrNoCGO = fmt.Errorf("go-systemd built with CGO disabled") 30 ) 31 32 // GetRunningSlice attempts to retrieve the name of the systemd slice in which 33 // the current process is running. 34 // This function is a wrapper around the libsystemd C library; if it cannot be 35 // opened, an error is returned. 36 func GetRunningSlice() (string, error) { 37 return getRunningSlice() 38 } 39 40 // RunningFromSystemService tries to detect whether the current process has 41 // been invoked from a system service. The condition for this is whether the 42 // process is _not_ a user process. User processes are those running in session 43 // scopes or under per-user `systemd --user` instances. 44 // 45 // To avoid false positives on systems without `pam_systemd` (which is 46 // responsible for creating user sessions), this function also uses a heuristic 47 // to detect whether it's being invoked from a session leader process. This is 48 // the case if the current process is executed directly from a service file 49 // (e.g. with `ExecStart=/this/cmd`). Note that this heuristic will fail if the 50 // command is instead launched in a subshell or similar so that it is not 51 // session leader (e.g. `ExecStart=/bin/bash -c "/this/cmd"`) 52 // 53 // This function is a wrapper around the libsystemd C library; if this is 54 // unable to successfully open a handle to the library for any reason (e.g. it 55 // cannot be found), an error will be returned. 56 func RunningFromSystemService() (bool, error) { 57 return runningFromSystemService() 58 } 59 60 // CurrentUnitName attempts to retrieve the name of the systemd system unit 61 // from which the calling process has been invoked. It wraps the systemd 62 // `sd_pid_get_unit` call, with the same caveat: for processes not part of a 63 // systemd system unit, this function will return an error. 64 func CurrentUnitName() (string, error) { 65 return currentUnitName() 66 } 67 68 // IsRunningSystemd checks whether the host was booted with systemd as its init 69 // system. This functions similarly to systemd's `sd_booted(3)`: internally, it 70 // checks whether /run/systemd/system/ exists and is a directory. 71 // http://www.freedesktop.org/software/systemd/man/sd_booted.html 72 func IsRunningSystemd() bool { 73 fi, err := os.Lstat("/run/systemd/system") 74 if err != nil { 75 return false 76 } 77 return fi.IsDir() 78 } 79 80 // GetMachineID returns a host's 128-bit machine ID as a string. This functions 81 // similarly to systemd's `sd_id128_get_machine`: internally, it simply reads 82 // the contents of /etc/machine-id 83 // http://www.freedesktop.org/software/systemd/man/sd_id128_get_machine.html 84 func GetMachineID() (string, error) { 85 machineID, err := ioutil.ReadFile("/etc/machine-id") 86 if err != nil { 87 return "", fmt.Errorf("failed to read /etc/machine-id: %v", err) 88 } 89 return strings.TrimSpace(string(machineID)), nil 90 } 91