func genServiceFile(appInfo *snap.AppInfo) string { serviceTemplate := `[Unit] # Auto-generated, DO NO EDIT Description=Service for snap application {{.App.Snap.Name}}.{{.App.Name}} After=snapd.frameworks.target{{ if .App.Socket }} {{.SocketFileName}}{{end}} Requires=snapd.frameworks.target{{ if .App.Socket }} {{.SocketFileName}}{{end}} X-Snappy=yes [Service] ExecStart={{.App.LauncherCommand}} Restart={{.Restart}} WorkingDirectory={{.App.Snap.DataDir}} {{if .App.StopCommand}}ExecStop={{.App.LauncherStopCommand}}{{end}} {{if .App.PostStopCommand}}ExecStopPost={{.App.LauncherPostStopCommand}}{{end}} {{if .StopTimeout}}TimeoutStopSec={{.StopTimeout.Seconds}}{{end}} Type={{.App.Daemon}} {{if .App.BusName}}BusName={{.App.BusName}}{{end}} [Install] WantedBy={{.ServiceTargetUnit}} ` var templateOut bytes.Buffer t := template.Must(template.New("wrapper").Parse(serviceTemplate)) var restartCond string if appInfo.RestartCond == systemd.RestartNever { restartCond = "no" } else { restartCond = appInfo.RestartCond.String() } if restartCond == "" { restartCond = systemd.RestartOnFailure.String() } socketFileName := "" if appInfo.Socket { socketFileName = filepath.Base(appInfo.ServiceSocketFile()) } wrapperData := struct { App *snap.AppInfo SocketFileName string Restart string StopTimeout time.Duration ServiceTargetUnit string Home string EnvVars string }{ App: appInfo, SocketFileName: socketFileName, Restart: restartCond, StopTimeout: serviceStopTimeout(appInfo), ServiceTargetUnit: systemd.ServicesTarget, // systemd runs as PID 1 so %h will not work. Home: "/root", } if err := t.Execute(&templateOut, wrapperData); err != nil { // this can never happen, except we forget a variable logger.Panicf("Unable to execute template: %v", err) } return templateOut.String() }