Adam Borowski <kilobyte@???> writes:
> How do you guys like this:?
> http://git.busybox.net/busybox/commit/?id=accd9eeb719916da974584b33b1aeced5f3bb346
I think that's a silly reason for removing a feature. But I found
something nicer while doing a (minimal) bit of research on sd_listen:
,----
| union {
| struct sockaddr sa;
| struct sockaddr_un un;
| } sa;
|
| [...]
|
| memset(&sa, 0, sizeof(sa));
| sa.un.sun_family = AF_UNIX;
| strncpy(sa.un.sun_path, "/run/foobar.sk", sizeof(sa.un.sun_path));
| if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
`----
That's from an example for extolling the virtues of 'systemd socket
activation' to 'lesser minions' expected to perform minor acts of
sabotage in support of the good cause (like implementing such features
in order to 'enable' services to cease functioning without systemd).
One would usually initialize an AF_UNIX address like this:
struct sockaddr_un sun;
sun.sun_family = AF_UNIX;
strncpy(sun.sun_path, "/run/foorbar.sk", sizeof(sun.sun_path));
The sun_path member is a char array of size UNIX_PATH_MAX (108). The
strncpy will end up zero-filling this array beyond the copied
string. The address would then be used like this
bind(sk, (struct sockaddr *)&sun, sizeof(sun));
Using a union in this way is 'unspecified behaviour' as of ISO C. It's
also strangely schizophrenic as there's no point in zero-filling the
entire structure prior to initializing its members one by one which
implies zero-filling the larger part of the second one[*] again. It's
also theoretically broken: The code is only correct if the length of the
name argument is known to be less than the size of the buffer as strncpy
won't insert a zero-byte otherwise, ie, on one hand, this use a
size-checking function with fairly byzantine semantics, on the other
hand, the code relies on 'knowing' that "/run/foobar.sk" will fit into
the buffer while leaving space for a trailing zero. In case the length
of the name is unknown, one would usually do something like
strncpy(sun.sun_path, name, sizeof(sun.sun_path));
sun.sun_path[sizeof(sun.sun_path) - 1] = 0;
to handle both case ('long name' and 'short name' correctly), the above
is really just a more expensive (and possibly confusing) variant of
memset(&sun, 0, sizeof(&sun.sun_path));
strcpy(sun.sun_path, "/run/foobar.sk");
NB: Code examples neither compiled nor tested.
[*] Coded homage to James Bond because of the 00 perhaps?