about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2022-05-08 00:36:43 +0000
committerLaurent Bercot <ska@appnovation.com>2022-05-08 00:36:43 +0000
commit7fde494f57985bba16e255b03a6cee6db44fdc8a (patch)
tree98f38bef6e5e93c5abffc489cfcc6783875c7eb6
parentd918eccfc262cebb0d8f54237a959ac66896eba0 (diff)
downloadmdevd-7fde494f57985bba16e255b03a6cee6db44fdc8a.tar.gz
mdevd-7fde494f57985bba16e255b03a6cee6db44fdc8a.tar.xz
mdevd-7fde494f57985bba16e255b03a6cee6db44fdc8a.zip
Fix event handling completion logic
With the fix for the duplicate spawn_command bug, we can now return
to the main loop mid-script. We need a marker to know when we're
done with the event and can rebc it.

Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r--src/mdevd/mdevd.c65
1 files changed, 34 insertions, 31 deletions
diff --git a/src/mdevd/mdevd.c b/src/mdevd/mdevd.c
index 1426332..d6fd6c3 100644
--- a/src/mdevd/mdevd.c
+++ b/src/mdevd/mdevd.c
@@ -55,7 +55,6 @@
 
 static int dryrun = 0 ;
 static int cont = 1 ;
-static pid_t pid = 0 ;
 static unsigned int verbosity = 1 ;
 static char const *slashsys = "/sys" ;
 static char const *fwbase = "/lib/firmware" ;
@@ -141,10 +140,12 @@ struct udata_s
   unsigned int action ;
   int mmaj ;
   int mmin ;
+  pid_t pid ;
   unsigned int i ;
   char buf[UEVENT_MAX_SIZE] ;
+  unsigned char done : 1 ;
 } ;
-#define UDATA_ZERO { .devname = 0, .devtype = 0, .action = 0, .mmaj = -1, .mmin = -1, .i = 0, .buf = "" }
+#define UDATA_ZERO { .devname = 0, .devtype = 0, .action = 0, .mmaj = -1, .mmin = -1, .pid = 0, .i = 0, .buf = "", .done = 0 }
 
 
  /* Utility functions */
@@ -300,7 +301,6 @@ static inline int uevent_read (int fd, struct uevent_s *event)
 }
 
 
-
  /* mdev.conf parsing. See PARSING.txt for details. */
 
  /* The first pass is simple. The goal is just to compute scriptlen and envmatchlen. */
@@ -669,7 +669,7 @@ static inline ssize_t alias_format (char *out, size_t outmax, char const *in, ch
   return w ;
 }
 
-static inline void spawn_command (char const *command, struct uevent_s const *event, int isel)
+static inline void spawn_command (char const *command, struct uevent_s const *event, int isel, udata *ud)
 {
   char const *argv[4] = { isel ? "execlineb" : "/bin/sh", isel ? "-Pc" : "-c", command, 0 } ;
   size_t envlen = env_len((char const **)environ) ;
@@ -679,14 +679,14 @@ static inline void spawn_command (char const *command, struct uevent_s const *ev
     if (verbosity) strerr_warnwu1sys("merge environment to spawn command") ;
     return ;
   }
-  pid = child_spawn0(argv[0], argv, envp) ;
-  if (!pid)
+  ud->pid = child_spawn0(argv[0], argv, envp) ;
+  if (!ud->pid)
   {
     if (verbosity) strerr_warnwu2sys("spawn ", argv[0]) ;
   }
 }
 
-static inline int run_scriptelem (struct uevent_s *event, scriptelem const *elem, char const *storage, struct envmatch_s const *envmatch, udata const *ud)
+static inline int run_scriptelem (struct uevent_s *event, scriptelem const *elem, char const *storage, struct envmatch_s const *envmatch, udata *ud)
 {
   size_t devnamelen = strlen(ud->devname) ;
   size_t nodelen = 0 ;
@@ -825,7 +825,7 @@ static inline int run_scriptelem (struct uevent_s *event, scriptelem const *elem
         strerr_warni2x("dry run: added variables: ", buf) ;
       }
     }
