Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Systemd string escaping

Tags:

systemd

etcd

If I run this command

/bin/bash -c 'while true;do /usr/bin/etcdctl set my-container "{\"host\": \"1\", \"port\": $(/usr/bin/docker port my-container 5000 | cut -d":" -f2)}" --ttl 60;sleep 45;done'

I get back from etcd what I expect {"host":"1", "port":49155}

But if I put it in a systemd file

ExecStart=/bin/bash -c 'while true;do /usr/bin/etcdctl set my-container "{\"host\": \"1\", \"port\": $(/usr/bin/docker port my-container 5000 | cut -d":" -f2)}" --ttl 60;sleep 45;done'

I get back {host:1, port:49155}

Any idea of why the escaping is different inside of the file? How can I fix it? Thanks!!

like image 425
MParker Avatar asked May 29 '14 14:05

MParker


3 Answers

In short -- it's different because systemd does its own string-splitting, unescaping and expansion, and the logic it uses isn't POSIX-compliant.

You can still do what you want, but you'll need more backslashes:

ExecStart=/bin/bash -c '\
  while :; do \
    port=$(/usr/bin/docker port my-container 5000 | cut -d: -f2); \
    /usr/bin/etcdctl set my-container "{\\\"host\\\": \\\"1\\\", \\\"port\\\": $port}" --ttl 60; \
    sleep 45; \
  done'

Note the use of \\\" for every literal " character in the desired output.


By the way -- personally, I advise against trying to generate JSON through string concatenation -- it's prone to injection vulnerabilities (if someone could put content of their choice in the output of the docker port command, they could potentially insert other key/value pairs into your data by having , "evil": true be in the port variable). This class of issues is avoided by using jq:

ExecStart=/bin/bash -c '\
  while :; do \
    port=$(/usr/bin/docker port my-container 5000 | cut -d: -f2); \
    json=$(jq -nc \
      --arg host 1 \
      --arg port "$port" \
      '{} | .host=$host | .port=($port | tonumber)'); \
    /usr/bin/etcdctl set my-container "$json" --ttl 60; \
    sleep 45; \
  done'

As a happy side effect, the above avoids needing any literal double-quote characters (the only ones used are syntactic to the copy of sh), so we don't need any backslashes to be passed through from systemd to the shell.

like image 187
Charles Duffy Avatar answered Oct 31 '22 14:10

Charles Duffy


systemd-escape '\"a fun thing"\' 

output: \x5c\x22a\x20fun\x20thing\x22\x5c

[Service]
ExecStart=/bin/sh -c 'echo "\x5c\x22a\x20fun\x20thing\x22\x5c"'

will print a fun thing

like image 29
user6588075 Avatar answered Oct 31 '22 12:10

user6588075


Systemd is doing isn't like bash as you now know, hence the escaping problem. In fact, systemd removes single and double quotes after parsing them. That fact is right out of the documentation (I went thru this too, then read :D).

The solution, call a script that echo back that info you need (with escaped quotes) if your purpose allows that.

like image 35
MiiinimalLogic Avatar answered Oct 31 '22 12:10

MiiinimalLogic