carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux
2
3package dbreads
4
5import (
6 "errors"
7 "fmt"
8 "log"
9 "net"
10 "os"
11 "os/user"
12 "strconv"
13
14 "golang.org/x/sys/unix"
15)
16
17var errNotSocket = errors.New("stdin is not a connected unix stream socket")
18
19// RunWorker is `carlos system db-worker`, which carlos-dbread@.service runs
20// once per connection to carlos-dbread.socket (spec §8.3).
21func RunWorker(args []string) {
22 if len(args) != 0 {
23 fmt.Fprintln(os.Stderr, "db-worker: takes no arguments")
24 os.Exit(2)
25 }
26 RunWorkerWith(WorkerOptions{Scratch: "/var/tmp", MaxRestored: fileSizeLimit()})
27}
28
29// RunWorkerWith is RunWorker with its options supplied: the seam the root
30// runner's acceptance tests use to make a restore slow (Task 15).
31func RunWorkerWith(opt WorkerOptions) {
32 conn, err := StdinConn(os.Stdin, CarlosUID)
33 if err != nil {
34 fmt.Fprintf(os.Stderr, "db-worker: %v\n", err)
35 os.Exit(2)
36 }
37 if err := ServeWorker(conn, opt); err != nil {
38 log.Printf("db-worker: %v", err)
39 os.Exit(1)
40 }
41}
42
43// CarlosUID is the agent's user, the only peer the worker serves.
44func CarlosUID() (uint32, error) {
45 u, err := user.Lookup("carlos")
46 if err != nil {
47 return 0, err
48 }
49 uid, err := strconv.ParseUint(u.Uid, 10, 32)
50 return uint32(uid), err
51}
52
53// StdinConn checks f is a connected unix stream socket (SO_TYPE, the socket
54// name's family, SO_PEERCRED) whose peer is wantUID, and returns it as a
55// connection.
56func StdinConn(f *os.File, wantUID func() (uint32, error)) (net.Conn, error) {
57 fd := int(f.Fd())
58 typ, err := unix.GetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_TYPE)
59 if err != nil || typ != unix.SOCK_STREAM {
60 return nil, errNotSocket
61 }
62 if sa, err := unix.Getsockname(fd); err != nil {
63 return nil, errNotSocket
64 } else if _, ok := sa.(*unix.SockaddrUnix); !ok {
65 return nil, errNotSocket
66 }
67 cred, err := unix.GetsockoptUcred(fd, unix.SOL_SOCKET, unix.SO_PEERCRED)
68 if err != nil || cred.Pid == 0 {
69 return nil, errNotSocket
70 }
71 want, err := wantUID()
72 if err != nil {
73 return nil, err
74 }
75 if cred.Uid != want {
76 return nil, fmt.Errorf("the peer is uid %d, not the agent's uid %d", cred.Uid, want)
77 }
78 c, err := net.FileConn(f)
79 if err != nil {
80 return nil, errNotSocket
81 }
82 return c, nil
83}
84
85// fileSizeLimit is the unit's LimitFSIZE, the restored-size cap the box set
86// for its workers, or DefaultMaxRestored when the process has no limit.
87func fileSizeLimit() int64 {
88 var r unix.Rlimit
89 if err := unix.Getrlimit(unix.RLIMIT_FSIZE, &r); err != nil || r.Cur == unix.RLIM_INFINITY || r.Cur > 1<<62 {
90 return DefaultMaxRestored
91 }
92 return int64(r.Cur)
93}
94