Skip to content

Commit b1c12ab

Browse files
create system job on darwin
1 parent c72f847 commit b1c12ab

File tree

2 files changed

+48
-10
lines changed

2 files changed

+48
-10
lines changed

examples/dev.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ self:
8585
schedule:
8686
- "*:15,45"
8787

88+
system:
89+
initialize: true
90+
inherit: default
91+
backup:
92+
source: ./
93+
schedule:
94+
- "*:5,10,20,25,35,40,50,55"
95+
schedule-permission: system
96+
8897
src:
8998
lock: "/tmp/resticprofile-profile-src.lock"
9099
backup:

schedule/schedule_darwin.go

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"strings"
1515

1616
"github.com/creativeprojects/resticprofile/calendar"
17+
"github.com/creativeprojects/resticprofile/constants"
1718
"howett.net/plist"
1819
)
1920

@@ -75,11 +76,10 @@ func (c *CalendarInterval) clone() *CalendarInterval {
7576

7677
// createJob creates a plist file and register it with launchd
7778
func (j *Job) createJob(schedules []*calendar.Event) error {
78-
home, err := os.UserHomeDir()
79-
if err != nil {
80-
return err
79+
ok := j.checkPermission(j.config.Permission())
80+
if !ok {
81+
return errors.New("user is not allowed to create a system job: please restart resticprofile as root (with sudo)")
8182
}
82-
8383
name := getJobName(j.config.Title(), j.config.SubTitle())
8484
job := &LaunchJob{
8585
Label: name,
@@ -92,7 +92,11 @@ func (j *Job) createJob(schedules []*calendar.Event) error {
9292
StartCalendarInterval: getCalendarIntervalsFromSchedules(schedules),
9393
}
9494

95-
file, err := os.Create(path.Join(home, UserAgentPath, name+agentExtension))
95+
filename, err := getFilename(name, j.config.Permission())
96+
if err != nil {
97+
return err
98+
}
99+
file, err := os.Create(filename)
96100
if err != nil {
97101
return err
98102
}
@@ -106,7 +110,6 @@ func (j *Job) createJob(schedules []*calendar.Event) error {
106110
}
107111

108112
// load the service
109-
filename := path.Join(home, UserAgentPath, name+agentExtension)
110113
cmd := exec.Command(launchctlBin, commandLoad, filename)
111114
cmd.Stdout = os.Stdout
112115
cmd.Stderr = os.Stderr
@@ -120,14 +123,16 @@ func (j *Job) createJob(schedules []*calendar.Event) error {
120123

121124
// removeJob stops and unloads the agent from launchd, then removes the configuration file
122125
func (j *Job) removeJob() error {
123-
home, err := os.UserHomeDir()
126+
ok := j.checkPermission(j.config.Permission())
127+
if !ok {
128+
return errors.New("user is not allowed to remove a system job: please restart resticprofile as root (with sudo)")
129+
}
130+
name := getJobName(j.config.Title(), j.config.SubTitle())
131+
filename, err := getFilename(name, j.config.Permission())
124132
if err != nil {
125133
return err
126134
}
127135

128-
name := getJobName(j.config.Title(), j.config.SubTitle())
129-
filename := path.Join(home, UserAgentPath, name+agentExtension)
130-
131136
if _, err := os.Stat(filename); err == nil || os.IsExist(err) {
132137
// stop the service in case it's already running
133138
stop := exec.Command(launchctlBin, commandStop, name)
@@ -173,10 +178,34 @@ func (j *Job) displayStatus(command string) error {
173178
return err
174179
}
175180

181+
func (j *Job) checkPermission(permission string) bool {
182+
if permission == constants.SchedulePermissionUser {
183+
// user mode is always available
184+
return true
185+
}
186+
if os.Geteuid() == 0 {
187+
// user has sudoed
188+
return true
189+
}
190+
// last case is system (or undefined) + no sudo
191+
return false
192+
}
193+
176194
func getJobName(profileName, command string) string {
177195
return fmt.Sprintf("%s.%s.%s", namePrefix, strings.ToLower(profileName), command)
178196
}
179197

198+
func getFilename(name, permission string) (string, error) {
199+
if permission == constants.SchedulePermissionSystem {
200+
return path.Join(GlobalDaemons, name+agentExtension), nil
201+
}
202+
home, err := os.UserHomeDir()
203+
if err != nil {
204+
return "", err
205+
}
206+
return path.Join(home, UserAgentPath, name+agentExtension), nil
207+
}
208+
180209
// getCalendarIntervalsFromSchedules converts schedules into launchd calendar events
181210
// let's say we've setup these rules:
182211
// Mon-Fri *-*-* *:0,30:00 = every half hour

0 commit comments

Comments
 (0)