platform: Fix daemon data

This commit is contained in:
世界
2026-07-13 15:42:06 +08:00
parent a8a69228d8
commit f505a47bca
7 changed files with 217 additions and 148 deletions
+6 -12
View File
@@ -14,8 +14,7 @@ const crashReportsDirectoryName = "crash_reports"
var crashReportFileOrder = []string{metadataFileName, nativeLogFileName, goLogFileName, configSnapshotFileName}
func (s *desktopService) ListCrashReports(ctx context.Context, empty *emptypb.Empty) (*CrashReportList, error) {
reportsDirectory := filepath.Join(workingDirectory, crashReportsDirectoryName)
userID, err := s.daemon.reportCaller(ctx, reportsDirectory)
reportsDirectory, userID, err := s.daemon.reportCaller(ctx, crashReportsDirectoryName)
if err != nil {
return nil, err
}
@@ -48,8 +47,7 @@ func (s *desktopService) ListCrashReports(ctx context.Context, empty *emptypb.Em
}
func (s *desktopService) ReadCrashReport(ctx context.Context, request *CrashReportRequest) (*CrashReportContent, error) {
reportsDirectory := filepath.Join(workingDirectory, crashReportsDirectoryName)
userID, err := s.daemon.reportCaller(ctx, reportsDirectory)
reportsDirectory, userID, err := s.daemon.reportCaller(ctx, crashReportsDirectoryName)
if err != nil {
return nil, err
}
@@ -75,8 +73,7 @@ func (s *desktopService) ReadCrashReport(ctx context.Context, request *CrashRepo
}
func (s *desktopService) MarkCrashReportRead(ctx context.Context, request *CrashReportRequest) (*emptypb.Empty, error) {
reportsDirectory := filepath.Join(workingDirectory, crashReportsDirectoryName)
userID, err := s.daemon.reportCaller(ctx, reportsDirectory)
reportsDirectory, userID, err := s.daemon.reportCaller(ctx, crashReportsDirectoryName)
if err != nil {
return nil, err
}
@@ -92,8 +89,7 @@ func (s *desktopService) MarkCrashReportRead(ctx context.Context, request *Crash
}
func (s *desktopService) ExportCrashReport(ctx context.Context, request *CrashReportExportRequest) (*CrashReportArchive, error) {
reportsDirectory := filepath.Join(workingDirectory, crashReportsDirectoryName)
userID, err := s.daemon.reportCaller(ctx, reportsDirectory)
reportsDirectory, userID, err := s.daemon.reportCaller(ctx, crashReportsDirectoryName)
if err != nil {
return nil, err
}
@@ -101,8 +97,7 @@ func (s *desktopService) ExportCrashReport(ctx context.Context, request *CrashRe
}
func (s *desktopService) DeleteCrashReport(ctx context.Context, request *CrashReportRequest) (*emptypb.Empty, error) {
reportsDirectory := filepath.Join(workingDirectory, crashReportsDirectoryName)
userID, err := s.daemon.reportCaller(ctx, reportsDirectory)
reportsDirectory, userID, err := s.daemon.reportCaller(ctx, crashReportsDirectoryName)
if err != nil {
return nil, err
}
@@ -118,8 +113,7 @@ func (s *desktopService) DeleteCrashReport(ctx context.Context, request *CrashRe
}
func (s *desktopService) DeleteAllCrashReports(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) {
reportsDirectory := filepath.Join(workingDirectory, crashReportsDirectoryName)
userID, err := s.daemon.reportCaller(ctx, reportsDirectory)
reportsDirectory, userID, err := s.daemon.reportCaller(ctx, crashReportsDirectoryName)
if err != nil {
return nil, err
}
+63 -34
View File
@@ -28,13 +28,13 @@ func (s *desktopService) GetDaemonInfo(ctx context.Context, empty *emptypb.Empty
return nil, err
}
ownership := DaemonOwnership_DAEMON_OWNERSHIP_AVAILABLE
options, err := loadStartOptions()
ownerUserID, err := loadOwner()
if err != nil && !os.IsNotExist(err) {
return nil, err
}
if options.OwnerUserID == identity.UserID {
if ownerUserID == identity.UserID {
ownership = DaemonOwnership_DAEMON_OWNERSHIP_CALLER
} else if options.OwnerUserID != "" {
} else if ownerUserID != "" {
ownership = DaemonOwnership_DAEMON_OWNERSHIP_OTHER
}
return &DaemonInfo{
@@ -53,29 +53,39 @@ func (s *desktopService) StartService(ctx context.Context, request *StartService
if s.daemon.closed {
return nil, os.ErrClosed
}
currentOptions, err := loadStartOptions()
ownerUserID, err := loadOwner()
if err != nil && !os.IsNotExist(err) {
return nil, err
}
if currentOptions.OwnerUserID != "" && currentOptions.OwnerUserID != identity.UserID {
if ownerUserID != "" && ownerUserID != identity.UserID {
return nil, status.Error(codes.PermissionDenied, "the service is owned by another user")
}
if ownerUserID == "" {
err = saveOwner(identity.UserID)
if err != nil {
return nil, err
}
}
currentOptions, err := loadStartOptions(identity.UserID)
if err != nil && !os.IsNotExist(err) {
return nil, err
}
mergedOptions := currentOptions
mergedOptions.WasRunning = true
mergedOptions.OwnerUserID = identity.UserID
if request.Options != nil {
mergedOptions.OOMKillerEnabled = request.Options.OomKillerEnabled
mergedOptions.OOMKillerDisabled = request.Options.OomKillerDisabled
mergedOptions.OOMMemoryLimit = request.Options.OomMemoryLimit
}
err = s.daemon.startService(request.ConfigContent, mergedOptions)
err = s.daemon.startServiceLocked(identity.UserID, request.ConfigContent, mergedOptions)
if err != nil {
return nil, s.daemon.cleanFailedStartLocked(identity.UserID, err)
return nil, s.daemon.cleanFailedStartLocked(identity.UserID, mergedOptions, err)
}
configError := atomicfile.WriteFile(filepath.Join(workingDirectory, serviceConfigFileName), []byte(request.ConfigContent), 0o600)
optionsError := saveStartOptions(mergedOptions)
directory := userWorkingDirectory(identity.UserID)
configError := atomicfile.WriteFile(filepath.Join(directory, serviceConfigFileName), []byte(request.ConfigContent), 0o600)
optionsError := saveStartOptions(identity.UserID, mergedOptions)
if configError != nil || optionsError != nil {
return nil, s.daemon.cleanFailedStartLocked(identity.UserID, E.Errors(configError, optionsError))
return nil, s.daemon.cleanFailedStartLocked(identity.UserID, mergedOptions, E.Errors(configError, optionsError))
}
return &emptypb.Empty{}, nil
}
@@ -90,17 +100,21 @@ func (s *desktopService) ClaimService(ctx context.Context, empty *emptypb.Empty)
if s.daemon.closed {
return nil, os.ErrClosed
}
options, err := loadStartOptions()
ownerUserID, err := loadOwner()
if err != nil && !os.IsNotExist(err) {
return nil, err
}
if options.OwnerUserID == identity.UserID {
if ownerUserID == identity.UserID {
return &emptypb.Empty{}, nil
}
if options.OwnerUserID != "" {
if ownerUserID != "" {
return nil, status.Error(codes.Aborted, "the service was claimed by another user")
}
err = s.daemon.resetRuntimeOwnerLocked(identity.UserID)
err = s.daemon.configureWorkingDirectoryLocked(userWorkingDirectory(identity.UserID))
if err != nil {
return nil, err
}
err = saveOwner(identity.UserID)
if err != nil {
return nil, err
}
@@ -117,14 +131,24 @@ func (s *desktopService) TakeOverService(ctx context.Context, empty *emptypb.Emp
if s.daemon.closed {
return nil, os.ErrClosed
}
options, err := loadStartOptions()
ownerUserID, err := loadOwner()
if err != nil && !os.IsNotExist(err) {
return nil, err
}
if options.OwnerUserID == identity.UserID {
if ownerUserID == identity.UserID {
return &emptypb.Empty{}, nil
}
err = s.daemon.stopServiceLocked(identity.UserID)
if ownerUserID != "" {
err = s.daemon.stopServiceLocked(ownerUserID)
if err != nil {
return nil, err
}
}
err = s.daemon.configureWorkingDirectoryLocked(userWorkingDirectory(identity.UserID))
if err != nil {
return nil, err
}
err = saveOwner(identity.UserID)
if err != nil {
return nil, err
}
@@ -132,12 +156,14 @@ func (s *desktopService) TakeOverService(ctx context.Context, empty *emptypb.Emp
return &emptypb.Empty{}, nil
}
func (d *Daemon) cleanFailedStartLocked(ownerUserID string, startError error) error {
func (d *Daemon) cleanFailedStartLocked(ownerUserID string, options startOptions, startError error) error {
closeError := d.startedService.CloseService()
crashReportError := tagUnownedReports(filepath.Join(workingDirectory, crashReportsDirectoryName), ownerUserID)
oomReportError := tagUnownedReports(filepath.Join(workingDirectory, oomReportsDirectoryName), ownerUserID)
resetError := d.resetRuntimeOwnerLocked(ownerUserID)
return E.Errors(startError, closeError, crashReportError, oomReportError, resetError)
directory := userWorkingDirectory(ownerUserID)
crashReportError := tagUnownedReports(filepath.Join(directory, crashReportsDirectoryName), ownerUserID)
oomReportError := tagUnownedReports(filepath.Join(directory, oomReportsDirectoryName), ownerUserID)
options.WasRunning = false
snapshotError := saveStartOptions(ownerUserID, options)
return E.Errors(startError, closeError, crashReportError, oomReportError, snapshotError)
}
func (s *desktopService) GetWorkingDirectory(ctx context.Context, empty *emptypb.Empty) (*WorkingDirectoryInfo, error) {
@@ -147,19 +173,20 @@ func (s *desktopService) GetWorkingDirectory(ctx context.Context, empty *emptypb
}
s.daemon.lifecycleAccess.Lock()
defer s.daemon.lifecycleAccess.Unlock()
options, err := loadStartOptions()
ownerUserID, err := loadOwner()
if err != nil {
return nil, err
}
if options.OwnerUserID != identity.UserID {
if ownerUserID != identity.UserID {
return nil, status.Error(codes.PermissionDenied, "the service is owned by another user")
}
size, err := directorySize(workingDirectory)
directory := userWorkingDirectory(identity.UserID)
size, err := directorySize(directory)
if err != nil {
return nil, err
}
return &WorkingDirectoryInfo{
Path: workingDirectory,
Path: directory,
Size: size,
}, nil
}
@@ -177,22 +204,24 @@ func (s *desktopService) DestroyWorkingDirectory(ctx context.Context, empty *emp
if s.daemon.startedService.Instance() != nil {
return nil, status.Error(codes.FailedPrecondition, "the service must be stopped before destroying the working directory")
}
options, err := loadStartOptions()
if err != nil && !os.IsNotExist(err) {
ownerUserID, err := loadOwner()
if err != nil {
return nil, err
}
if options.OwnerUserID != "" && options.OwnerUserID != identity.UserID {
if ownerUserID != identity.UserID {
return nil, status.Error(codes.PermissionDenied, "the service is owned by another user")
}
err = s.daemon.resetRuntimeOwnerLocked(identity.UserID)
directory := userWorkingDirectory(identity.UserID)
err = s.daemon.configureWorkingDirectoryLocked(workingDirectory)
if err != nil {
return nil, err
}
err = deleteReportsForUser(filepath.Join(workingDirectory, crashReportsDirectoryName), identity.UserID)
err = os.RemoveAll(directory)
if err != nil {
return nil, err
restoreError := s.daemon.configureWorkingDirectoryLocked(directory)
return nil, E.Errors(err, restoreError)
}
err = deleteReportsForUser(filepath.Join(workingDirectory, oomReportsDirectoryName), identity.UserID)
err = s.daemon.configureWorkingDirectoryLocked(directory)
if err != nil {
return nil, err
}
+10 -6
View File
@@ -20,31 +20,35 @@ func (h *managedHandler) ServiceStop() error {
if h.daemon.closed {
return os.ErrClosed
}
options, err := loadStartOptions()
ownerUserID, err := loadOwner()
if err != nil {
return err
}
return h.daemon.stopServiceLocked(options.OwnerUserID)
return h.daemon.stopServiceLocked(ownerUserID)
}
func (h *managedHandler) ServiceReload() error {
if h.daemon.closed {
return os.ErrClosed
}
configContent, err := loadServiceConfig()
ownerUserID, err := loadOwner()
if err != nil {
return err
}
options, err := loadStartOptions()
configContent, err := loadServiceConfig(ownerUserID)
if err != nil {
return err
}
err = h.daemon.startService(configContent, options)
options, err := loadStartOptions(ownerUserID)
if err != nil {
return err
}
err = h.daemon.startServiceLocked(ownerUserID, configContent, options)
if err != nil {
return err
}
options.WasRunning = true
return saveStartOptions(options)
return saveStartOptions(ownerUserID, options)
}
func (h *managedHandler) SystemProxyStatus() (*daemon.SystemProxyStatus, error) {
+6 -12
View File
@@ -19,8 +19,7 @@ const oomReportsDirectoryName = "oom_reports"
var oomReportLeadingFileOrder = []string{metadataFileName, configSnapshotFileName, goLogFileName}
func (s *desktopService) ListOOMReports(ctx context.Context, empty *emptypb.Empty) (*OOMReportList, error) {
reportsDirectory := filepath.Join(workingDirectory, oomReportsDirectoryName)
userID, err := s.daemon.reportCaller(ctx, reportsDirectory)
reportsDirectory, userID, err := s.daemon.reportCaller(ctx, oomReportsDirectoryName)
if err != nil {
return nil, err
}
@@ -53,8 +52,7 @@ func (s *desktopService) ListOOMReports(ctx context.Context, empty *emptypb.Empt
}
func (s *desktopService) ReadOOMReport(ctx context.Context, request *OOMReportRequest) (*OOMReportContent, error) {
reportsDirectory := filepath.Join(workingDirectory, oomReportsDirectoryName)
userID, err := s.daemon.reportCaller(ctx, reportsDirectory)
reportsDirectory, userID, err := s.daemon.reportCaller(ctx, oomReportsDirectoryName)
if err != nil {
return nil, err
}
@@ -102,8 +100,7 @@ func (s *desktopService) ReadOOMReport(ctx context.Context, request *OOMReportRe
}
func (s *desktopService) MarkOOMReportRead(ctx context.Context, request *OOMReportRequest) (*emptypb.Empty, error) {
reportsDirectory := filepath.Join(workingDirectory, oomReportsDirectoryName)
userID, err := s.daemon.reportCaller(ctx, reportsDirectory)
reportsDirectory, userID, err := s.daemon.reportCaller(ctx, oomReportsDirectoryName)
if err != nil {
return nil, err
}
@@ -119,8 +116,7 @@ func (s *desktopService) MarkOOMReportRead(ctx context.Context, request *OOMRepo
}
func (s *desktopService) ExportOOMReport(ctx context.Context, request *OOMReportExportRequest) (*CrashReportArchive, error) {
reportsDirectory := filepath.Join(workingDirectory, oomReportsDirectoryName)
userID, err := s.daemon.reportCaller(ctx, reportsDirectory)
reportsDirectory, userID, err := s.daemon.reportCaller(ctx, oomReportsDirectoryName)
if err != nil {
return nil, err
}
@@ -128,8 +124,7 @@ func (s *desktopService) ExportOOMReport(ctx context.Context, request *OOMReport
}
func (s *desktopService) DeleteOOMReport(ctx context.Context, request *OOMReportRequest) (*emptypb.Empty, error) {
reportsDirectory := filepath.Join(workingDirectory, oomReportsDirectoryName)
userID, err := s.daemon.reportCaller(ctx, reportsDirectory)
reportsDirectory, userID, err := s.daemon.reportCaller(ctx, oomReportsDirectoryName)
if err != nil {
return nil, err
}
@@ -145,8 +140,7 @@ func (s *desktopService) DeleteOOMReport(ctx context.Context, request *OOMReport
}
func (s *desktopService) DeleteAllOOMReports(ctx context.Context, empty *emptypb.Empty) (*emptypb.Empty, error) {
reportsDirectory := filepath.Join(workingDirectory, oomReportsDirectoryName)
userID, err := s.daemon.reportCaller(ctx, reportsDirectory)
reportsDirectory, userID, err := s.daemon.reportCaller(ctx, oomReportsDirectoryName)
if err != nil {
return nil, err
}
+14 -10
View File
@@ -92,22 +92,26 @@ func tagUnownedReports(reportsDirectory string, userID string) error {
return nil
}
func (d *Daemon) reportCaller(ctx context.Context, reportsDirectory string) (string, error) {
func (d *Daemon) reportCaller(ctx context.Context, reportsDirectoryName string) (string, string, error) {
identity, err := peerIdentityFromContext(ctx)
if err != nil {
return "", err
return "", "", err
}
d.lifecycleAccess.Lock()
defer d.lifecycleAccess.Unlock()
options, err := loadStartOptions()
if err != nil && !os.IsNotExist(err) {
return "", err
}
err = tagUnownedReports(reportsDirectory, options.OwnerUserID)
ownerUserID, err := loadOwner()
if err != nil {
return "", err
return "", "", err
}
return identity.UserID, nil
if ownerUserID != identity.UserID {
return "", "", status.Error(codes.PermissionDenied, "the service is owned by another user")
}
reportsDirectory := filepath.Join(userWorkingDirectory(identity.UserID), reportsDirectoryName)
err = tagUnownedReports(reportsDirectory, identity.UserID)
if err != nil {
return "", "", err
}
return reportsDirectory, identity.UserID, nil
}
func deleteReportsForUser(reportsDirectory string, userID string) error {
@@ -165,7 +169,7 @@ func exportReportArchive(reportsDirectory string, name string, userID string, wi
if err != nil {
return nil, err
}
tempRoot := filepath.Join(workingDirectory, "temp")
tempRoot := filepath.Join(filepath.Dir(reportsDirectory), "temp")
err = os.MkdirAll(tempRoot, 0o700)
if err != nil {
return nil, err
+70 -63
View File
@@ -24,23 +24,22 @@ import (
"google.golang.org/grpc/status"
)
const daemonCrashOutputFileName = "CrashReport-Daemon.log"
type Daemon struct {
logger log.ContextLogger
startedService *daemon.StartedService
server *grpc.Server
listenerPath string
lifecycleAccess sync.Mutex
closed bool
peerAccess sync.Mutex
peerConnections map[peerConnection]peerIdentity
logger log.ContextLogger
startedService *daemon.StartedService
server *grpc.Server
runtimeWorkingDirectory string
lifecycleAccess sync.Mutex
closed bool
peerAccess sync.Mutex
peerConnections map[peerConnection]peerIdentity
}
func newDaemon() (*Daemon, error) {
ctx := include.Context(context.Background())
d := &Daemon{
logger: log.StdLogger(),
logger: log.StdLogger(),
runtimeWorkingDirectory: workingDirectory,
}
d.startedService = daemon.NewStartedService(daemon.ServiceOptions{
Context: ctx,
@@ -91,13 +90,6 @@ func (d *Daemon) Start() error {
if err != nil {
return err
}
if listener.Addr().Network() == "unix" {
d.listenerPath, err = filepath.Abs(listener.Addr().String())
if err != nil {
listener.Close()
return err
}
}
d.logger.Info("daemon listening at ", listener.Addr())
go func() {
serveError := d.server.Serve(listener)
@@ -115,38 +107,82 @@ func (d *Daemon) restore() {
if d.closed {
return
}
options, err := loadStartOptions()
ownerUserID, err := loadOwner()
if err != nil {
if !os.IsNotExist(err) {
d.logger.Warn("load owner: ", err)
}
return
}
ownerWorkingDirectory := userWorkingDirectory(ownerUserID)
err = d.configureWorkingDirectoryLocked(ownerWorkingDirectory)
if err != nil {
d.logger.Warn("configure working directory: ", err)
return
}
options, err := loadStartOptions(ownerUserID)
if err != nil {
if !os.IsNotExist(err) {
d.logger.Warn("load start options: ", err)
}
return
}
err = tagUnownedReports(filepath.Join(workingDirectory, crashReportsDirectoryName), options.OwnerUserID)
err = tagUnownedReports(filepath.Join(ownerWorkingDirectory, crashReportsDirectoryName), ownerUserID)
if err != nil {
d.logger.Warn("tag crash reports: ", err)
}
err = tagUnownedReports(filepath.Join(workingDirectory, oomReportsDirectoryName), options.OwnerUserID)
err = tagUnownedReports(filepath.Join(ownerWorkingDirectory, oomReportsDirectoryName), ownerUserID)
if err != nil {
d.logger.Warn("tag OOM reports: ", err)
}
if !options.WasRunning {
return
}
configContent, err := loadServiceConfig()
configContent, err := loadServiceConfig(ownerUserID)
if err != nil {
d.logger.Error("restore service: ", err)
return
}
d.logger.Info("restoring service")
err = d.startService(configContent, options)
err = d.startServiceLocked(ownerUserID, configContent, options)
if err != nil {
d.logger.Error("restore service: ", err)
}
}
func (d *Daemon) startService(configContent string, options startOptions) error {
_ = os.WriteFile(filepath.Join(workingDirectory, configSnapshotFileName), []byte(configContent), 0o600)
func (d *Daemon) configureWorkingDirectoryLocked(directory string) error {
if d.runtimeWorkingDirectory == directory {
return nil
}
err := os.MkdirAll(directory, 0o700)
if err != nil {
return err
}
err = os.Chdir(directory)
if err != nil {
return err
}
err = libbox.Setup(&libbox.SetupOptions{
BasePath: directory,
WorkingPath: directory,
TempPath: directory,
CrashReportSource: "Daemon",
})
if err != nil {
return err
}
libbox.PromoteOOMDraft()
d.runtimeWorkingDirectory = directory
return nil
}
func (d *Daemon) startServiceLocked(ownerUserID string, configContent string, options startOptions) error {
directory := userWorkingDirectory(ownerUserID)
err := d.configureWorkingDirectoryLocked(directory)
if err != nil {
return err
}
_ = os.WriteFile(filepath.Join(directory, configSnapshotFileName), []byte(configContent), 0o600)
libbox.ReloadSetupOptions(&libbox.SetupOptions{
OomKillerEnabled: options.OOMKillerEnabled,
OomKillerDisabled: options.OOMKillerDisabled,
@@ -156,39 +192,8 @@ func (d *Daemon) startService(configContent string, options startOptions) error
return d.startedService.StartOrReloadService(configContent, nil)
}
func (d *Daemon) clearRuntimeData() error {
entries, err := os.ReadDir(workingDirectory)
if err != nil {
return err
}
for _, entry := range entries {
if entry.Name() == crashReportsDirectoryName ||
entry.Name() == oomReportsDirectoryName ||
entry.Name() == daemonCrashOutputFileName {
continue
}
entryPath := filepath.Join(workingDirectory, entry.Name())
if d.listenerPath != "" && entryPath == d.listenerPath {
continue
}
err = os.RemoveAll(entryPath)
if err != nil {
return err
}
}
return nil
}
func (d *Daemon) resetRuntimeOwnerLocked(ownerUserID string) error {
err := d.clearRuntimeData()
if err != nil {
return err
}
return saveStartOptions(startOptions{OwnerUserID: ownerUserID})
}
func (d *Daemon) stopServiceLocked(nextOwnerUserID string) error {
options, err := loadStartOptions()
func (d *Daemon) stopServiceLocked(ownerUserID string) error {
options, err := loadStartOptions(ownerUserID)
if err != nil && !os.IsNotExist(err) {
return err
}
@@ -198,15 +203,17 @@ func (d *Daemon) stopServiceLocked(nextOwnerUserID string) error {
return err
}
}
crashReportError := tagUnownedReports(filepath.Join(workingDirectory, crashReportsDirectoryName), options.OwnerUserID)
directory := userWorkingDirectory(ownerUserID)
crashReportError := tagUnownedReports(filepath.Join(directory, crashReportsDirectoryName), ownerUserID)
if crashReportError != nil {
return crashReportError
}
oomReportError := tagUnownedReports(filepath.Join(workingDirectory, oomReportsDirectoryName), options.OwnerUserID)
oomReportError := tagUnownedReports(filepath.Join(directory, oomReportsDirectoryName), ownerUserID)
if oomReportError != nil {
return oomReportError
}
return d.resetRuntimeOwnerLocked(nextOwnerUserID)
options.WasRunning = false
return saveStartOptions(ownerUserID, options)
}
func (d *Daemon) Close() {
@@ -311,14 +318,14 @@ func ownerProtectedMethod(method string) bool {
}
func (d *Daemon) authorizeOwnerLocked(userID string) error {
options, err := loadStartOptions()
ownerUserID, err := loadOwner()
if err != nil {
if os.IsNotExist(err) {
return status.Error(codes.PermissionDenied, "the service has no owner")
}
return err
}
if options.OwnerUserID == "" || options.OwnerUserID != userID {
if ownerUserID == "" || ownerUserID != userID {
return status.Error(codes.PermissionDenied, "the service is owned by another user")
}
return nil
+48 -11
View File
@@ -1,6 +1,8 @@
package main
import (
"crypto/sha256"
"encoding/hex"
"os"
"path/filepath"
@@ -11,26 +13,56 @@ import (
const (
serviceConfigFileName = "config.json"
startOptionsFileName = "start_options.json"
ownerFileName = "owner.json"
usersDirectoryName = "users"
)
type startOptions struct {
WasRunning bool `json:"was_running"`
OwnerUserID string `json:"owner_user_id"`
OOMKillerEnabled bool `json:"oom_killer_enabled"`
OOMKillerDisabled bool `json:"oom_killer_disabled"`
OOMMemoryLimit int64 `json:"oom_memory_limit"`
WasRunning bool `json:"was_running"`
OOMKillerEnabled bool `json:"oom_killer_enabled"`
OOMKillerDisabled bool `json:"oom_killer_disabled"`
OOMMemoryLimit int64 `json:"oom_memory_limit"`
}
func loadServiceConfig() (string, error) {
content, err := os.ReadFile(filepath.Join(workingDirectory, serviceConfigFileName))
type ownerState struct {
UserID string `json:"user_id"`
}
func userWorkingDirectory(userID string) string {
digest := sha256.Sum256([]byte(userID))
return filepath.Join(workingDirectory, usersDirectoryName, hex.EncodeToString(digest[:]))
}
func loadOwner() (string, error) {
content, err := os.ReadFile(filepath.Join(workingDirectory, ownerFileName))
if err != nil {
return "", err
}
state, err := json.UnmarshalExtended[ownerState](content)
if err != nil {
return "", err
}
return state.UserID, nil
}
func saveOwner(userID string) error {
content, err := json.Marshal(ownerState{UserID: userID})
if err != nil {
return err
}
return atomicfile.WriteFile(filepath.Join(workingDirectory, ownerFileName), content, 0o600)
}
func loadServiceConfig(userID string) (string, error) {
content, err := os.ReadFile(filepath.Join(userWorkingDirectory(userID), serviceConfigFileName))
if err != nil {
return "", err
}
return string(content), nil
}
func loadStartOptions() (startOptions, error) {
content, err := os.ReadFile(filepath.Join(workingDirectory, startOptionsFileName))
func loadStartOptions(userID string) (startOptions, error) {
content, err := os.ReadFile(filepath.Join(userWorkingDirectory(userID), startOptionsFileName))
if err != nil {
return startOptions{}, err
}
@@ -41,10 +73,15 @@ func loadStartOptions() (startOptions, error) {
return options, nil
}
func saveStartOptions(options startOptions) error {
func saveStartOptions(userID string, options startOptions) error {
content, err := json.Marshal(options)
if err != nil {
return err
}
return atomicfile.WriteFile(filepath.Join(workingDirectory, startOptionsFileName), content, 0o600)
directory := userWorkingDirectory(userID)
err = os.MkdirAll(directory, 0o700)
if err != nil {
return err
}
return atomicfile.WriteFile(filepath.Join(directory, startOptionsFileName), content, 0o600)
}