Package: release.debian.org
Severity: normal
User: release.debian....@packages.debian.org
Usertags: unblock

Please unblock package udpkg

I've added locking for the status file, so parallel udpkg invocations
will not break the world. This fixes #987368. We definitely want this
fix for Bullseye. I've CC:ed KiBi too.

See attached debdiff.

unblock udpkg/1.20

-- System Information:
Debian Release: 10.10
  APT prefers stable-debug
  APT policy: (500, 'stable-debug'), (500, 'stable'), (500, 'oldstable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 5.10.0-0.bpo.5-amd64 (SMP w/4 CPU cores)
Kernel taint flags: TAINT_CPU_OUT_OF_SPEC
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8), 
LANGUAGE=en_GB:en (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
diff -Nru udpkg-1.19/debian/changelog udpkg-1.20/debian/changelog
--- udpkg-1.19/debian/changelog 2018-09-23 18:16:44.000000000 +0100
+++ udpkg-1.20/debian/changelog 2021-06-11 02:46:39.000000000 +0100
@@ -1,3 +1,19 @@
+udpkg (1.20) unstable; urgency=medium
+
+  [ Holger Wansing ]
+  * Remove trailing whitespaces from changelog file, to fix lintian tag.
+
+  [ Cyril Brulebois ]
+  * Remove Christian Perrier from Uploaders, with many thanks for all
+    his contributions over the years! (Closes: #927557)
+
+  [ Steve McIntyre ]
+  * Add locking for the status file, so parallel udpkg invocations
+    will not break the world. Closes: #987368
+  * Add myself to Uploaders
+
+ -- Steve McIntyre <93...@debian.org>  Fri, 11 Jun 2021 02:46:39 +0100
+
 udpkg (1.19) unstable; urgency=medium
 
   * Team upload.
@@ -374,7 +390,7 @@
 
 udpkg (0.004) unstable; urgency=low
 
-  * fixes builddeps (closes: #86934) 
+  * fixes builddeps (closes: #86934)
 
  -- Randolph Chung <ta...@debian.org>  Wed, 21 Feb 2001 21:00:45 -0700
 
@@ -397,5 +413,3 @@
   * Non-release.
 
  -- Joey Hess <jo...@debian.org>  Thu, 26 Oct 2000 12:02:04 -0700
-
-
diff -Nru udpkg-1.19/debian/control udpkg-1.20/debian/control
--- udpkg-1.19/debian/control   2018-08-10 20:25:18.000000000 +0100
+++ udpkg-1.20/debian/control   2021-06-10 23:04:38.000000000 +0100
@@ -2,7 +2,7 @@
 Section: debian-installer
 Priority: standard
 Maintainer: Debian Install System Team <debian-b...@lists.debian.org>
-Uploaders: Bastian Blank <wa...@debian.org>, Christian Perrier 
<bubu...@debian.org>
+Uploaders: Bastian Blank <wa...@debian.org>, Steve McIntyre <93...@debian.org>
 Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.7.0), libdebian-installer4-dev 
(>= 0.41), dh-autoreconf
 Vcs-Browser: https://salsa.debian.org/installer-team/udpkg
 Vcs-Git: https://salsa.debian.org/installer-team/udpkg.git
diff -Nru udpkg-1.19/status.c udpkg-1.20/status.c
--- udpkg-1.19/status.c 2018-08-10 20:25:18.000000000 +0100
+++ udpkg-1.20/status.c 2021-06-11 00:45:35.000000000 +0100
@@ -1,9 +1,11 @@
 #include "udpkg.h"
 
+#include <errno.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <search.h>
+#include <sys/file.h>
 #include <debian-installer.h>
 
 /* Status file handling routines
@@ -19,8 +21,15 @@
  *    control info from (new) packages is merged into the status file, 
  *    replacing any pre-existing entries. when a merge happens, status info 
  *    read using the status_read function is written back to the status file
+ *
+ * There is also a pair of functions to lock and unlock access to the
+ * status, to protect against multiple invocations of udpkg racing
+ * against each other. Callers are responsible for using this locking
+ * around any code that works with the status file.
  */
 
+static int lock_fd = -1;
+
 static const char *statuswords[][10] = {
        { (char *)STATUS_WANTSTART, "unknown", "install", "hold", 
                "deinstall", "purge", 0 },
@@ -208,6 +217,45 @@
        }
 }
 
+void status_lock(void)
+{
+       int error;
+       lock_fd = open(STATUSFILELOCK, O_WRONLY | O_CREAT, 0200);
+       if (lock_fd < 0)
+       {
+               fprintf(stderr, "Unable to open lockfile %s (%d), abort!",
+                       STATUSFILELOCK, errno);
+               exit(1);
+       }
+       error = flock(lock_fd, LOCK_EX);
+       if (error < 0)
+       {
+               fprintf(stderr, "Unable to lock lockfile %s (%d), abort!",
+                       STATUSFILELOCK, errno);
+               exit(1);
+       }
+}
+
+void status_unlock(void)
+{
+       int error;
+       if (lock_fd < 0)
+       {
+               fprintf(stderr, "Trying to unlock when we don't have the 
lockfile %s open!",
+                       STATUSFILELOCK);
+               exit(1);
+       }
+       error = flock(lock_fd, LOCK_UN);
+       if (error < 0)
+       {
+               fprintf(stderr, "Unable to unlock lockfile %s (%d), abort!",
+                       STATUSFILELOCK, errno);
+               exit(1);
+       }
+       close(lock_fd);
+       lock_fd = -1;
+}
+
 void *status_read(void)
 {
        FILE *f;
diff -Nru udpkg-1.19/udpkg.c udpkg-1.20/udpkg.c
--- udpkg-1.19/udpkg.c  2018-08-10 20:25:18.000000000 +0100
+++ udpkg-1.20/udpkg.c  2021-06-11 02:17:34.000000000 +0100
@@ -15,6 +15,14 @@
 #include <sys/utsname.h>
 #include <debian-installer.h>
 
+#ifdef LOCK_DEBUG
+#  define STATUS_LOCK() fprintf(stderr, "%d(%d): trying to lock status 
file\n", getpid(),__LINE__); status_lock(); fprintf(stderr, "%d(%d): locked\n", 
getpid(),__LINE__)
+#  define STATUS_UNLOCK() fprintf(stderr, "%d(%d): trying to unlock status 
file\n", getpid(),__LINE__); status_unlock(); fprintf(stderr, "%d(%d): 
unlocked\n", getpid(),__LINE__)
+#else
+#  define STATUS_LOCK() status_lock()
+#  define STATUS_UNLOCK() status_unlock()
+#endif
+
 static int force_configure = 0;
 static int loadtemplate = 1;
 
@@ -450,12 +458,14 @@
 {
        int r = 0;
        struct package_t *pkg;
+       STATUS_LOCK();
        void *status = status_read();
 
        if (di_exec_shell_log("rm -rf -- " DPKGCIDIR) != 0 ||
            mkdir(DPKGCIDIR, S_IRWXU) != 0)
        {
                perror("mkdir");
+               STATUS_UNLOCK();
                return 1;
        }
        
@@ -468,6 +478,7 @@
        status_merge(status, pkgs);
        if (di_exec_shell_log("rm -rf -- " DPKGCIDIR) != 0)
                r = 1;
+       STATUS_UNLOCK();
        return r;
 }
 
@@ -476,7 +487,9 @@
        int r = 0;
        void *found;
        struct package_t *pkg;
+       STATUS_LOCK();
        void *status = status_read();
+       STATUS_UNLOCK();
        for (pkg = pkgs; pkg != 0 && r == 0; pkg = pkg->next)
        {
                found = tfind(pkg, &status, package_compare);
@@ -492,18 +505,22 @@
                        r = dpkg_doconfigure(*(struct package_t **)found);
                }
        }
+       STATUS_LOCK();
        status_merge(status, 0);
+       STATUS_UNLOCK();
        return r;
 }
 
 static int dpkg_install(struct package_t *pkgs)
 {
        struct package_t *p, *ordered = 0;
+       STATUS_LOCK();
        void *status = status_read();
        if (di_exec_shell_log("rm -rf -- " DPKGCIDIR) != 0 ||
            mkdir(DPKGCIDIR, S_IRWXU) != 0)
        {
                perror("mkdir");
+               STATUS_UNLOCK();
                return 1;
        }
        
@@ -542,6 +559,7 @@
        
        if (ordered != 0)
                status_merge(status, pkgs);
+       STATUS_UNLOCK();
        return di_exec_shell_log("rm -rf -- " DPKGCIDIR);
 }
 
