+ }
+}
+
+static char *curtime(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ sprintf(
+ strftime_HHMMSS(G.timestr, sizeof(G.timestr), &tv.tv_sec),
+ ".%06u",
+ (unsigned)tv.tv_usec
+ );
+ return G.timestr;
+}
+
+static void open_mdev_log(const char *seq, unsigned my_pid)
+{
+ int logfd = open("mdev.log", O_WRONLY | O_APPEND);
+ if (logfd >= 0) {
+ xmove_fd(logfd, STDERR_FILENO);
+ G.verbose = 2;
+ applet_name = xasprintf("%s[%s]", applet_name, seq ? seq : utoa(my_pid));
+ }
+}
+
+/* If it exists, does /dev/mdev.seq match $SEQNUM?
+ * If it does not match, earlier mdev is running
+ * in parallel, and we need to wait.
+ * Active mdev pokes us with SIGCHLD to check the new file.
+ */
+static int
+wait_for_seqfile(unsigned expected_seq)
+{
+ /* We time out after 2 sec */
+ static const struct timespec ts = { 0, 32*1000*1000 };
+ int timeout = 2000 / 32;
+ int seq_fd = -1;
+ int do_once = 1;
+ sigset_t set_CHLD;
+
+ sigemptyset(&set_CHLD);
+ sigaddset(&set_CHLD, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &set_CHLD, NULL);
+
+ for (;;) {
+ int seqlen;
+ char seqbuf[sizeof(long)*3 + 2];
+ unsigned seqbufnum;
+
+ if (seq_fd < 0) {
+ seq_fd = open("mdev.seq", O_RDWR);
+ if (seq_fd < 0)
+ break;
+ close_on_exec_on(seq_fd);
+ }
+ seqlen = pread(seq_fd, seqbuf, sizeof(seqbuf) - 1, 0);
+ if (seqlen < 0) {
+ close(seq_fd);
+ seq_fd = -1;
+ break;
+ }
+ seqbuf[seqlen] = '\0';
+ if (seqbuf[0] == '\n' || seqbuf[0] == '\0') {
+ /* seed file: write out seq ASAP */
+ xwrite_str(seq_fd, utoa(expected_seq));
+ xlseek(seq_fd, 0, SEEK_SET);
+ dbg2("first seq written");
+ break;
+ }
+ seqbufnum = atoll(seqbuf);
+ if (seqbufnum == expected_seq) {
+ /* correct idx */
+ break;
+ }
+ if (seqbufnum > expected_seq) {
+ /* a later mdev runs already (this was seen by users to happen) */
+ /* do not overwrite seqfile on exit */
+ close(seq_fd);
+ seq_fd = -1;
+ break;
+ }
+ if (do_once) {
+ dbg2("%s mdev.seq='%s', need '%u'", curtime(), seqbuf, expected_seq);
+ do_once = 0;
+ }
+ if (sigtimedwait(&set_CHLD, NULL, &ts) >= 0) {
+ dbg3("woken up");
+ continue; /* don't decrement timeout! */
+ }
+ if (--timeout == 0) {
+ dbg1("%s mdev.seq='%s'", "timed out", seqbuf);
+ break;
+ }
+ }
+ sigprocmask(SIG_UNBLOCK, &set_CHLD, NULL);
+ return seq_fd;
+}
+
+static void signal_mdevs(unsigned my_pid)
+{
+ procps_status_t* p = NULL;
+ while ((p = procps_scan(p, PSSCAN_ARGV0)) != NULL) {
+ if (p->pid != my_pid
+ && p->argv0
+ && strcmp(bb_basename(p->argv0), "mdev") == 0
+ ) {
+ kill(p->pid, SIGCHLD);
+ }