Understanding piping to a unix domain socket in the background
3
votes
0
answers
159
views
I have a Debian 12 (bookworm) host where I run three VMs using QEMU / KVM. To simplify VM management, each VM has a QEMU monitor socket. These sockets are
/vm/1.sock
, /vm/2.sock
and /vm/3.sock
. Among others, I can use such a socket to gracefully shutdown the respective VM; the command would be something like that:
printf "%s\n" 'system_powerdown' | socat - unix-connect:/vm/1.sock
So far, so good. This works as expected for each of the three VMs / sockets.
Now I have a script that needs to shut down all of these VMs, where no delay must occur if one of the shutdown commands hangs or takes a long time. That means that I have to execute the command line shown above in the background.
The respective part in the original version of that script is:
{ printf "%s\n" 'system_powerdown' | socat - unix-connect:/vm/1.sock; } &
{ printf "%s\n" 'system_powerdown' | socat - unix-connect:/vm/2.sock; } &
{ printf "%s\n" 'system_powerdown' | socat - unix-connect:/vm/3.sock; } &
Apart from the fact that this produces weird output (because the commands are executed asynchronously and their outputs are interleaved), it does not work as intended. **It shuts down one of the VMs, but not the other two.** During my tests, it was always VM #2 that got shut down, but I believe that this is pure random.
[ Side note: VM #2 takes only 3 seconds or so to actually shut down, while VM #1 and VM #3 take 10 seconds or so; this *may* be the reason why it's always VM #2 that gets shut down. But let's put that aside for the moment; I wouldn't be able to explain it anyway and still believe that it's random that it's only VM #2 that gets shut down. ]
Then I changed the passage shown above in the following way:
( printf "%s\n" 'system_powerdown' | socat - unix-connect:/vm/1.sock ) &
( printf "%s\n" 'system_powerdown' | socat - unix-connect:/vm/2.sock ) &
( printf "%s\n" 'system_powerdown' | socat - unix-connect:/vm/3.sock ) &
Of course, this version also produces weird output, **but otherwise works; it reliably shuts down all of the three VMs.**
While I am glad to have a working solution, I would like to understand the matter. After having re-visited the relevant parts of the bash manual, I believe that both versions should shut down all VMs, but this is not the case. Why does the second version work, while the first version doesn't?
Of course, I have read some similar questions on this site and elsewhere that deal with executing commands or pipes in background. From this research I got the impression that both variants should work. Some answers also proposed to move the &
into the braces, like that:
(printf "%s\n" 'system_powerdown' | socat - unix-connect:/vm/1.sock &)
But I haven't tried that yet because I first would like to understand the difference between the first and the second version shown above.
Asked by Binarus
(3901 rep)
Oct 17, 2024, 06:24 PM