-    else spawn_command(storage + elem->command, event, elem->flagexecline) ;
+    else spawn_command(storage + elem->command, event, elem->flagexecline, ud) ;
   }
 
   if (elem->movetype != MOVEINFO_NOCREATE && ud->action == ACTION_REMOVE && ud->mmaj >= 0)
@@ -839,16 +839,18 @@ static inline int run_scriptelem (struct uevent_s *event, scriptelem const *elem
     else unlink_void(node) ;
   }
 
-  return pid || !elem->flagcont ;
+  ud->done = !elem->flagcont ;
+  return ud->done || !!ud->pid ;
 }
 
-static inline void run_script (struct uevent_s *event, scriptelem const *script, unsigned short scriptlen, char const *storage, struct envmatch_s const *envmatch, udata *ud)
+static int run_script (struct uevent_s *event, scriptelem const *script, unsigned short scriptlen, char const *storage, struct envmatch_s const *envmatch, udata *ud)
 {
-  while (ud->i < scriptlen)
-    if (run_scriptelem(event, script + ud->i++, storage, envmatch, ud)) break ;
+  for (;; ud->i++)  /* last elem is the catchall with flagcont=0 */
+    if (run_scriptelem(event, script + ud->i, storage, envmatch, ud)) break ;
+  return ud->done && !ud->pid ;
 }
 
