+ /* serialize and wait for parent or child events */
+ if (devpath_busy(loop_msg, max_childs) != 0) {
+ dbg("delay seq %llu (%s)", loop_msg->seqnum, loop_msg->devpath);
+ continue;
+ }
+
+ /* move event to run list */
+ list_move_tail(&loop_msg->node, &running_list);
+ udev_event_run(loop_msg);
+ running++;
+ dbg("moved seq %llu to running list", loop_msg->seqnum);
+ }
+}
+
+static struct udevd_uevent_msg *get_msg_from_envbuf(const char *buf, int buf_size)
+{
+ int bufpos;
+ int i;
+ struct udevd_uevent_msg *msg;
+ char *physdevdriver_key = NULL;
+ int maj = 0;
+ int min = 0;
+
+ msg = malloc(sizeof(struct udevd_uevent_msg) + buf_size);
+ if (msg == NULL)
+ return NULL;
+ memset(msg, 0x00, sizeof(struct udevd_uevent_msg) + buf_size);
+
+ /* copy environment buffer and reconstruct envp */
+ memcpy(msg->envbuf, buf, buf_size);
+ bufpos = 0;
+ for (i = 0; (bufpos < buf_size) && (i < UEVENT_NUM_ENVP-2); i++) {
+ int keylen;
+ char *key;
+
+ key = &msg->envbuf[bufpos];
+ keylen = strlen(key);
+ msg->envp[i] = key;
+ bufpos += keylen + 1;
+ dbg("add '%s' to msg.envp[%i]", msg->envp[i], i);
+
+ /* remember some keys for further processing */
+ if (strncmp(key, "ACTION=", 7) == 0)
+ msg->action = &key[7];
+ else if (strncmp(key, "DEVPATH=", 8) == 0)
+ msg->devpath = &key[8];
+ else if (strncmp(key, "SUBSYSTEM=", 10) == 0)
+ msg->subsystem = &key[10];
+ else if (strncmp(key, "DRIVER=", 7) == 0)
+ msg->driver = &key[7];
+ else if (strncmp(key, "SEQNUM=", 7) == 0)
+ msg->seqnum = strtoull(&key[7], NULL, 10);
+ else if (strncmp(key, "DEVPATH_OLD=", 12) == 0)
+ msg->devpath_old = &key[12];
+ else if (strncmp(key, "PHYSDEVPATH=", 12) == 0)
+ msg->physdevpath = &key[12];
+ else if (strncmp(key, "PHYSDEVDRIVER=", 14) == 0)
+ physdevdriver_key = key;
+ else if (strncmp(key, "MAJOR=", 6) == 0)
+ maj = strtoull(&key[6], NULL, 10);
+ else if (strncmp(key, "MINOR=", 6) == 0)
+ min = strtoull(&key[6], NULL, 10);
+ else if (strncmp(key, "TIMEOUT=", 8) == 0)
+ msg->timeout = strtoull(&key[8], NULL, 10);
+ }
+ msg->devt = makedev(maj, min);
+ msg->envp[i++] = "UDEVD_EVENT=1";
+
+ if (msg->driver == NULL && msg->physdevpath == NULL && physdevdriver_key != NULL) {
+ /* for older kernels DRIVER is empty for a bus device, export PHYSDEVDRIVER as DRIVER */
+ msg->envp[i++] = &physdevdriver_key[7];
+ msg->driver = &physdevdriver_key[14];
+ }
+
+ msg->envp[i] = NULL;
+
+ if (msg->devpath == NULL || msg->action == NULL) {
+ info("DEVPATH or ACTION missing, ignore message");
+ free(msg);
+ return NULL;
+ }
+ return msg;
+}
+
+/* receive the udevd message from userspace */
+static void get_ctrl_msg(void)
+{
+ struct udevd_ctrl_msg ctrl_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 *intval;
+ char *pos;
+
+ memset(&ctrl_msg, 0x00, sizeof(struct udevd_ctrl_msg));
+ iov.iov_base = &ctrl_msg;
+ iov.iov_len = sizeof(struct udevd_ctrl_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)
+ err("unable to receive user udevd message: %s", strerror(errno));
+ return;
+ }
+ cmsg = CMSG_FIRSTHDR(&smsg);
+ cred = (struct ucred *) CMSG_DATA(cmsg);
+
+ if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
+ err("no sender credentials received, message ignored");
+ return;
+ }