91 lines
3.3 KiB
Go
91 lines
3.3 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package event
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const eventRuntimeDirPrefix = "dws-event-"
|
|
|
|
func currentUserID() string {
|
|
return strconv.Itoa(os.Geteuid())
|
|
}
|
|
|
|
// MaxUnixSocketPath returns the longest Unix socket path accepted by
|
|
// bind/connect on this OS (Go rejects longer names with EINVAL before
|
|
// the syscall). sockaddr_un.sun_path is 104 bytes on darwin and the
|
|
// BSDs and 108 on Linux; the usable budget is one less.
|
|
func MaxUnixSocketPath() int {
|
|
return maxUnixSocketPath(runtime.GOOS)
|
|
}
|
|
|
|
func maxUnixSocketPath(goos string) int {
|
|
if goos == "linux" {
|
|
return 107
|
|
}
|
|
return 103
|
|
}
|
|
|
|
// IPCEndpoint returns the bus IPC endpoint for one identity: a Named Pipe
|
|
// name on Windows, otherwise a deterministic Unix socket under a private
|
|
// per-user runtime directory.
|
|
//
|
|
// Unix sockets must live on a local filesystem that supports bind(2).
|
|
// Config directories may reside on NFS, CSI, FUSE, or other shared mounts
|
|
// that reject Unix socket creation with ENOTSUPP. On Unix, the endpoint uses
|
|
// XDG_RUNTIME_DIR when it is absolute and short enough; otherwise it falls
|
|
// back to a per-UID directory under os.TempDir. The transport creates and
|
|
// validates that directory as owner-only before listening or dialing. The
|
|
// socket name is keyed by a hash of workDir so every process (consume parent,
|
|
// forked _bus child, status/stop tooling) that derives the endpoint from the
|
|
// same workDir agrees on the location. bus.lock / bus.meta / bus.log always
|
|
// stay in workDir.
|
|
//
|
|
// This is the single source of truth for endpoint derivation; the cobra
|
|
// layer and busctl must not re-implement the shape.
|
|
func IPCEndpoint(workDir, editionName string, sourceKind SourceKind, identityHash string) string {
|
|
return ipcEndpointForOS(runtime.GOOS, workDir, editionName, sourceKind, identityHash)
|
|
}
|
|
|
|
func ipcEndpointForOS(goos, workDir, editionName string, sourceKind SourceKind, identityHash string) string {
|
|
if sourceKind == "" {
|
|
sourceKind = SourceKindAppStream
|
|
}
|
|
if goos == "windows" {
|
|
return `\\.\pipe\dws-event-` + editionName + "-" + string(sourceKind) + "-" + identityHash
|
|
}
|
|
return unixSocketEndpoint(goos, workDir, strings.TrimSpace(os.Getenv("XDG_RUNTIME_DIR")), os.TempDir())
|
|
}
|
|
|
|
func unixSocketEndpoint(goos, workDir, runtimeDir, tempDir string) string {
|
|
socketName := "dws-evt-" + IdentityHash(workDir) + ".sock"
|
|
userDirName := eventRuntimeDirPrefix + currentUserID()
|
|
if filepath.IsAbs(runtimeDir) {
|
|
candidate := filepath.Join(runtimeDir, userDirName, socketName)
|
|
if len(candidate) <= maxUnixSocketPath(goos) {
|
|
return candidate
|
|
}
|
|
}
|
|
fallback := filepath.Join(tempDir, userDirName, socketName)
|
|
if len(fallback) <= maxUnixSocketPath(goos) {
|
|
return fallback
|
|
}
|
|
return filepath.Join("/tmp", userDirName, socketName)
|
|
}
|