diff --git a/pkg/systemd/parser/unitfile.go b/pkg/systemd/parser/unitfile.go index ac04f8effe..099145f592 100644 --- a/pkg/systemd/parser/unitfile.go +++ b/pkg/systemd/parser/unitfile.go @@ -827,15 +827,16 @@ func (f *UnitFile) LookupAllArgs(groupName string, key string) []string { // array of words. The split code is exec-like, and both unquotes and // applied c-style c escapes. This is typically used for keys like // ExecStart -func (f *UnitFile) LookupLastArgs(groupName string, key string) ([]string, bool) { +func (f *UnitFile) LookupLastArgs(groupName string, key string) ([]string, bool, error) { execKey, ok := f.LookupLast(groupName, key) - if ok { - execArgs, err := splitString(execKey, WhitespaceSeparators, SplitRelax|SplitUnquote|SplitCUnescape) - if err == nil { - return execArgs, true - } + if !ok { + return nil, false, nil } - return nil, false + execArgs, err := splitString(execKey, WhitespaceSeparators, SplitRelax|SplitUnquote|SplitCUnescape) + if err != nil { + return nil, false, err + } + return execArgs, true, nil } // Look up 'Environment' style key-value keys diff --git a/pkg/systemd/quadlet/quadlet.go b/pkg/systemd/quadlet/quadlet.go index 6d53d12168..de9590b383 100644 --- a/pkg/systemd/quadlet/quadlet.go +++ b/pkg/systemd/quadlet/quadlet.go @@ -621,7 +621,9 @@ func ConvertContainer(container *parser.UnitFile, isUser bool, unitsInfoMap map[ serviceStopCmd.Args[0] = fmt.Sprintf("-%s", serviceStopCmd.Args[0]) service.AddCmdline(ServiceGroup, "ExecStopPost", serviceStopCmd.Args) - if err := handleExecReload(container, service, ContainerGroup, containerName); err != nil { + warn, err = handleExecReload(container, service, ContainerGroup, containerName) + warnings = errors.Join(warnings, warn) + if err != nil { return nil, warnings, err } @@ -888,10 +890,11 @@ func ConvertContainer(container *parser.UnitFile, isUser bool, unitsInfoMap map[ podman.add("--rootfs", rootfs) } - execArgs, ok := container.LookupLastArgs(ContainerGroup, KeyExec) + execArgs, ok, warn := container.LookupLastArgs(ContainerGroup, KeyExec) if ok { podman.add(execArgs...) } + warnings = errors.Join(warnings, warn) service.AddCmdline(ServiceGroup, "ExecStart", podman.Args) @@ -2169,18 +2172,22 @@ func addDefaultDependencies(service *parser.UnitFile, isUser bool) { } } -func handleExecReload(quadletUnitFile, serviceUnitFile *parser.UnitFile, groupName, containerName string) error { +// handleExecReload handles the ExecReload key. +// If return (warning, error) +// An error is returned if both KeyReloadCmd and KeyReloadSignal are set, +// and a warning is returned if it failed to parse the ReloadCmd key. +func handleExecReload(quadletUnitFile, serviceUnitFile *parser.UnitFile, groupName, containerName string) (error, error) { reloadSignal, signalOk := quadletUnitFile.Lookup(groupName, KeyReloadSignal) signalOk = signalOk && len(reloadSignal) > 0 - reloadcmd, cmdOk := quadletUnitFile.LookupLastArgs(groupName, KeyReloadCmd) + reloadcmd, cmdOk, warn := quadletUnitFile.LookupLastArgs(groupName, KeyReloadCmd) cmdOk = cmdOk && len(reloadcmd) > 0 if !cmdOk && !signalOk { - return nil + return warn, nil } if cmdOk && signalOk { - return fmt.Errorf("%s and %s are mutually exclusive but both are set", KeyReloadCmd, KeyReloadSignal) + return warn, fmt.Errorf("%s and %s are mutually exclusive but both are set", KeyReloadCmd, KeyReloadSignal) } serviceReloadCmd := createBasePodmanCommand(quadletUnitFile, groupName) @@ -2192,7 +2199,7 @@ func handleExecReload(quadletUnitFile, serviceUnitFile *parser.UnitFile, groupNa } serviceUnitFile.AddCmdline(ServiceGroup, "ExecReload", serviceReloadCmd.Args) - return nil + return warn, nil } func translateUnitDependencies(serviceUnitFile *parser.UnitFile, unitsInfoMap map[string]*UnitInfo) error { diff --git a/test/e2e/quadlet/exec-unsupported-escape.container b/test/e2e/quadlet/exec-unsupported-escape.container new file mode 100644 index 0000000000..78513cfe7a --- /dev/null +++ b/test/e2e/quadlet/exec-unsupported-escape.container @@ -0,0 +1,5 @@ +## assert-podman-final-args localhost/imagename + +[Container] +Image=localhost/imagename +Exec='test\.com' diff --git a/test/e2e/quadlet/reloadcmd-unsupported-escape.container b/test/e2e/quadlet/reloadcmd-unsupported-escape.container new file mode 100644 index 0000000000..a7a447c565 --- /dev/null +++ b/test/e2e/quadlet/reloadcmd-unsupported-escape.container @@ -0,0 +1,5 @@ +## assert-podman-final-args localhost/imagename + +[Container] +Image=localhost/imagename +ReloadCmd='test\.sh' diff --git a/test/e2e/quadlet_test.go b/test/e2e/quadlet_test.go index e35abb5609..23224eff84 100644 --- a/test/e2e/quadlet_test.go +++ b/test/e2e/quadlet_test.go @@ -232,7 +232,7 @@ func (t *quadletTestcase) assertKeyNotContains(args []string, unit *parser.UnitF } func (t *quadletTestcase) assertPodmanArgs(args []string, unit *parser.UnitFile, key string, allowRegex, globalOnly bool) bool { - podmanArgs, _ := unit.LookupLastArgs("Service", key) + podmanArgs, _, _ := unit.LookupLastArgs("Service", key) if globalOnly { podmanCmdLocation := findSublist(podmanArgs, []string{args[0]}) if podmanCmdLocation == -1 { @@ -287,7 +287,7 @@ func keyValMapEqualRegex(expectedKeyValMap, actualKeyValMap map[string]string) b } func (t *quadletTestcase) assertPodmanArgsKeyVal(args []string, unit *parser.UnitFile, key string, allowRegex, globalOnly bool) bool { - podmanArgs, _ := unit.LookupLastArgs("Service", key) + podmanArgs, _, _ := unit.LookupLastArgs("Service", key) if globalOnly { podmanCmdLocation := findSublist(podmanArgs, []string{args[0]}) @@ -334,7 +334,7 @@ func (t *quadletTestcase) assertPodmanArgsKeyVal(args []string, unit *parser.Uni } func (t *quadletTestcase) assertPodmanFinalArgs(args []string, unit *parser.UnitFile, key string) bool { - podmanArgs, _ := unit.LookupLastArgs("Service", key) + podmanArgs, _, _ := unit.LookupLastArgs("Service", key) if len(podmanArgs) < len(args) { return false } @@ -342,7 +342,7 @@ func (t *quadletTestcase) assertPodmanFinalArgs(args []string, unit *parser.Unit } func (t *quadletTestcase) assertPodmanFinalArgsRegex(args []string, unit *parser.UnitFile, key string) bool { - podmanArgs, _ := unit.LookupLastArgs("Service", key) + podmanArgs, _, _ := unit.LookupLastArgs("Service", key) if len(podmanArgs) < len(args) { return false } @@ -1106,6 +1106,9 @@ BOGUS=foo Entry("Unsupported Service Key - DynamicUser.network", "service-dynamicuser.network", "Warning: using key DynamicUser in the Service group is not supported"), Entry("Unsupported Service Key - DynamicUser.pod", "service-dynamicuser.pod", "Warning: using key DynamicUser in the Service group is not supported"), Entry("Unsupported Service Key - DynamicUser.volume", "service-dynamicuser.volume", "Warning: using key DynamicUser in the Service group is not supported"), + + Entry("exec-unsupported-escape.container", "exec-unsupported-escape.container", "unsupported escape char"), + Entry("reloadcmd-unsupported-escape.container", "reloadcmd-unsupported-escape.container", "unsupported escape char"), ) DescribeTable("Running expected error quadlet test case",