@@ -602,6 +620,7 @@
        struct package_t *p;
        char buf[1024], buf2[1024];
        FILE *fp;
+       STATUS_LOCK();
        void *status = status_read();
 
        for (p = pkgs; p != 0; p = p->next)
@@ -650,6 +669,7 @@
                  p->status |= STATUS_STATUSHALFINSTALLED;
        }
        status_merge(status, pkgs);
+       STATUS_UNLOCK();
        return r;
 #else
        FPRINTF(stderr, "udpkg: No support for -r.\n");
diff -Nru udpkg-1.19/udpkg.h udpkg-1.20/udpkg.h
--- udpkg-1.19/udpkg.h  2018-08-10 20:25:18.000000000 +0100
+++ udpkg-1.20/udpkg.h  2021-06-10 01:19:44.000000000 +0100
@@ -19,6 +19,7 @@
 
 #define BUFSIZE                4096
 #define STATUSFILE     ADMINDIR "/status"
+#define STATUSFILELOCK ADMINDIR "/status.lck"
 #define DPKGCIDIR      ADMINDIR "/tmp.ci/"
 #define INFODIR                ADMINDIR "/info/"
 #define UDPKG_QUIET    "UDPKG_QUIET"
@@ -95,6 +96,8 @@
 void *status_read(void);
 void control_read(FILE *f, struct package_t *p);
 int status_merge(void *status, struct package_t *pkgs);
+void status_lock(void);
+void status_unlock(void);
 int package_compare(const void *p1, const void *p2);
 struct package_t *depends_resolve(struct package_t *pkgs, void *status);
 

Reply via email to