utils/service: add systemd_quote helper

We need a way to escape systemd command lines properly as systemd treats
unrecognised escape sequences as separate literal characters. This helper
function does that.
This commit is contained in:
Ruoyu Zhong 2024-12-04 02:45:09 +08:00
parent b854d17426
commit 15146b2b67
No known key found for this signature in database
2 changed files with 59 additions and 0 deletions

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
require "utils/service"
RSpec.describe Utils::Service do
describe "::systemd_quote" do
it "quotes empty strings correctly" do
expect(described_class.systemd_quote("")).to eq '""'
end
it "quotes strings with special characters escaped correctly" do
expect(described_class.systemd_quote("\a\b\f\n\r\t\v\\"))
.to eq '"\\a\\b\\f\\n\\r\\t\\v\\\\"'
expect(described_class.systemd_quote("\"' ")).to eq "\"\\\"' \""
end
it "does not escape characters that do not need escaping" do
expect(described_class.systemd_quote("daemon off;")).to eq '"daemon off;"'
expect(described_class.systemd_quote("--timeout=3")).to eq '"--timeout=3"'
expect(described_class.systemd_quote("--answer=foo bar"))
.to eq '"--answer=foo bar"'
end
end
end

View File

@ -48,5 +48,40 @@ module Utils
def self.systemctl?
!systemctl.nil?
end
# Quote a string for use in systemd command lines, e.g., in `ExecStart`.
# https://www.freedesktop.org/software/systemd/man/latest/systemd.syntax.html#Quoting
sig { params(str: String).returns(String) }
def self.systemd_quote(str)
result = +"\""
# No need to escape single quotes and spaces, as we're always double
# quoting the entire string.
str.each_char do |char|
result << case char
when "\a"
"\\a"
when "\b"
"\\b"
when "\f"
"\\f"
when "\n"
"\\n"
when "\r"
"\\r"
when "\t"
"\\t"
when "\v"
"\\v"
when "\\"
"\\\\"
when "\""
"\\\""
else
char
end
end
result << "\""
result.freeze
end
end
end