+ if (strncmp(key, "PHYSDEVPATH=", 12) == 0)
+ msg->physdevpath = &key[12];
+
+ if (strncmp(key, "TIMEOUT=", 8) == 0)
+ msg->timeout = strtoull(&key[8], NULL, 10);
+ }
+ msg->envp[i++] = "UDEVD_EVENT=1";
+ msg->envp[i] = NULL;
+
+ return msg;
+}
+
+/* receive the udevd message from userspace */
+static struct uevent_msg *get_udevd_msg(void)
+{
+ static struct udevd_msg usend_msg;
+ struct uevent_msg *msg;
+ ssize_t size;
+ struct msghdr smsg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ struct ucred *cred;
+ char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+ int envbuf_size;
+ int *intval;
+
+ memset(&usend_msg, 0x00, sizeof(struct udevd_msg));
+ iov.iov_base = &usend_msg;
+ iov.iov_len = sizeof(struct udevd_msg);
+
+ memset(&smsg, 0x00, sizeof(struct msghdr));
+ smsg.msg_iov = &iov;
+ smsg.msg_iovlen = 1;
+ smsg.msg_control = cred_msg;
+ smsg.msg_controllen = sizeof(cred_msg);
+
+ size = recvmsg(udevd_sock, &smsg, 0);
+ if (size < 0) {
+ if (errno != EINTR)
+ dbg("unable to receive udevd message");
+ return NULL;
+ }
+ cmsg = CMSG_FIRSTHDR(&smsg);
+ cred = (struct ucred *) CMSG_DATA(cmsg);
+
+ if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
+ info("no sender credentials received, message ignored");
+ return NULL;
+ }
+
+ if (cred->uid != 0) {
+ info("sender uid=%i, message ignored", cred->uid);
+ return NULL;
+ }
+
+ if (strncmp(usend_msg.magic, UDEV_MAGIC, sizeof(UDEV_MAGIC)) != 0 ) {
+ info("message magic '%s' doesn't match, ignore it", usend_msg.magic);
+ return NULL;
+ }
+
+ switch (usend_msg.type) {
+ case UDEVD_UEVENT_UDEVSEND:
+ case UDEVD_UEVENT_INITSEND:
+ info("udevd event message received");
+ envbuf_size = size - offsetof(struct udevd_msg, envbuf);
+ dbg("envbuf_size=%i", envbuf_size);
+ msg = get_msg_from_envbuf(usend_msg.envbuf, envbuf_size);
+ if (msg == NULL)
+ return NULL;
+ msg->type = usend_msg.type;
+ return msg;
+ case UDEVD_STOP_EXEC_QUEUE:
+ info("udevd message (STOP_EXEC_QUEUE) received");
+ stop_exec_q = 1;
+ break;
+ case UDEVD_START_EXEC_QUEUE:
+ info("udevd message (START_EXEC_QUEUE) received");
+ stop_exec_q = 0;
+ exec_queue_manager();
+ break;
+ case UDEVD_SET_LOG_LEVEL:
+ intval = (int *) usend_msg.envbuf;
+ info("udevd message (SET_LOG_PRIORITY) received, udev_log_priority=%i", *intval);
+ udev_log_priority = *intval;
+ break;
+ case UDEVD_SET_MAX_CHILDS:
+ intval = (int *) usend_msg.envbuf;
+ info("udevd message (UDEVD_SET_MAX_CHILDS) received, max_childs=%i", *intval);
+ max_childs = *intval;
+ break;
+ default:
+ dbg("unknown message type");
+ }
+ return NULL;
+}
+
+/* receive the kernel user event message and do some sanity checks */
+static struct uevent_msg *get_netlink_msg(void)
+{
+ struct uevent_msg *msg;
+ int bufpos;
+ ssize_t size;
+ static char buffer[UEVENT_BUFFER_SIZE + 512];
+ char *pos;
+
+ size = recv(uevent_netlink_sock, &buffer, sizeof(buffer), 0);
+ if (size < 0) {
+ if (errno != EINTR)
+ dbg("unable to receive udevd message");
+ return NULL;
+ }
+
+ if ((size_t)size > sizeof(buffer)-1)
+ size = sizeof(buffer)-1;
+ buffer[size] = '\0';
+ dbg("uevent_size=%li", (long)size);
+
+ /* start of event payload */
+ bufpos = strlen(buffer)+1;
+ msg = get_msg_from_envbuf(&buffer[bufpos], size-bufpos);
+ if (msg == NULL)
+ return NULL;
+ msg->type = UDEVD_UEVENT_NETLINK;
+
+ /* validate message */
+ pos = strchr(buffer, '@');
+ if (pos == NULL) {
+ dbg("invalid uevent '%s'", buffer);
+ free(msg);
+ return NULL;
+ }
+ pos[0] = '\0';
+
+ if (msg->action == NULL) {
+ dbg("no ACTION in payload found, skip event '%s'", buffer);
+ free(msg);
+ return NULL;
+ }
+
+ if (strcmp(msg->action, buffer) != 0) {
+ dbg("ACTION in payload does not match uevent, skip event '%s'", buffer);
+ free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+static void asmlinkage sig_handler(int signum)
+{
+ int rc;
+
+ switch (signum) {
+ case SIGINT:
+ case SIGTERM:
+ exit(20 + signum);
+ break;
+ case SIGALRM:
+ /* set flag, then write to pipe if needed */
+ run_msg_q = 1;
+ goto do_write;
+ break;
+ case SIGCHLD:
+ /* set flag, then write to pipe if needed */
+ sigchilds_waiting = 1;
+ goto do_write;
+ break;
+ }
+
+do_write:
+ /* if pipe is empty, write to pipe to force select to return
+ * immediately when it gets called
+ */
+ if (!sig_flag) {
+ rc = write(pipefds[1],&signum,sizeof(signum));
+ if (rc >= 0)
+ sig_flag = 1;