// Copyright 2016 CoreOS, Inc. // // 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. // +build cgo package util // #include // #include // #include // // int // my_sd_pid_get_owner_uid(void *f, pid_t pid, uid_t *uid) // { // int (*sd_pid_get_owner_uid)(pid_t, uid_t *); // // sd_pid_get_owner_uid = (int (*)(pid_t, uid_t *))f; // return sd_pid_get_owner_uid(pid, uid); // } // // int // my_sd_pid_get_unit(void *f, pid_t pid, char **unit) // { // int (*sd_pid_get_unit)(pid_t, char **); // // sd_pid_get_unit = (int (*)(pid_t, char **))f; // return sd_pid_get_unit(pid, unit); // } // // int // my_sd_pid_get_slice(void *f, pid_t pid, char **slice) // { // int (*sd_pid_get_slice)(pid_t, char **); // // sd_pid_get_slice = (int (*)(pid_t, char **))f; // return sd_pid_get_slice(pid, slice); // } // // int // am_session_leader() // { // return (getsid(0) == getpid()); // } import "C" import ( "fmt" "syscall" "unsafe" "github.com/coreos/pkg/dlopen" ) var libsystemdNames = []string{ // systemd < 209 "libsystemd-login.so.0", "libsystemd-login.so", // systemd >= 209 merged libsystemd-login into libsystemd proper "libsystemd.so.0", "libsystemd.so", } func getRunningSlice() (slice string, err error) { var h *dlopen.LibHandle h, err = dlopen.GetHandle(libsystemdNames) if err != nil { return } defer func() { if err1 := h.Close(); err1 != nil { err = err1 } }() sd_pid_get_slice, err := h.GetSymbolPointer("sd_pid_get_slice") if err != nil { return } var s string sl := C.CString(s) defer C.free(unsafe.Pointer(sl)) ret := C.my_sd_pid_get_slice(sd_pid_get_slice, 0, &sl) if ret < 0 { err = fmt.Errorf("error calling sd_pid_get_slice: %v", syscall.Errno(-ret)) return } return C.GoString(sl), nil } func runningFromSystemService() (ret bool, err error) { var h *dlopen.LibHandle h, err = dlopen.GetHandle(libsystemdNames) if err != nil { return } defer func() { if err1 := h.Close(); err1 != nil { err = err1 } }() sd_pid_get_owner_uid, err := h.GetSymbolPointer("sd_pid_get_owner_uid") if err != nil { return } var uid C.uid_t errno := C.my_sd_pid_get_owner_uid(sd_pid_get_owner_uid, 0, &uid) serrno := syscall.Errno(-errno) // when we're running from a unit file, sd_pid_get_owner_uid returns // ENOENT (systemd <220) or ENXIO (systemd >=220) switch { case errno >= 0: ret = false case serrno == syscall.ENOENT, serrno == syscall.ENXIO: // Since the implementation of sessions in systemd relies on // the `pam_systemd` module, using the sd_pid_get_owner_uid // heuristic alone can result in false positives if that module // (or PAM itself) is not present or properly configured on the // system. As such, we also check if we're the session leader, // which should be the case if we're invoked from a unit file, // but not if e.g. we're invoked from the command line from a // user's login session ret = C.am_session_leader() == 1 default: err = fmt.Errorf("error calling sd_pid_get_owner_uid: %v", syscall.Errno(-errno)) } return } func currentUnitName() (unit string, err error) { var h *dlopen.LibHandle h, err = dlopen.GetHandle(libsystemdNames) if err != nil { return } defer func() { if err1 := h.Close(); err1 != nil { err = err1 } }() sd_pid_get_unit, err := h.GetSymbolPointer("sd_pid_get_unit") if err != nil { return } var s string u := C.CString(s) defer C.free(unsafe.Pointer(u)) ret := C.my_sd_pid_get_unit(sd_pid_get_unit, 0, &u) if ret < 0 { err = fmt.Errorf("error calling sd_pid_get_unit: %v", syscall.Errno(-ret)) return } unit = C.GoString(u) return }