func getUnitFileName() (unit string, err error) { libname := C.CString("libsystemd.so") defer C.free(unsafe.Pointer(libname)) handle := C.dlopen(libname, C.RTLD_LAZY) if handle == nil { err = fmt.Errorf("error opening libsystemd.so") return } defer func() { if r := C.dlclose(handle); r != 0 { err = fmt.Errorf("error closing libsystemd.so") } }() sym := C.CString("sd_pid_get_unit") defer C.free(unsafe.Pointer(sym)) sd_pid_get_unit := C.dlsym(handle, sym) if sd_pid_get_unit == nil { err = fmt.Errorf("error resolving sd_pid_get_unit function") 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 }
// populateFunctions ranges over the library's ftable, initializing each // function inside. Assumes that the caller executes runtime.LockOSThread. func (lib *Lib) populateFunctions() error { libT := reflect.TypeOf(lib.ftable) functionsV := reflect.ValueOf(lib).Elem().FieldByName("ftable") n := libT.NumField() for i := 0; i < n; i++ { // Get the field name, and make sure it's an Fp_. f := libT.FieldByIndex([]int{i}) if !strings.HasPrefix(f.Name, fpPrefix) { return fmt.Errorf( "Unexpected: field %q does not start with %q", f.Name, fpPrefix) } // Resolve the symbol. cfname := C.CString(f.Name[len(fpPrefix):]) v := C.dlsym(lib.handle, cfname) C.free(unsafe.Pointer(cfname)) if v == nil { return fmt.Errorf("%s", C.GoString(C.dlerror())) } // Save the value into the struct functionsV.FieldByIndex([]int{i}).SetPointer(v) } return nil }
func getSlice() (slice string, err error) { libname := C.CString("libsystemd.so") defer C.free(unsafe.Pointer(libname)) handle := C.dlopen(libname, C.RTLD_LAZY) if handle == nil { err = fmt.Errorf("error opening libsystemd.so") return } defer func() { if r := C.dlclose(handle); r != 0 { err = fmt.Errorf("error closing libsystemd.so") } }() sym := C.CString("sd_pid_get_slice") defer C.free(unsafe.Pointer(sym)) sd_pid_get_slice := C.dlsym(handle, sym) if sd_pid_get_slice == nil { err = fmt.Errorf("error resolving sd_pid_get_slice function") 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 } slice = C.GoString(sl) return }
// 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 *libHandle h, err = getHandle() if err != nil { return } defer func() { if err1 := h.Close(); err1 != nil { err = err1 } }() sym := C.CString("sd_pid_get_slice") defer C.free(unsafe.Pointer(sym)) sd_pid_get_slice := C.dlsym(h.handle, sym) if sd_pid_get_slice == nil { err = fmt.Errorf("error resolving sd_pid_get_slice function") 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 }
// 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 *libHandle h, err = getHandle() if err != nil { return } defer func() { if err1 := h.Close(); err1 != nil { err = err1 } }() sym := C.CString("sd_pid_get_unit") defer C.free(unsafe.Pointer(sym)) sd_pid_get_unit := C.dlsym(h.handle, sym) if sd_pid_get_unit == nil { err = fmt.Errorf("error resolving sd_pid_get_unit function") 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 }
func FindProc(lib string, handle unsafe.Pointer, n string) (addr uintptr, e error) { cn := C.CString(n) //TODO(t): use bytePtrFromString()? defer C.free(unsafe.Pointer(cn)) addr = uintptr(C.dlsym(handle, cn)) if addr == 0 { e = errors.New(n + " not found in " + lib) } return }
func Sym(handle uintptr, symbol string) (uintptr, error) { ptr := C.CString(symbol) defer C.free(unsafe.Pointer(ptr)) ret := C.dlsym(unsafe.Pointer(handle), ptr) if ret != nil { return uintptr(ret), nil } return uintptr(ret), errors.New(C.GoString(C.dlerror())) }
func MustFindProc(lib string, handle unsafe.Pointer, n string) (addr uintptr) { cn := C.CString(n) //TODO(t): use bytePtrFromString()? defer C.free(unsafe.Pointer(cn)) addr = uintptr(C.dlsym(handle, cn)) if addr == 0 { panic("mustFindProc of " + n + " in " + lib + " failed") } return }
func fn(fname string) unsafe.Pointer { name := C.CString(fname) defer C.free(unsafe.Pointer(name)) p := C.dlsym(alHandle, name) if uintptr(p) == 0 { log.Fatalf("al: couldn't dlsym %q", fname) } return p }
func (h Handle) Symbol(symbol string) (uintptr, error) { c_sym := C.CString(symbol) defer C.free(unsafe.Pointer(c_sym)) c_addr := C.dlsym(h.c, c_sym) if c_addr == nil { c_err := C.dlerror() return 0, fmt.Errorf("dl: %s", C.GoString(c_err)) } return uintptr(c_addr), nil }
func Symbol(handle uintptr, symbol string) (uintptr, error) { cstr := C.CString(symbol) defer C.free(unsafe.Pointer(cstr)) sym := C.dlsym(unsafe.Pointer(handle), cstr) if sym == nil { return 0, dlerror("dlsym") } return uintptr(sym), nil }
// GetSymbolPointer takes a symbol name and returns a pointer to the symbol. func (l *LibHandle) GetSymbolPointer(symbol string) (unsafe.Pointer, error) { sym := C.CString(symbol) defer C.free(unsafe.Pointer(sym)) C.dlerror() p := C.dlsym(l.Handle, sym) e := C.dlerror() if e != nil { return nil, fmt.Errorf("error resolving symbol %q: %v", symbol, errors.New(C.GoString(e))) } return p, nil }
func getSymbolPointer(handle unsafe.Pointer, symbol string) (unsafe.Pointer, error) { sym := C.CString(symbol) defer C.free(unsafe.Pointer(sym)) C.dlerror() p := C.dlsym(handle, sym) e := C.dlerror() if e != nil { return nil, errwrap.Wrap(fmt.Errorf("error resolving symbol %q", symbol), errors.New(C.GoString(e))) } return p, nil }
func dlsym(lib unsafe.Pointer, name string) (addr unsafe.Pointer, err error) { var s = C.CString(name) defer C.free(unsafe.Pointer(s)) dlmtx.Lock() defer dlmtx.Unlock() if addr = C.dlsym(lib, s); addr == nil { err = dlerror() } return }
func loadThySelf(t *testing.T, symbol string) { this_process := C.dlopen(nil, C.RTLD_NOW) if this_process == nil { t.Fatal("dlopen:", C.GoString(C.dlerror())) } defer C.dlclose(this_process) symbol_address := C.dlsym(this_process, C.CString(symbol)) if symbol_address == nil { t.Fatal("dlsym:", C.GoString(C.dlerror())) } else { t.Log(symbol, symbol_address) } }
func (library *Library) Sym(name string) *Function { if library == nil { return nil } if library.ptr == nil { return nil } function := &Function{} function.name = name cname := cstr(function.name) defer cname.free() function.ptr = C.dlsym(library.ptr, cname) return function }
/* * loadThySelf() * Go doesn't support dynamic linking. However, it supports a C interface that supports * dynamic linking. And it supports symbol export allowing callbacks into go functions * using a C calling convention. So, Go supports dynamic linking. */ func loadThySelf(symbol string) *[0]byte { this_process := C.dlopen(nil, C.RTLD_NOW) if this_process == nil { panic(C.GoString(C.dlerror())) } symbol_address := C.dlsym(this_process, C.CString(symbol)) if symbol_address == nil { panic(C.GoString(C.dlerror())) } C.dlclose(this_process) return (*[0]byte)(unsafe.Pointer(symbol_address)) }
func loadThySelf(t *testing.T, symbol string) { this_process := C.dlopen(nil, C.RTLD_NOW) if this_process == nil { t.Error("dlopen:", C.GoString(C.dlerror())) return } defer C.dlclose(this_process) symbol_address := C.dlsym(this_process, C.CString(symbol)) if symbol_address == nil { t.Error("dlsym:", C.GoString(C.dlerror())) return } t.Log(symbol, symbol_address) C.call4029(symbol_address) }
// 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 *libHandle h, err = getHandle() if err != nil { return } defer func() { if err1 := h.Close(); err1 != nil { err = err1 } }() sym := C.CString("sd_pid_get_owner_uid") defer C.free(unsafe.Pointer(sym)) sd_pid_get_owner_uid := C.dlsym(h.handle, sym) if sd_pid_get_owner_uid == nil { err = fmt.Errorf("error resolving sd_pid_get_owner_uid function") 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 dlsym(handle uintptr, symbol string) (uintptr, error) { Csymbol := C.CString(symbol) defer C.free(unsafe.Pointer(Csymbol)) Chandle := unsafe.Pointer(handle) // First clean preview error _, _ = C.dlerror() // Then call dlsym CSymbolHandle, _ := C.dlsym(Chandle, Csymbol) // Test error now CErrString, _ := C.dlerror() if CErrString == nil { return uintptr(CSymbolHandle), nil } else { return 0, errors.New(C.GoString(CErrString)) } }
func isRunningFromUnitFile() (ret bool, err error) { libname := C.CString("libsystemd.so") defer C.free(unsafe.Pointer(libname)) handle := C.dlopen(libname, C.RTLD_LAZY) if handle == nil { // we can't open libsystemd.so so we assume systemd is not // installed and we're not running from a unit file ret = false return } defer func() { if r := C.dlclose(handle); r != 0 { err = fmt.Errorf("error closing libsystemd.so") } }() sd_pid_get_owner_uid := C.dlsym(handle, C.CString("sd_pid_get_owner_uid")) if sd_pid_get_owner_uid == nil { err = fmt.Errorf("error resolving sd_pid_get_owner_uid function") return } var uid C.uid_t errno := C.my_sd_pid_get_owner_uid(sd_pid_get_owner_uid, 0, &uid) // 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 return case syscall.Errno(-errno) == syscall.ENOENT || syscall.Errno(-errno) == syscall.ENXIO: ret = true return default: err = fmt.Errorf("error calling sd_pid_get_owner_uid: %v", syscall.Errno(-errno)) return } }
// Sym loads the symbol identified by the given name into // the out parameter. Note that out must always be a pointer. // See the package documentation to learn how types are mapped // between Go and C. func (d *DL) Sym(symbol string, out interface{}) error { s := C.CString(symbol) defer C.free(unsafe.Pointer(s)) mu.Lock() handle := C.dlsym(d.handle, s) if handle == nil { err := dlerror() mu.Unlock() return err } mu.Unlock() if out == nil { return errors.New("out can't be nil") } switch val := out.(type) { case *int: // We treat Go's int as long, since it // varies depending on the platform bit size *val = *(*int)(handle) case *int8: *val = *(*int8)(handle) case *int16: *val = *(*int16)(handle) case *int32: *val = *(*int32)(handle) case *int64: *val = *(*int64)(handle) case *uint: // We treat Go's uint as unsigned long, since it // varies depending on the platform bit size *val = *(*uint)(handle) case *uint8: *val = *(*uint8)(handle) case *uint16: *val = *(*uint16)(handle) case *uint32: *val = *(*uint32)(handle) case *uint64: *val = *(*uint64)(handle) case *uintptr: *val = *(*uintptr)(handle) case *float32: *val = *(*float32)(handle) case *float64: *val = *(*float64)(handle) case *string: *val = C.GoString(*(**C.char)(handle)) case *unsafe.Pointer: *val = handle default: ref := reflect.ValueOf(out) if !ref.IsValid() || ref.Kind() != reflect.Ptr { return fmt.Errorf("out must be a pointer, not %T", out) } elem := ref.Elem() switch elem.Kind() { case reflect.Func: typ := elem.Type() tr, err := makeTrampoline(typ, handle) if err != nil { return err } v := reflect.MakeFunc(typ, tr) elem.Set(v) case reflect.Ptr: v := reflect.NewAt(elem.Type().Elem(), handle) elem.Set(v) default: return fmt.Errorf("invalid out type %T", out) } } return nil }
// Sym loads the symbol identified by the given name into // the out parameter. Note that out must always be a pointer. // See the package documentation to learn how types are mapped // between Go and C. func (d *DL) Sym(symbol string, out interface{}) error { s := C.CString(symbol) defer C.free(unsafe.Pointer(s)) mu.Lock() handle := C.dlsym(d.handle, s) if handle == nil { err := dlerror() mu.Unlock() return err } mu.Unlock() val := reflect.ValueOf(out) if !val.IsValid() || val.Kind() != reflect.Ptr { return fmt.Errorf("out must be a pointer, not %T", out) } if val.IsNil() { return errors.New("out can't be nil") } elem := val.Elem() typ := reflect.TypeOf(elem.Interface()) switch typ.Kind() { case reflect.Int: // We treat Go's int as long, since it // varies depending on the platform bit size elem.SetInt(int64(*(*int)(handle))) case reflect.Int8: elem.SetInt(int64(*(*int8)(handle))) case reflect.Int16: elem.SetInt(int64(*(*int16)(handle))) case reflect.Int32: elem.SetInt(int64(*(*int32)(handle))) case reflect.Int64: elem.SetInt(int64(*(*int64)(handle))) case reflect.Uint: // We treat Go's uint as unsigned long, since it // varies depending on the platform bit size elem.SetUint(uint64(*(*uint)(handle))) case reflect.Uint8: elem.SetUint(uint64(*(*uint8)(handle))) case reflect.Uint16: elem.SetUint(uint64(*(*uint16)(handle))) case reflect.Uint32: elem.SetUint(uint64(*(*uint32)(handle))) case reflect.Uint64: elem.SetUint(uint64(*(*uint64)(handle))) case reflect.Uintptr: elem.SetUint(uint64(*(*uintptr)(handle))) case reflect.Float32: elem.SetFloat(float64(*(*float32)(handle))) case reflect.Float64: elem.SetFloat(float64(*(*float64)(handle))) case reflect.Func: tr, err := makeTrampoline(typ, handle) if err != nil { return err } v := reflect.MakeFunc(typ, tr) elem.Set(v) case reflect.Ptr: v := reflect.NewAt(elem.Type().Elem(), handle) elem.Set(v) case reflect.String: elem.SetString(C.GoString(*(**C.char)(handle))) case reflect.UnsafePointer: elem.SetPointer(handle) default: return fmt.Errorf("invalid out type %T", out) } return nil }