Recently, the inclusion of libsystemd as a dependency of distribution vendored copies of OpenSSH server caused a bit of a scare. Not necessarily because of libsystemd. That being said, maybe NIH isn't that bad in some situations, maybe we shouldn't be so eager to add a dependency when a short bit of code is sufficient. So I wrote a short bit of code.
// SPDX-License-Identifier: CC0-1.0 #include <errno.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> int notify_socket_send(const char *message) { const char *path = getenv("NOTIFY_SOCKET"); if (path == NULL || path[0] == '\0') return 0; struct sockaddr_un sa = {.sun_family = AF_UNIX}; size_t len = strnlen(path, sizeof sa.sun_path); if (len >= sizeof sa.sun_path) return ENAMETOOLONG; memcpy(sa.sun_path, path, len); if (sa.sun_path[0] == '@') sa.sun_path[0] = '\0'; size_t addrlen = sa.sun_path[0] == '\0' ? sizeof sa.sun_family + len : sizeof sa; int fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (fd == -1) return errno; ssize_t ret = sendto(fd, message, strlen(message), 0, (void *)&sa, addrlen); int errno_save = errno; close(fd); return ret == -1 ? errno_save : 0; }
Please do let me know about all the bugs you find. I'm sure there's at least one.
Updates on 2024-04-01: There were bugs and I have now gotten around to compiling the code. This version latest also incorporates some suggestions from Leah Neukirchen and Rich Felker (dalias). The changes are as follows:
- The function has a new name so as to not imply that the notification protocol needs to be systemd specific.
- The code now specifically handles an empty but set environment variable (currently the same way as an unset one).
- Dalias suggested using
strnlento avoid checking too far into the string. This is a bit of a micro-optimisation but I felt like it was fair to incorporate anyway, the reasoning is sound. - Dalias also suggested just using
errnonumbers, since the code already depends on posix for unix sockets so I can depend on POSIX for theirerrnonumbers. I am not sure I 100% like the way I ended up interpreting this advice, as some error numbers from socket overlap with those from sendto. But the overlaps shouldn't be too confusing. Instead of the_strerrorfunction, use the normalstrerrorfunction on the return value to get insight into the error.
If you happen to like negative returns for errors, feel free to add some minus signs. - Leah checked the old code to make sure it didn't have any obvious errors, and confirmed it didn't, but then I changed the code anyway so it's possible I've introduced new bugs.
- I've further considered whether it makes sense to check the positive return value of
sendto, and I believe that (and I don't seem to be alone in this)sendtowill error withEMSGSIZEif the datagram is simply too big. The docs are a bit vague but datagrams shouldn't ever be getting split on send (on receipt you lose what you didn't budget for in your receive buffer, unless you peek). - I implemented support (hopefully correctly) for abstract sockets. This requires some complexity around how the length is handled. Abstract sockets can't be the full length of
sun_pathbut IIRCsd_notifyhas the same limitation.
Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.