diff options
Diffstat (limited to 'udev')
-rw-r--r-- | udev/udevd.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/udev/udevd.c b/udev/udevd.c index 6dd59ae697..e38c601649 100644 --- a/udev/udevd.c +++ b/udev/udevd.c @@ -34,6 +34,7 @@ #include <sys/time.h> #include <sys/prctl.h> #include <sys/socket.h> +#include <sys/un.h> #include <sys/signalfd.h> #include <sys/select.h> #include <sys/poll.h> @@ -950,6 +951,81 @@ static int mem_size_mb(void) return memsize; } +static int init_notify(const char *state) +{ + int fd = -1, r; + struct msghdr msghdr; + struct iovec iovec; + struct ucred *ucred; + union { + struct sockaddr sa; + struct sockaddr_un un; + } sockaddr; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; + } control; + const char *e; + + if (!(e = getenv("NOTIFY_SOCKET"))) { + r = 0; + goto finish; + } + + /* Must be an abstract socket, or an absolute path */ + if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { + r = -EINVAL; + goto finish; + } + + if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { + r = -errno; + goto finish; + } + + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sa.sa_family = AF_UNIX; + strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); + + if (sockaddr.un.sun_path[0] == '@') + sockaddr.un.sun_path[0] = 0; + + memset(&iovec, 0, sizeof(iovec)); + iovec.iov_base = (char*) state; + iovec.iov_len = strlen(state); + + memset(&control, 0, sizeof(control)); + control.cmsghdr.cmsg_level = SOL_SOCKET; + control.cmsghdr.cmsg_type = SCM_CREDENTIALS; + control.cmsghdr.cmsg_len = CMSG_LEN(sizeof(struct ucred)); + + ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); + ucred->pid = getpid(); + ucred->uid = getuid(); + ucred->gid = getgid(); + + memset(&msghdr, 0, sizeof(msghdr)); + msghdr.msg_name = &sockaddr; + msghdr.msg_namelen = sizeof(struct sockaddr_un); + msghdr.msg_iov = &iovec; + msghdr.msg_iovlen = 1; + msghdr.msg_control = &control; + msghdr.msg_controllen = control.cmsghdr.cmsg_len; + + if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { + r = -errno; + goto finish; + } + + r = 0; + +finish: + if (fd >= 0) + close(fd); + + return r; +} + int main(int argc, char *argv[]) { struct udev *udev; @@ -1201,6 +1277,8 @@ int main(int argc, char *argv[]) rc = 0; goto exit; } + } else { + init_notify("READY=1"); } /* set scheduling priority for the main daemon process */ |