+ struct udevd_uevent_msg *loop_msg;
+ struct udevd_uevent_msg *tmp_msg;
+ int running;
+
+ if (list_empty(&exec_list))
+ return;
+
+ running = running_processes();
+ dbg("%d processes runnning on system", running);
+ if (running < 0)
+ running = max_childs_running;
+
+ list_for_each_entry_safe(loop_msg, tmp_msg, &exec_list, node) {
+ /* check running processes in our session and possibly throttle */
+ if (running >= max_childs_running) {
+ running = running_processes_in_session(sid, max_childs_running+10);
+ dbg("at least %d processes running in session", running);
+ if (running >= max_childs_running) {
+ dbg("delay seq %llu, too many processes already running", loop_msg->seqnum);
+ return;
+ }
+ }
+
+ /* 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;