[Libguestfs] [PATCH libnbd 2/2] api: Implement local command with systemd socket activation.
Eric Blake
eblake at redhat.com
Fri Sep 27 13:16:01 UTC 2019
On 9/27/19 7:28 AM, Richard W.M. Jones wrote:
>>> + /* We must unset CLOEXEC on the fd. (dup2 above does this
>>> + * implicitly because CLOEXEC is set on the fd, not on the
>>> + * socket).
>>> + */
>>> + flags = fcntl (s, F_GETFD, 0);
>>> + if (flags == -1) {
>>> + perror ("fcntl: F_GETFD");
>>
>> perror is not async-signal-safe. Calling it in a child of a
>> potentially-multi-threaded parent is therefore prone to deadlock, if
>> perror() triggers a request to grab any resource that was left
>> locked by a different thread holding the lock but stranded by the
>> fork.
>
> I suspect these sort of problems are unsolvable. I've studied enough
> customer bug reports where we've had to reverse engineer exactly how
> something failed given only a slim error log to know that error
> messages are always useful and I wouldn't want to remove these.
> However because of the chance of deadlock, how about a deadlock-free
> function that write(2)'s the message + errno to stderr?
Yes, sticking to write() is better than nothing. Open-coding an
int-to-string for displying errno is doable, or bypassing strerror() and
going straight for the non-portable sys_errlist[errno] lookup (if
configure says sys_errlist is available) can also be used - it's a
question of how nice do you want to make things, while still trying to
remain safe.
>>> +
>>> + snprintf (listen_pid, sizeof listen_pid, "%ld", (long) getpid ());
>>> + setenv ("LISTEN_PID", listen_pid, 1);
>>> + setenv ("LISTEN_FDS", "1", 1);
>
> And we could use similar code here.
Yeah, if we're going to open-code a signal-safe int-to-string, we have
several uses for it :)
>
>> snprintf() and setenv() are also not async-signal-safe. Which is a
>> bummer, since you really don't know the child pid until in the
>> child. You could open-code the translation of a decimal number into
>> a buffer without snprintf, but you also have to figure out how to
>> safely put it into the environ seen by the child. How does systemd
>> do it?
>
> For setenv(), systemd does this by building a char **environ which is
> passed to execve. The code is complicated to say the least:
>
> https://github.com/systemd/systemd/blob/5ac1530eca652cd16819853fe06e76e156f5cf5e/src/core/dbus-execute.c
Can we pre-build the bulk of the replacement environ in the parent,
leaving just the one entry to munge in the child? At least that way we
can malloc without worries.
>
>>> + _exit (EXIT_FAILURE);
>>
>> Is EXIT_FAILURE the best here, or should we consider exiting with
>> status 126/127 to match what other programs (sh, env, nice, nohup,
>> ...) do when execvp() fails?
>
> Yes (this is also a bug elsewhere). Not sure if 126 or 127 is
> right:
>
> https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
Depends on the value of errno after the fact. ENOENT => 127, all others
126.
>
> ...
>> Do we document that nbd_close() may block?
>
> We should do. I've added it in a separate patch.
>
> I'll have a rethink about this patch and come back with something
> better in a while.
>
> Rich.
>
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
More information about the Libguestfs
mailing list