mirror of
https://github.com/containers/podman.git
synced 2025-06-29 15:08:09 +08:00
Merge pull request #9178 from Luap99/fix-9176
Fix podman generate systemd --new special char handling
This commit is contained in:
@ -60,13 +60,21 @@ func filterPodFlags(command []string) []string {
|
|||||||
return processed
|
return processed
|
||||||
}
|
}
|
||||||
|
|
||||||
// quoteArguments makes sure that all arguments with at least one whitespace
|
// escapeSystemdArguments makes sure that all arguments with at least one whitespace
|
||||||
// are quoted to make sure those are interpreted as one argument instead of
|
// are quoted to make sure those are interpreted as one argument instead of
|
||||||
// multiple ones.
|
// multiple ones. Also make sure to escape all characters which have a special
|
||||||
func quoteArguments(command []string) []string {
|
// meaning to systemd -> $,% and \
|
||||||
|
// see: https://www.freedesktop.org/software/systemd/man/systemd.service.html#Command%20lines
|
||||||
|
func escapeSystemdArguments(command []string) []string {
|
||||||
for i := range command {
|
for i := range command {
|
||||||
|
command[i] = strings.ReplaceAll(command[i], "$", "$$")
|
||||||
|
command[i] = strings.ReplaceAll(command[i], "%", "%%")
|
||||||
if strings.ContainsAny(command[i], " \t") {
|
if strings.ContainsAny(command[i], " \t") {
|
||||||
command[i] = strconv.Quote(command[i])
|
command[i] = strconv.Quote(command[i])
|
||||||
|
} else if strings.Contains(command[i], `\`) {
|
||||||
|
// strconv.Quote also escapes backslashes so
|
||||||
|
// we should replace only if strconv.Quote was not used
|
||||||
|
command[i] = strings.ReplaceAll(command[i], `\`, `\\`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return command
|
return command
|
||||||
|
@ -29,7 +29,7 @@ func TestFilterPodFlags(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQuoteArguments(t *testing.T) {
|
func TestEscapeSystemdArguments(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
input []string
|
input []string
|
||||||
output []string
|
output []string
|
||||||
@ -46,10 +46,46 @@ func TestQuoteArguments(t *testing.T) {
|
|||||||
[]string{"foo", "bar=\"arg with\ttab\""},
|
[]string{"foo", "bar=\"arg with\ttab\""},
|
||||||
[]string{"foo", "\"bar=\\\"arg with\\ttab\\\"\""},
|
[]string{"foo", "\"bar=\\\"arg with\\ttab\\\"\""},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
[]string{"$"},
|
||||||
|
[]string{"$$"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]string{"foo", "command with dollar sign $"},
|
||||||
|
[]string{"foo", "\"command with dollar sign $$\""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]string{"foo", "command with two dollar signs $$"},
|
||||||
|
[]string{"foo", "\"command with two dollar signs $$$$\""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]string{"%"},
|
||||||
|
[]string{"%%"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]string{"foo", "command with percent sign %"},
|
||||||
|
[]string{"foo", "\"command with percent sign %%\""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]string{"foo", "command with two percent signs %%"},
|
||||||
|
[]string{"foo", "\"command with two percent signs %%%%\""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]string{`\`},
|
||||||
|
[]string{`\\`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]string{"foo", `command with backslash \`},
|
||||||
|
[]string{"foo", `"command with backslash \\"`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]string{"foo", `command with two backslashs \\`},
|
||||||
|
[]string{"foo", `"command with two backslashs \\\\"`},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
quoted := quoteArguments(test.input)
|
quoted := escapeSystemdArguments(test.input)
|
||||||
assert.Equal(t, test.output, quoted)
|
assert.Equal(t, test.output, quoted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,7 +204,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
|
|||||||
startCommand := []string{info.Executable}
|
startCommand := []string{info.Executable}
|
||||||
if index > 2 {
|
if index > 2 {
|
||||||
// include root flags
|
// include root flags
|
||||||
info.RootFlags = strings.Join(quoteArguments(info.CreateCommand[1:index-1]), " ")
|
info.RootFlags = strings.Join(escapeSystemdArguments(info.CreateCommand[1:index-1]), " ")
|
||||||
startCommand = append(startCommand, info.CreateCommand[1:index-1]...)
|
startCommand = append(startCommand, info.CreateCommand[1:index-1]...)
|
||||||
}
|
}
|
||||||
startCommand = append(startCommand,
|
startCommand = append(startCommand,
|
||||||
@ -279,7 +279,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
startCommand = append(startCommand, remainingCmd...)
|
startCommand = append(startCommand, remainingCmd...)
|
||||||
startCommand = quoteArguments(startCommand)
|
startCommand = escapeSystemdArguments(startCommand)
|
||||||
|
|
||||||
info.ExecStartPre = "/bin/rm -f {{{{.PIDFile}}}} {{{{.ContainerIDFile}}}}"
|
info.ExecStartPre = "/bin/rm -f {{{{.PIDFile}}}} {{{{.ContainerIDFile}}}}"
|
||||||
info.ExecStart = strings.Join(startCommand, " ")
|
info.ExecStart = strings.Join(startCommand, " ")
|
||||||
|
@ -349,6 +349,30 @@ ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
|
|||||||
PIDFile=%t/jadda-jadda.pid
|
PIDFile=%t/jadda-jadda.pid
|
||||||
Type=forking
|
Type=forking
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target default.target
|
||||||
|
`
|
||||||
|
|
||||||
|
goodNewWithSpecialChars := `# jadda-jadda.service
|
||||||
|
# autogenerated by Podman CI
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Podman jadda-jadda.service
|
||||||
|
Documentation=man:podman-generate-systemd(1)
|
||||||
|
Wants=network.target
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=PODMAN_SYSTEMD_UNIT=%n
|
||||||
|
Restart=always
|
||||||
|
TimeoutStopSec=70
|
||||||
|
ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
|
||||||
|
ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d --replace --name test awesome-image:latest sh -c "kill $$$$ && echo %%\\"
|
||||||
|
ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
|
||||||
|
ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
|
||||||
|
PIDFile=%t/jadda-jadda.pid
|
||||||
|
Type=forking
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target default.target
|
WantedBy=multi-user.target default.target
|
||||||
`
|
`
|
||||||
@ -647,6 +671,22 @@ WantedBy=multi-user.target default.target
|
|||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
{"good with special chars",
|
||||||
|
containerInfo{
|
||||||
|
Executable: "/usr/bin/podman",
|
||||||
|
ServiceName: "jadda-jadda",
|
||||||
|
ContainerNameOrID: "jadda-jadda",
|
||||||
|
RestartPolicy: "always",
|
||||||
|
PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
|
||||||
|
StopTimeout: 10,
|
||||||
|
PodmanVersion: "CI",
|
||||||
|
CreateCommand: []string{"I'll get stripped", "create", "--name", "test", "awesome-image:latest", "sh", "-c", "kill $$ && echo %\\"},
|
||||||
|
EnvVariable: EnvVariable,
|
||||||
|
},
|
||||||
|
goodNewWithSpecialChars,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
test := tt
|
test := tt
|
||||||
|
@ -269,7 +269,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
|
|||||||
return "", errors.Errorf("pod does not appear to be created via `podman pod create`: %v", info.CreateCommand)
|
return "", errors.Errorf("pod does not appear to be created via `podman pod create`: %v", info.CreateCommand)
|
||||||
}
|
}
|
||||||
podRootArgs = info.CreateCommand[1 : podCreateIndex-1]
|
podRootArgs = info.CreateCommand[1 : podCreateIndex-1]
|
||||||
info.RootFlags = strings.Join(quoteArguments(podRootArgs), " ")
|
info.RootFlags = strings.Join(escapeSystemdArguments(podRootArgs), " ")
|
||||||
podCreateArgs = filterPodFlags(info.CreateCommand[podCreateIndex+1:])
|
podCreateArgs = filterPodFlags(info.CreateCommand[podCreateIndex+1:])
|
||||||
}
|
}
|
||||||
// We're hard-coding the first five arguments and append the
|
// We're hard-coding the first five arguments and append the
|
||||||
@ -306,7 +306,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
|
|||||||
}
|
}
|
||||||
|
|
||||||
startCommand = append(startCommand, podCreateArgs...)
|
startCommand = append(startCommand, podCreateArgs...)
|
||||||
startCommand = quoteArguments(startCommand)
|
startCommand = escapeSystemdArguments(startCommand)
|
||||||
|
|
||||||
info.ExecStartPre1 = "/bin/rm -f {{{{.PIDFile}}}} {{{{.PodIDFile}}}}"
|
info.ExecStartPre1 = "/bin/rm -f {{{{.PIDFile}}}} {{{{.PodIDFile}}}}"
|
||||||
info.ExecStartPre2 = strings.Join(startCommand, " ")
|
info.ExecStartPre2 = strings.Join(startCommand, " ")
|
||||||
|
Reference in New Issue
Block a user