-static inline void act_on_event (struct uevent_s *event, char *sysdevpath, size_t sysdevpathlen, unsigned int action, scriptelem const *script, unsigned short scriptlen, char const *storage, struct envmatch_s const *envmatch, udata *ud)
+static inline int act_on_event (struct uevent_s *event, char *sysdevpath, size_t sysdevpathlen, unsigned int action, scriptelem const *script, unsigned short scriptlen, char const *storage, struct envmatch_s const *envmatch, udata *ud)
 {
   ssize_t hasmajmin = 0 ;
   unsigned int mmaj, mmin ;
@@ -905,7 +907,7 @@ static inline void act_on_event (struct uevent_s *event, char *sysdevpath, size_
   if (strlen(ud->devname) >= PATH_MAX - 1)
   {
     if (verbosity) strerr_warnwu2x("device name too long: ", ud->devname) ;
-    return ;
+    return 1 ;
   }
   if (strstr(sysdevpath, "/block/")) ud->devtype = S_IFBLK ;
   else
@@ -914,28 +916,31 @@ static inline void act_on_event (struct uevent_s *event, char *sysdevpath, size_
     if (x && str_start(x, "block")) ud->devtype = S_IFBLK ;
   }
   ud->i = 0 ;
-  run_script(event, script, scriptlen, storage, envmatch, ud) ;
+  ud->done = 0 ;
+  return run_script(event, script, scriptlen, storage, envmatch, ud) ;
 }
 
-static inline void on_event (struct uevent_s *event, scriptelem const *script, unsigned short scriptlen, char const *storage, struct envmatch_s const *envmatch, udata *ud)
+static inline int on_event (struct uevent_s *event, scriptelem const *script, unsigned short scriptlen, char const *storage, struct envmatch_s const *envmatch, udata *ud)
 {
   unsigned int action ;
   char const *x = event_getvar(event, "ACTION") ;
-  if (!x) return ;
+  if (!x) return 1 ;
   if (!strcmp(x, "add")) action = ACTION_ADD ;
   else if (!strcmp(x, "remove")) action = ACTION_REMOVE ;
   else action = ACTION_ANY ;
   x = event_getvar(event, "DEVPATH") ;
-  if (!x) return ;
+  if (!x) return 1 ;
   {
+    int done = 1 ;
     size_t devpathlen = strlen(x) ;
     size_t slashsyslen = strlen(slashsys) ;
     char sysdevpath[devpathlen + slashsyslen + 8] ; /* act_on_event needs the extra storage */
     memcpy(sysdevpath, slashsys, slashsyslen) ;
     memcpy(sysdevpath + slashsyslen, x, devpathlen + 1) ;
     x = event_getvar(event, "FIRMWARE") ;
-    if (action == ACTION_ADD || !x) act_on_event(event, sysdevpath, slashsyslen + devpathlen, action, script, scriptlen, storage, envmatch, ud) ;
+    if (action == ACTION_ADD || !x) done = act_on_event(event, sysdevpath, slashsyslen + devpathlen, action, script, scriptlen, storage, envmatch, ud) ;
     if (action == ACTION_ADD && x) load_firmware(x, sysdevpath) ;
+    return done ;
   }
 }
 
@@ -955,18 +960,17 @@ static inline int handle_signals (struct uevent_s *event, scriptelem const *scri
       case SIGTERM : cont = 0 ; break ;
       case SIGHUP : cont = 1 ; break ;
       case SIGCHLD :
-        if (!pid) wait_reap() ;
+        if (!ud->pid) wait_reap() ;
         else
         {
           int wstat ;
-          int r = wait_pid_nohang(pid, &wstat) ;
+          int r = wait_pid_nohang(ud->pid, &wstat) ;
           if (r < 0)
             if (errno != ECHILD) strerr_diefu1sys(111, "wait_pid_nohang") ;
             else break ;
           else if (!r) break ;
-          pid = 0 ;
-          e = 1 ;
-          run_script(event, script, scriptlen, storage, envmatch, ud) ;
+          ud->pid = 0 ;
+          e = ud->done ? 1 : run_script(event, script, scriptlen, storage, envmatch, ud) ;
         }
         break ;
       default :
@@ -978,8 +982,7 @@ static inline int handle_signals (struct uevent_s *event, scriptelem const *scri
 static inline int handle_event (int fd, struct uevent_s *event, scriptelem const *script, unsigned short scriptlen, char const *storage, struct envmatch_s const *envmatch, udata *ud)
 {
   if (!uevent_read(fd, event) || event->varn <= 1) return 0 ;
-    on_event(event, script, scriptlen, storage, envmatch, ud) ;
-  return 1 ;
+  return on_event(event, script, scriptlen, storage, envmatch, ud) ;
 }
 
 static int output_event (unsigned int outputfd, struct uevent_s *event)
@@ -1131,17 +1134,17 @@ int main (int argc, char const *const *argv)
         notif = 0 ;
       }
 
-      while (pid || cont == 2)
+      while (ud.pid || cont == 2)
       {
-        if (iopause_stamp(x, 1 + (!pid && cont == 2), 0, 0) < 0) strerr_diefu1sys(111, "iopause") ;
+        if (iopause_stamp(x, 1 + (!ud.pid && cont == 2), 0, 0) < 0) strerr_diefu1sys(111, "iopause") ;
         if (x[0].revents & IOPAUSE_READ)
-          if (handle_signals(&event, script, scriptlen, storage, envmatch, &ud) && !pid)
+          if (handle_signals(&event, script, scriptlen, storage, envmatch, &ud))
           {
             if (outputfd && !output_event(outputfd, &event)) outputfd = 0 ;
             if (rebc) rebc_event(rebc, &event) ;
           }
-        if (!pid && cont == 2 && x[1].revents & IOPAUSE_READ)
-          if (handle_event(x[1].fd, &event, script, scriptlen, storage, envmatch, &ud) && !pid)
+        if (!ud.pid && cont == 2 && x[1].revents & IOPAUSE_READ)
+          if (handle_event(x[1].fd, &event, script, scriptlen, storage, envmatch, &ud))
           {
             if (outputfd && !output_event(outputfd, &event)) outputfd = 0 ;
             if (rebc) rebc_event(rebc, &event) ;