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

     1  # go-launchd [![Go Reference](https://pkg.go.dev/badge/github.com/bored-engineer/go-launchd.svg)](https://pkg.go.dev/github.com/bored-engineer/go-launchd) [![Test Workflow](https://github.com/bored-engineer/go-launchd/actions/workflows/test.yml/badge.svg)](https://github.com/bored-engineer/go-launchd/actions/workflows/test.yml)
     2  [Golang](https://go.dev/) support for macOS (Darwin) launchd socket activation ([launch_activate_socket](https://developer.apple.com/documentation/xpc/1505523-launch_activate_socket)) without [cgo](https://pkg.go.dev/cmd/cgo).
     3  
     4  ## How it works
     5  Using a similar technique as the [crypto/x509 package](https://go-review.googlesource.com/c/go/+/232397) and [golang.org/x/sys/unix package](https://pkg.go.dev/golang.org/x/sys/unix) it is possible to import the [launch_activate_socket](https://developer.apple.com/documentation/xpc/1505523-launch_activate_socket) function from `libxpc.dylib` at runtime via the `go:cgo_import_dynamic` directive:
     6  ```go
     7  // launch_activate_socket is defined in libxpc.dylib
     8  var libxpc_launch_activate_socket_trampoline_addr uintptr
     9  
    10  //go:cgo_import_dynamic libxpc_launch_activate_socket launch_activate_socket "/usr/lib/system/libxpc.dylib"
    11  ```
    12  This must be combined with a golang assembly file ([libxpc.s](./libxpc.s)) to populate the "trampoline" variable with a pointer to the relevant function:
    13  ```
    14  TEXT libxpc_launch_activate_socket_trampoline<>(SB),NOSPLIT,$0-0
    15      JMP	libxpc_launch_activate_socket(SB)
    16  
    17  GLOBL	·libxpc_launch_activate_socket_trampoline_addr(SB), RODATA, $8
    18  DATA	·libxpc_launch_activate_socket_trampoline_addr(SB)/8, $libxpc_launch_activate_socket_trampoline<>(SB)
    19  ```
    20  Finally by linking the internal `syscall.syscall` function we are able to invoke the [launch_activate_socket](https://developer.apple.com/documentation/xpc/1505523-launch_activate_socket) function:
    21  ```go
    22  // Implemented in the runtime package (runtime/sys_darwin.go)
    23  func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
    24  
    25  //go:linkname syscall_syscall syscall.syscall
    26  ```
    27  The remaining logic is primarily implemented in [libxpc.go](./libxpc.go) to convert from C structures into Golang equivalents.
    28  
    29  ## Usage
    30  See also the [example/](./example/) directory for the associated launchd job definition (plist):
    31  ```go
    32  package main
    33  
    34  import launchd "github.com/bored-engineer/go-launchd"
    35  
    36  func main() {
    37  	l, err := launchd.Activate("Listeners")
    38  	if err != nil {
    39  		log.Fatalf("launchd.Socket failed: %s", err)
    40  	}
    41  	for {
    42  		conn, err := l.Accept()
    43  		if err != nil {
    44  			log.Printf("(net.Listener).Accept failed: %s", err)
    45  			continue
    46  		}
    47  		go func(conn net.Conn) {
    48  			defer conn.Close()
    49  			io.Copy(conn, conn)
    50  		}(conn)
    51  	}
    52  }
    53  
    54  ```