github.com/AbhinandanKurakure/podman/v3@v3.4.10/pkg/systemd/generate/common.go (about) 1 package generate 2 3 import ( 4 "strconv" 5 "strings" 6 7 "github.com/containers/podman/v3/pkg/systemd/define" 8 "github.com/pkg/errors" 9 ) 10 11 // minTimeoutStopSec is the minimal stop timeout for generated systemd units. 12 // Once exceeded, processes of the services are killed and the cgroup(s) are 13 // cleaned up. 14 const minTimeoutStopSec = 60 15 16 // validateRestartPolicy checks that the user-provided policy is valid. 17 func validateRestartPolicy(restart string) error { 18 for _, i := range define.RestartPolicies { 19 if i == restart { 20 return nil 21 } 22 } 23 return errors.Errorf("%s is not a valid restart policy", restart) 24 } 25 26 const headerTemplate = `# {{{{.ServiceName}}}}.service 27 {{{{- if (eq .GenerateNoHeader false) }}}} 28 # autogenerated by Podman {{{{.PodmanVersion}}}} 29 {{{{- if .TimeStamp}}}} 30 # {{{{.TimeStamp}}}} 31 {{{{- end}}}} 32 {{{{- end}}}} 33 34 [Unit] 35 Description=Podman {{{{.ServiceName}}}}.service 36 Documentation=man:podman-generate-systemd(1) 37 Wants=network-online.target 38 After=network-online.target 39 RequiresMountsFor={{{{.RunRoot}}}} 40 ` 41 42 // filterPodFlags removes --pod, --pod-id-file and --infra-conmon-pidfile from the specified command. 43 // argCount is the number of last arguments which should not be filtered, e.g. the container entrypoint. 44 func filterPodFlags(command []string, argCount int) []string { 45 processed := []string{} 46 for i := 0; i < len(command)-argCount; i++ { 47 s := command[i] 48 if s == "--pod" || s == "--pod-id-file" || s == "--infra-conmon-pidfile" { 49 i++ 50 continue 51 } 52 if strings.HasPrefix(s, "--pod=") || 53 strings.HasPrefix(s, "--pod-id-file=") || 54 strings.HasPrefix(s, "--infra-conmon-pidfile=") { 55 continue 56 } 57 processed = append(processed, s) 58 } 59 processed = append(processed, command[len(command)-argCount:]...) 60 return processed 61 } 62 63 // filterCommonContainerFlags removes --sdnotify, --rm and --cgroups from the specified command. 64 // argCount is the number of last arguments which should not be filtered, e.g. the container entrypoint. 65 func filterCommonContainerFlags(command []string, argCount int) []string { 66 processed := []string{} 67 for i := 0; i < len(command)-argCount; i++ { 68 s := command[i] 69 70 switch { 71 case s == "--rm": 72 // Boolean flags support --flag and --flag={true,false}. 73 continue 74 case s == "--sdnotify", s == "--cgroups", s == "--cidfile", s == "--restart": 75 i++ 76 continue 77 case strings.HasPrefix(s, "--rm="), 78 strings.HasPrefix(s, "--cgroups="), 79 strings.HasPrefix(s, "--cidfile="), 80 strings.HasPrefix(s, "--restart="): 81 continue 82 } 83 processed = append(processed, s) 84 } 85 processed = append(processed, command[len(command)-argCount:]...) 86 return processed 87 } 88 89 // escapeSystemdArguments makes sure that all arguments with at least one whitespace 90 // are quoted to make sure those are interpreted as one argument instead of 91 // multiple ones. Also make sure to escape all characters which have a special 92 // meaning to systemd -> $,% and \ 93 // see: https://www.freedesktop.org/software/systemd/man/systemd.service.html#Command%20lines 94 func escapeSystemdArguments(command []string) []string { 95 for i := range command { 96 command[i] = escapeSystemdArg(command[i]) 97 } 98 return command 99 } 100 101 func escapeSystemdArg(arg string) string { 102 arg = strings.ReplaceAll(arg, "$", "$$") 103 arg = strings.ReplaceAll(arg, "%", "%%") 104 if strings.ContainsAny(arg, " \t") { 105 arg = strconv.Quote(arg) 106 } else if strings.Contains(arg, `\`) { 107 // strconv.Quote also escapes backslashes so 108 // we should replace only if strconv.Quote was not used 109 arg = strings.ReplaceAll(arg, `\`, `\\`) 110 } 111 return arg 112 } 113 114 func removeDetachArg(args []string, argCount int) []string { 115 // "--detach=false" could also be in the container entrypoint 116 // split them off so we do not remove it there 117 realArgs := args[len(args)-argCount:] 118 flagArgs := removeArg("-d=false", args[:len(args)-argCount]) 119 flagArgs = removeArg("--detach=false", flagArgs) 120 return append(flagArgs, realArgs...) 121 } 122 123 func removeReplaceArg(args []string, argCount int) []string { 124 // "--replace=false" could also be in the container entrypoint 125 // split them off so we do not remove it there 126 realArgs := args[len(args)-argCount:] 127 flagArgs := removeArg("--replace=false", args[:len(args)-argCount]) 128 return append(flagArgs, realArgs...) 129 } 130 131 func removeArg(arg string, args []string) []string { 132 newArgs := []string{} 133 for _, a := range args { 134 if a != arg { 135 newArgs = append(newArgs, a) 136 } 137 } 138 return newArgs 139 }