utils.go 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /*
  2. Copyright 2025 Psiphon Inc.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package udsipc
  14. import (
  15. "context"
  16. "fmt"
  17. "log/slog"
  18. "os"
  19. "path/filepath"
  20. "syscall"
  21. "unsafe"
  22. )
  23. // ErrorCallback receives error notifications with context.
  24. type ErrorCallback func(err error, context string)
  25. // MaxSocketPathLength returns the maximum length for a Unix Domain Socket
  26. // path read directly from the syscall struct for the platform. 1 is then
  27. // subtracted from the returned length to account for a null byte terminator.
  28. func MaxSocketPathLength() int {
  29. var addr syscall.RawSockaddrUnix
  30. return int(unsafe.Sizeof(addr.Path) - 1)
  31. }
  32. // ResolveSocketPath determines the socket path to use.
  33. func ResolveSocketPath(systemd *SystemdManager, fallbackPath string) string {
  34. if !systemd.IsSystemd() {
  35. return fallbackPath
  36. }
  37. runtimeDir := systemd.GetRuntimeDir()
  38. if runtimeDir == "" {
  39. return fallbackPath
  40. }
  41. return filepath.Join(runtimeDir, filepath.Base(fallbackPath))
  42. }
  43. // EnsureSocketDir creates the socket directory if it doesn't exist.
  44. func EnsureSocketDir(socketPath string) error {
  45. dir := filepath.Dir(socketPath)
  46. if err := os.MkdirAll(dir, 0o750); err != nil {
  47. return fmt.Errorf("failed to create directory for socket path: %s: %w", socketPath, err)
  48. }
  49. return nil
  50. }
  51. // CleanupSocket removes the socket file if it exists.
  52. func CleanupSocket(socketPath string) error {
  53. err := os.Remove(socketPath)
  54. if err != nil && !os.IsNotExist(err) {
  55. return fmt.Errorf("failed to cleanup socket: %s: %w", socketPath, err)
  56. }
  57. return nil
  58. }
  59. // LogEnvironment logs the current environment configuration.
  60. func LogEnvironment(ctx context.Context, logger *slog.Logger, systemd *SystemdManager, socketPath string) {
  61. if systemd.IsSystemd() {
  62. logger.LogAttrs(ctx, slog.LevelInfo, "running under systemd",
  63. slog.String("socket_path", socketPath),
  64. slog.String("runtime_dir", systemd.GetRuntimeDir()),
  65. slog.String("state_dir", systemd.GetStateDir()),
  66. slog.Bool("socket_activation", systemd.GetSystemdListener() != nil),
  67. slog.Bool("ready_notification", systemd.notifyConn != nil),
  68. )
  69. } else {
  70. logger.LogAttrs(ctx, slog.LevelInfo, "running standalone", slog.String("socket_path", socketPath))
  71. }
  72. }