github.com/bored-engineer/go-launchd@v0.0.0-20230905041514-6aff1185c30f/libxpc.go (about)

     1  //go:build darwin
     2  // +build darwin
     3  
     4  package launchd
     5  
     6  import (
     7  	"runtime"
     8  	"syscall"
     9  	"unsafe"
    10  )
    11  
    12  // Supported is true if launchd socket activation is supported on this platform
    13  const Supported = true
    14  
    15  // As a sanity check, refuse any returned array larger than this with syscall.EINVAL
    16  const maxFDs = 1 << 20
    17  
    18  // launch_activate_socket is defined in libxpc.dylib
    19  var libxpc_launch_activate_socket_trampoline_addr uintptr
    20  
    21  //go:cgo_import_dynamic libxpc_launch_activate_socket launch_activate_socket "/usr/lib/system/libxpc.dylib"
    22  
    23  // invokes launch_activate_socket
    24  func libxpc_launch_activate_socket(name string) ([]int, error) {
    25  	c_name_ptr, err := syscall.BytePtrFromString(name)
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	var c_fds_ptr *uintptr // *C.int
    30  	defer func() {
    31  		if c_fds_ptr != nil {
    32  			free(unsafe.Pointer(c_fds_ptr))
    33  		}
    34  	}()
    35  	var c_cnt uint // C.size_t
    36  	res, _, _ := syscall_syscall(
    37  		libxpc_launch_activate_socket_trampoline_addr,
    38  		uintptr(unsafe.Pointer(c_name_ptr)),
    39  		uintptr(unsafe.Pointer(&c_fds_ptr)),
    40  		uintptr(unsafe.Pointer(&c_cnt)),
    41  	)
    42  	runtime.KeepAlive(c_name_ptr)
    43  	if res != 0 {
    44  		return nil, syscall.Errno(res)
    45  	} else if c_cnt > maxFDs {
    46  		return nil, syscall.EINVAL
    47  	}
    48  	c_fds := (*[maxFDs]int)(unsafe.Pointer(c_fds_ptr))
    49  	fds := make([]int, c_cnt)
    50  	copy(fds, (*c_fds)[0:c_cnt])
    51  	return fds, nil
    52  }