Пример #1
0
// NewJournal returns a new Journal instance pointing to the local journal
func NewJournal() (j *Journal, err error) {
	h, err := dlopen.GetHandle(libsystemdNames)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err == nil {
			return
		}
		err2 := h.Close()
		if err2 != nil {
			err = fmt.Errorf(`%q and "error closing handle: %v"`, err, err2)
		}
	}()

	j = &Journal{lib: h}

	sd_journal_open, err := j.getFunction("sd_journal_open")
	if err != nil {
		return nil, err
	}

	r := C.my_sd_journal_open(sd_journal_open, &j.cjournal, C.SD_JOURNAL_LOCAL_ONLY)

	if r < 0 {
		return nil, fmt.Errorf("failed to open journal: %d", syscall.Errno(-r))
	}

	return j, nil
}
Пример #2
0
func getFunction(name string) (unsafe.Pointer, error) {
	libsystemdMutex.Lock()
	defer libsystemdMutex.Unlock()

	if libsystemdHandle == nil {
		h, err := dlopen.GetHandle(libsystemdNames)
		if err != nil {
			return nil, err
		}

		libsystemdHandle = h
	}

	f, ok := libsystemdFunctions[name]
	if !ok {
		var err error
		f, err = libsystemdHandle.GetSymbolPointer(name)
		if err != nil {
			return nil, err
		}

		libsystemdFunctions[name] = f
	}

	return f, nil
}
Пример #3
0
// GetRunningSlice attempts to retrieve the name of the systemd slice in which
// the current process is running.
// This function is a wrapper around the libsystemd C library; if it cannot be
// opened, an error is returned.
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
}
Пример #4
0
// CurrentUnitName attempts to retrieve the name of the systemd system unit
// from which the calling process has been invoked. It wraps the systemd
// `sd_pid_get_unit` call, with the same caveat: for processes not part of a
// systemd system unit, this function will return an error.
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
}
Пример #5
0
// RunningFromSystemService tries to detect whether the current process has
// been invoked from a system service. The condition for this is whether the
// process is _not_ a user process. User processes are those running in session
// scopes or under per-user `systemd --user` instances.
//
// To avoid false positives on systems without `pam_systemd` (which is
// responsible for creating user sessions), this function also uses a heuristic
// to detect whether it's being invoked from a session leader process. This is
// the case if the current process is executed directly from a service file
// (e.g. with `ExecStart=/this/cmd`). Note that this heuristic will fail if the
// command is instead launched in a subshell or similar so that it is not
// session leader (e.g. `ExecStart=/bin/bash -c "/this/cmd"`)
//
// This function is a wrapper around the libsystemd C library; if this is
// unable to successfully open a handle to the library for any reason (e.g. it
// cannot be found), an errr will be returned
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
}
Пример #6
0
// NewJournalFromDir returns a new Journal instance pointing to a journal residing
// in a given directory. The supplied path may be relative or absolute; if
// relative, it will be converted to an absolute path before being opened.
func NewJournalFromDir(path string) (j *Journal, err error) {
	h, err := dlopen.GetHandle(libsystemdNames)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err == nil {
			return
		}
		err2 := h.Close()
		if err2 != nil {
			err = fmt.Errorf(`%q and "error closing handle: %v"`, err, err2)
		}
	}()

	path, err = filepath.Abs(path)
	if err != nil {
		return nil, err
	}

	j = &Journal{lib: h}

	sd_journal_open_directory, err := j.getFunction("sd_journal_open_directory")
	if err != nil {
		return nil, err
	}

	p := C.CString(path)
	defer C.free(unsafe.Pointer(p))

	r := C.my_sd_journal_open_directory(sd_journal_open_directory, &j.cjournal, p, 0)
	if r < 0 {
		return nil, fmt.Errorf("failed to open journal in directory %q: %d", path, syscall.Errno(-r))
	}

	return j, nil
}