1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
//go:build linux && cgo
package endpoints
import (
"errors"
"fmt"
"net"
"os"
"os/exec"
"os/user"
"strconv"
incus "github.com/lxc/incus/v6/client"
"github.com/lxc/incus/v6/shared/logger"
"github.com/lxc/incus/v6/shared/subprocess"
"github.com/lxc/incus/v6/shared/util"
)
// Bind to the given unix socket path.
func socketUnixListen(path string) (*net.UnixListener, error) {
addr, err := net.ResolveUnixAddr("unix", path)
if err != nil {
return nil, fmt.Errorf("cannot resolve socket address: %w", err)
}
listener, err := net.ListenUnix("unix", addr)
if err != nil {
return nil, fmt.Errorf("cannot bind socket: %w", err)
}
return listener, err
}
// CheckAlreadyRunning checks if the socket at the given path is already
// bound to a running process, and return an error if so.
//
// FIXME: We should probably rather just try a regular unix socket
// connection without using the client. However this is the way
// this logic has historically behaved, so let's keep it like it
// was.
func CheckAlreadyRunning(path string) error {
// If socket activated, nothing to do
pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
if err == nil {
if pid == os.Getpid() {
return nil
}
}
// If there's no socket file at all, there's nothing to do.
if !util.PathExists(path) {
return nil
}
_, err = incus.ConnectIncusUnix(path, nil)
// If the connection succeeded it means there's another daemon running.
if err == nil {
return errors.New("Incus is already running")
}
return nil
}
// Remove any stale socket file at the given path.
func socketUnixRemoveStale(path string) error {
// If there's no socket file at all, there's nothing to do.
if !util.PathExists(path) {
return nil
}
logger.Debugf("Detected stale unix socket, deleting")
err := os.Remove(path)
if err != nil {
return fmt.Errorf("could not delete stale local socket: %w", err)
}
return nil
}
// Change the file mode of the given unix socket file,.
func socketUnixSetPermissions(path string, mode os.FileMode) error {
err := os.Chmod(path, mode)
if err != nil {
return fmt.Errorf("cannot set permissions on local socket: %w", err)
}
return nil
}
// Change the ownership of the given unix socket file,.
func socketUnixSetOwnership(path string, groupName string) error {
var gid int
var err error
if groupName != "" {
g, err := user.LookupGroup(groupName)
if err != nil {
return fmt.Errorf("cannot get group ID of '%s': %w", groupName, err)
}
gid, err = strconv.Atoi(g.Gid)
if err != nil {
return err
}
} else {
gid = os.Getgid()
}
err = os.Chown(path, os.Getuid(), gid)
if err != nil {
return fmt.Errorf("cannot change ownership on local socket: %w", err)
}
return nil
}
// Set the SELinux label on the socket.
func socketUnixSetLabel(path string, label string) error {
// Skip if no label requested.
if label == "" {
return nil
}
// Check if chcon is installed.
_, err := exec.LookPath("chcon")
if err != nil {
return nil
}
// Attempt to apply (don't fail as kernel may not support it).
_, _ = subprocess.RunCommand("chcon", label, path)
return nil
}
|