Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package virtme for openSUSE:Leap:16.0 
checked in at 2025-08-11 16:12:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Leap:16.0/virtme (Old)
 and      /work/SRC/openSUSE:Leap:16.0/.virtme.new.1085 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "virtme"

Mon Aug 11 16:12:43 2025 rev:4 rq:1298845 version:1.37

Changes:
--------
--- /work/SRC/openSUSE:Leap:16.0/virtme/virtme.changes  2025-06-04 
11:24:14.562329251 +0200
+++ /work/SRC/openSUSE:Leap:16.0/.virtme.new.1085/virtme.changes        
2025-08-11 16:13:25.897934340 +0200
@@ -1,0 +2,12 @@
+Mon Aug 11 06:27:20 UTC 2025 - Michael Vetter <mvet...@suse.com>
+
+- Update to 1.37:
+  The most interesting feature in this new version is the initial
+  support for systemd.
+  Until now, virtme-ng didn’t support systemd because it relied on a custom
+  init system (virtme-ng-init) to speed up boot time. As a result, tests
+  requiring systemd couldn't run inside the virtme-ng session. With the new
+  --systemd option, virtme-ng can now (optionally) boot with systemd in the
+  virtualized environment, enabling full systemd interaction during testing.
+
+-------------------------------------------------------------------

Old:
----
  virtme-ng-1.36.tar.xz

New:
----
  virtme-ng-1.37.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ virtme.spec ++++++
--- /var/tmp/diff_new_pack.n7wwzr/_old  2025-08-11 16:13:26.213947983 +0200
+++ /var/tmp/diff_new_pack.n7wwzr/_new  2025-08-11 16:13:26.213947983 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package virtme
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2025 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -22,7 +22,7 @@
 %global pythons python311
 %endif
 Name:           virtme
-Version:        1.36
+Version:        1.37
 Release:        0
 Summary:        Tools for virtualize the running distro or a rootfs
 License:        GPL-2.0-only
@@ -81,5 +81,4 @@
 %{python_sitelib}/%{name}_ng
 %{python_sitelib}/%{name}_ng-%{version}-py*.egg-info
 %{_datadir}/bash-completion
-%config(noreplace) %{_sysconfdir}/%{name}-ng.conf
 

++++++ _service ++++++
--- /var/tmp/diff_new_pack.n7wwzr/_old  2025-08-11 16:13:26.257949882 +0200
+++ /var/tmp/diff_new_pack.n7wwzr/_new  2025-08-11 16:13:26.261950055 +0200
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/arighi/virtme-ng.git</param>
     <param name="scm">git</param>
     <param name="submodules">enable</param>
-    <param name="revision">v1.36</param>
+    <param name="revision">v1.37</param>
        <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="versionrewrite-replacement">\1</param>

++++++ virtme-ng-1.36.tar.xz -> virtme-ng-1.37.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virtme-ng-1.36/.pre-commit-config.yaml 
new/virtme-ng-1.37/.pre-commit-config.yaml
--- old/virtme-ng-1.36/.pre-commit-config.yaml  2025-05-11 16:37:00.000000000 
+0200
+++ new/virtme-ng-1.37/.pre-commit-config.yaml  2025-08-08 09:40:53.000000000 
+0200
@@ -11,7 +11,7 @@
       - id: check-executables-have-shebangs
       - id: check-shebang-scripts-are-executable
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: v0.11.8
+    rev: v0.12.7
     hooks:
       - id: ruff
         args: [--fix]
@@ -21,6 +21,6 @@
     hooks:
       - id: shellcheck
   - repo: https://github.com/scop/pre-commit-shfmt
-    rev: v3.11.0-1
+    rev: v3.12.0-2
     hooks:
       - id: shfmt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virtme-ng-1.36/README.md new/virtme-ng-1.37/README.md
--- old/virtme-ng-1.36/README.md        2025-05-11 16:37:00.000000000 +0200
+++ new/virtme-ng-1.37/README.md        2025-08-08 09:40:53.000000000 +0200
@@ -103,6 +103,25 @@
  $ ./vng --help
 ```
 
+Configuration
+=============
+
+* You may customize the default configuration by providing one of the
+  following, by order of preference: `$HOME/.config/virtme-ng/virtme-ng.conf`,
+  `$HOME/.virtme-ng.conf` or `/etc/virtme-ng.conf`. As a fallback for any
+  missing values, the default ones will be used.
+
+* The format of the file is JSON. Default values:
+```
+{
+    "default_opts": {},
+    "systemd": {
+        "masks": ["getty@"]
+    }
+}
+```
+
+
 Requirements
 ============
 
@@ -294,6 +313,36 @@
    Linux version 6.7.0-060700rc5-generic (kernel@kathleen) 
(x86_64-linux-gnu-gcc-13 (Ubuntu 13.2.0-7ubuntu1) 13.2.0, GNU ld (GNU Binutils 
for Ubuntu) 2.41) #202312102332 SMP PREEMPT_DYNAMIC Sun Dec 10 23:41:31 UTC 2023
 ```
 
+ - Run with systemd as init:
+```
+   $ sudo vng -r --systemd --exec "systemctl status | head"
+   ● virtme-ng
+      State: starting
+      Units: 392 loaded (incl. loaded aliases)
+      Jobs: 4 queued
+      Failed: 3 units
+      Since: Mon 2025-05-26 11:00:47 -03; 4s ago
+   systemd: 257.5+suse.8.gc10a66fb4d
+   Tainted: unmerged-bin
+      CGroup: /
+            ├─init.scope
+```
+
+ - Run with systemd as init in an external rootfs:
+```
+   $ vng -r --systemd --user root --root ./rootfs/sid --exec "systemctl status 
| head"
+   ● virtme-ng
+      State: degraded
+      Units: 273 loaded (incl. loaded aliases)
+      Jobs: 0 queued
+      Failed: 4 units
+      Since: Mon 2025-05-26 14:01:06 UTC; 2s ago
+   systemd: 257.5-2
+   Tainted: unmerged-bin
+      CGroup: /
+            ├─init.scope
+```
+
  - Run the current kernel creating a 1GB NUMA node with CPUs 0,1,3 assigned
    and a 3GB NUMA node with CPUs 2,4,5,6,7 assigned:
 ```
@@ -520,12 +569,12 @@
 Typically, if you always use virtme-ng with an external build server (e.g.,
 `vng --build --build-host REMOTE_SERVER --build-host-exec-prefix CMD`) you
 don't always want to specify these options, so instead, you can simply define
-them in `~/.config/virtme-ng/virtme-ng.conf` under `default_opts` and then
-simply run `vng --build`.
+them in your configuration file (refer to the [Configuration](#configuration)
+section) under `default_opts` and then simply run `vng --build`.
 
 Example (always use an external build server called 'kathleen' and run make
 inside a build chroot called `chroot:lunar-amd64`). To do so, add the
-`default_opts` section in `~/.config/virtme-ng/virtme-ng.conf` as following:
+`default_opts` section in your configuration file as following:
 ```
 {
     "default_opts": {
@@ -584,9 +633,17 @@
 ```
 
  - Snap support is still experimental and something may not work as expected
-   (keep in mind that virtme-ng will try to run snapd in a bare minimum system
-   environment without systemd), if some snaps are not running try to disable
-   apparmor, adding `--append="apparmor=0"` to the virtme-ng command line.
+   (keep in mind that, by default, virtme-ng will try to run snapd in a bare
+   minimum system environment without systemd), if some snaps are not running
+   try to disable apparmor, adding `--append="apparmor=0"` to the virtme-ng
+   command line.
+
+ - Systemd support (`--systemd`) is still experimental. If something does not
+   work for you, try masking the unit that is freezing, e.g. `--append
+   "systemd.mask=$PROBLEMATIC_UNIT"` (refer to the
+   [Configuration](#configuration) section for a more permanent setup). Be
+   aware that you might also need `--user root`, or if you're using your own
+   `/` as ROOTFS, you may need to run vng itself as root.
 
  - Running virtme-ng instances inside docker: in case of failures/issues,
    especially with stdin/stdout/stderr redirections, make sure that you have
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virtme-ng-1.36/cfg/virtme-ng.conf 
new/virtme-ng-1.37/cfg/virtme-ng.conf
--- old/virtme-ng-1.36/cfg/virtme-ng.conf       2025-05-11 16:37:00.000000000 
+0200
+++ new/virtme-ng-1.37/cfg/virtme-ng.conf       1970-01-01 01:00:00.000000000 
+0100
@@ -1,4 +0,0 @@
-{
-    "default_opts" : {
-    }
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virtme-ng-1.36/setup.py new/virtme-ng-1.37/setup.py
--- old/virtme-ng-1.36/setup.py 2025-05-11 16:37:00.000000000 +0200
+++ new/virtme-ng-1.37/setup.py 2025-08-08 09:40:53.000000000 +0200
@@ -124,7 +124,6 @@
     packages.append("virtme.guest.bin")
 
 data_files = [
-    ("/etc", ["cfg/virtme-ng.conf"]),
     ("/usr/share/bash-completion/completions", ["virtme-ng-prompt", 
"vng-prompt"]),
 ]
 if build_manpages:
@@ -146,7 +145,7 @@
     author_email="ari...@nvidia.com",
     description="Build and run a kernel inside a virtualized snapshot of your 
live system",
     url="https://github.com/arighi/virtme-ng";,
-    license="GPLv2",
+    license="GPL-2.0-only",
     long_description=open(
         os.path.join(os.path.dirname(__file__), "README.md"), encoding="utf-8"
     ).read(),
@@ -178,7 +177,6 @@
         "Environment :: Console",
         "Intended Audience :: Developers",
         "Intended Audience :: System Administrators",
-        "License :: OSI Approved :: GNU General Public License v2 (GPLv2)",
         "Operating System :: POSIX :: Linux",
     ],
     zip_safe=False,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virtme-ng-1.36/virtme/commands/run.py 
new/virtme-ng-1.37/virtme/commands/run.py
--- old/virtme-ng-1.36/virtme/commands/run.py   2025-05-11 16:37:00.000000000 
+0200
+++ new/virtme-ng-1.37/virtme/commands/run.py   2025-08-08 09:40:53.000000000 
+0200
@@ -25,11 +25,14 @@
 from typing import Any, Dict, List, NoReturn, Optional, Tuple
 
 from virtme_ng.utils import (
+    CACHE_DIR,
     DEFAULT_VIRTME_SSH_HOSTNAME_CID_SEPARATOR,
+    SERIAL_GETTY_FILE,
     SSH_CONF_FILE,
     SSH_DIR,
     VIRTME_SSH_DESTINATION_NAME,
     VIRTME_SSH_HOSTNAME_CID_SEPARATORS,
+    get_conf,
 )
 
 from .. import architectures, mkinitramfs, modfinder, qemu_helpers, resources, 
virtmods
@@ -98,6 +101,11 @@
         "--root", action="store", default="/", help="Local path to use as 
guest root"
     )
     g.add_argument(
+        "--systemd",
+        action="store_true",
+        help="Execute systemd as init (EXPERIMENTAL)",
+    )
+    g.add_argument(
         "--rw",
         action="store_true",
         help="Give the guest read-write access to its root filesystem",
@@ -929,8 +937,10 @@
     try:
         # Run the 'file' command on the binary and check for the string
         # "statically linked"
-        result = subprocess.check_output(["file", binary_path], 
universal_newlines=True)
-        return "statically linked" in result
+        result = subprocess.check_output(
+            ["file", "-L", binary_path], universal_newlines=True
+        )
+        return "statically linked" in result or "static-pie linked" in result
     except subprocess.CalledProcessError:
         return False
 
@@ -1161,12 +1171,17 @@
         if kernel.version:
             print(f"kernel version = {kernel.version}")
         vmlinux = ""
-        if os.path.exists("vmlinux"):
+        if args.kdir is not None and os.path.exists(f"{args.kdir}/vmlinux"):
+            vmlinux = f"{args.kdir}/vmlinux"
+        elif os.path.exists("vmlinux"):
             vmlinux = "vmlinux"
         elif os.path.exists(f"/usr/lib/debug/boot/vmlinux-{kernel.version}"):
             vmlinux = f"/usr/lib/debug/boot/vmlinux-{kernel.version}"
         command = ["gdb", "-q", "-ex", "target remote localhost:1234", vmlinux]
-        os.execvp("gdb", command)
+        if args.dry_run:
+            print(shlex.join(command))
+        else:
+            os.execvp("gdb", command)
         sys.exit(0)
 
     qemuargs: List[str] = [qemu.qemubin]
@@ -1189,9 +1204,10 @@
     try:
         with open("/proc/sys/fs/nr_open", encoding="utf-8") as file:
             nr_open = file.readline().strip()
-            kernelargs.append(f"nr_open={nr_open}")
-    except FileNotFoundError:
+    except (FileNotFoundError, PermissionError):
         pass
+    else:
+        kernelargs.append(f"nr_open={nr_open}")
 
     # Parse NUMA settings.
     if args.numa:
@@ -1296,28 +1312,59 @@
     else:
         virtme_init_cmd = "virtme-init"
 
+    if args.systemd:
+        # disable systemd-fstab-generator so boot does not freeze while 
waiting for disks
+        kernelargs.append("fstab=no")
+        # disable systemd-cryptsetup-generator so it doesn't wait for 
encrypted disks
+        kernelargs.append("luks=no")
+        # disable auditd so there are no errors if the user lacks `--rw`
+        kernelargs.append("audit=off")
+        kernelargs.extend(
+            [f"console={console}" for console in arch.serial_console_args() or 
[]],
+        )
+        kernelargs.extend(
+            [f"systemd.mask={unit}" for unit in get_conf("systemd.masks") or 
[]]
+        )
+
     if args.root == "/":
-        initcmds = [f"init={guest_tools_path}/{virtme_init_cmd}"]
+        if args.systemd:
+            initcmds = [
+                "init=/bin/sh",
+                "--",
+                "-c",
+                f"SYSTEMD_UNIT_PATH={CACHE_DIR}: exec /sbin/init;",
+            ]
+        else:
+            initcmds = [f"init={guest_tools_path}/{virtme_init_cmd}"]
     else:
         virtfs_config = VirtFSConfig(
             path=guest_tools_path,
             mount_tag="virtme.guesttools",
         )
         export_virtfs(qemu, arch, qemuargs, virtfs_config)
-        initcmds = [
-            "init=/bin/sh",
-            "--",
-            "-c",
-            ";".join(
+        initsh = [
+            "mount -t tmpfs run /run",
+            "mkdir -p /run/virtme/guesttools",
+            "/bin/mount -n -t 9p -o 
ro,version=9p2000.L,trans=virtio,access=any "
+            + "virtme.guesttools /run/virtme/guesttools",
+        ]
+        if args.systemd:
+            virtfs_config = VirtFSConfig(
+                path=str(CACHE_DIR),
+                mount_tag="virtme.cache",
+            )
+            export_virtfs(qemu, arch, qemuargs, virtfs_config)
+            initsh.extend(
                 [
-                    "mount -t tmpfs run /run",
-                    "mkdir -p /run/virtme/guesttools",
+                    "mkdir -p /run/virtme/cache",
                     "/bin/mount -n -t 9p -o 
ro,version=9p2000.L,trans=virtio,access=any "
-                    + "virtme.guesttools /run/virtme/guesttools",
-                    f"exec /run/virtme/guesttools/{virtme_init_cmd}",
+                    + "virtme.cache /run/virtme/cache",
+                    "SYSTEMD_UNIT_PATH=/run/virtme/cache: exec /sbin/init",
                 ]
-            ),
-        ]
+            )
+        else:
+            initsh.append(f"exec /run/virtme/guesttools/{virtme_init_cmd}")
+        initcmds = ["init=/bin/sh", "--", "-c", "; ".join(initsh)]
 
     # Arrange for modules to end up in the right place
     if kernel.moddir is not None:
@@ -1400,12 +1447,15 @@
     if args.graphics is None and not args.script_sh and not args.script_exec:
         qemuargs.extend(["-echr", "1"])
 
-        # Redirect kernel errors to stderr, creating a separate console.
-        #
-        # If we don't have access to stderr via procfs (for example when
-        # running inside a container), print a warning and implicitly
-        # suppress the kernel errors redirection.
-        if can_access_file("/proc/self/fd/2"):
+        if args.systemd:
+            # Do nothing if `--systemd` is used, since it relies on the serial 
console
+            pass
+        elif can_access_file("/proc/self/fd/2"):
+            # Redirect kernel errors to stderr, creating a separate console.
+            #
+            # If we don't have access to stderr via procfs (for example when
+            # running inside a container), print a warning and implicitly
+            # suppress the kernel errors redirection.
             qemuargs.extend(["-chardev", "file,path=/proc/self/fd/2,id=dmesg"])
             qemuargs.extend(["-device", arch.virtio_dev_type("serial")])
             qemuargs.extend(["-device", "virtconsole,chardev=dmesg"])
@@ -1841,6 +1891,28 @@
     # Load a normal kernel
     qemuargs.extend(["-kernel", kernel.kimg])
     if kernelargs:
+        if args.systemd:
+            init_environment_vars = []
+            for arg in kernelargs:
+                match = re.match(r"(virtme_.*)=(.*)", arg)
+                if not match:
+                    continue
+                
init_environment_vars.append(f"{match.group(1)}={match.group(2)}")
+            os.makedirs(CACHE_DIR, exist_ok=True)
+            with open(SERIAL_GETTY_FILE, "w", encoding="utf-8") as f:
+                f.write(
+                    f"""[Service]
+StandardInput=tty
+StandardOutput=tty
+TTYPath=/dev/%I
+TTYReset=yes
+TTYVHangup=yes
+Environment={shlex.join(init_environment_vars)}"""
+                )
+                if args.root == "/":
+                    
f.write(f"\nExecStart={guest_tools_path}/{virtme_init_cmd}")
+                else:
+                    
f.write(f"\nExecStart=/run/virtme/guesttools/{virtme_init_cmd}")
         qemuargs.extend(["-append", " ".join(quote_karg(a) for a in 
kernelargs)])
     if initrdpath is not None:
         qemuargs.extend(["-initrd", initrdpath])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virtme-ng-1.36/virtme/guest/virtme-init 
new/virtme-ng-1.37/virtme/guest/virtme-init
--- old/virtme-ng-1.36/virtme/guest/virtme-init 2025-05-11 16:37:00.000000000 
+0200
+++ new/virtme-ng-1.37/virtme/guest/virtme-init 2025-08-08 09:40:53.000000000 
+0200
@@ -19,8 +19,13 @@
 mount -t proc -o nosuid,noexec,nodev proc /proc/
 mount -t sysfs -o nosuid,noexec,nodev sys /sys/
 
-# Mount tmpfs dirs
-mount -t tmpfs -o mode=0755 run /run/
+if [[ $$ -eq 1 ]]; then
+    # only mount /run if systemd is not the init
+    if ! grep -q "run /run" /proc/mounts; then
+        # Mount tmpfs dirs
+        mount -t tmpfs -o mode=0755 run /run/
+    fi
+fi
 mkdir /run/tmp
 
 # Setup rw filesystem overlays
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virtme-ng-1.36/virtme_ng/run.py 
new/virtme-ng-1.37/virtme_ng/run.py
--- old/virtme-ng-1.36/virtme_ng/run.py 2025-05-11 16:37:00.000000000 +0200
+++ new/virtme-ng-1.37/virtme_ng/run.py 2025-08-08 09:40:53.000000000 +0200
@@ -29,7 +29,7 @@
 
 from virtme.util import SilentError, get_username
 from virtme_ng.mainline import KernelDownloader
-from virtme_ng.utils import CONF_FILE, spinner_decorator
+from virtme_ng.utils import get_conf, spinner_decorator
 from virtme_ng.version import VERSION
 
 
@@ -556,6 +556,12 @@
         + "or to launch this command instead of a prompt (--client).",
     )
 
+    parser.add_argument(
+        "--systemd",
+        action="store_true",
+        help="Execute systemd as init (EXPERIMENTAL)",
+    )
+
     return parser
 
 
@@ -675,32 +681,9 @@
 
     def __init__(self):
         self.virtme_param = {}
-        conf_path = self.get_conf_file_path()
-        self.default_opts = []
-        if conf_path is not None:
-            with open(conf_path, encoding="utf-8") as conf_fd:
-                conf_data = json.loads(conf_fd.read())
-                if "default_opts" in conf_data:
-                    self.default_opts = conf_data["default_opts"]
+        self.default_opts = get_conf("default_opts")
         self.cpus = str(os.cpu_count())
 
-    def get_conf_file_path(self):
-        """Return virtme-ng main configuration file path."""
-
-        # First check if there is a config file in the user's home config
-        # directory, then check for a single config file in ~/.virtme-ng.conf 
and
-        # finally check for /etc/virtme-ng.conf. If none of them exist, report 
an
-        # error and exit.
-        configs = (
-            CONF_FILE,
-            Path(Path.home(), ".virtme-ng.conf"),
-            Path("/etc", "virtme-ng.conf"),
-        )
-        for conf in configs:
-            if conf.exists():
-                return conf
-        return None
-
     def _format_cmd(self, cmd):
         return shlex.split(cmd)
 
@@ -948,6 +931,12 @@
         else:
             self.virtme_param["root"] = ""
 
+    def _get_virtme_systemd(self, args):
+        if args.systemd:
+            self.virtme_param["systemd"] = "--systemd"
+        else:
+            self.virtme_param["systemd"] = ""
+
     def _get_virtme_rw(self, args):
         if args.rw:
             self.virtme_param["rw"] = "--rw"
@@ -1301,6 +1290,7 @@
         self._get_virtme_user(args)
         self._get_virtme_arch(args)
         self._get_virtme_root(args)
+        self._get_virtme_systemd(args)
         self._get_virtme_rw(args)
         self._get_virtme_rodir(args)
         self._get_virtme_rwdir(args)
@@ -1349,6 +1339,7 @@
             + f"{self.virtme_param['user']} "
             + f"{self.virtme_param['arch']} "
             + f"{self.virtme_param['root']} "
+            + f"{self.virtme_param['systemd']} "
             + f"{self.virtme_param['rw']} "
             + f"{self.virtme_param['rodir']} "
             + f"{self.virtme_param['rwdir']} "
@@ -1397,38 +1388,72 @@
         # Use QMP to generate a memory dump
         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         sock.connect(("localhost", 3636))
-        data = sock.recv(1024)
+        sock_f = sock.makefile(encoding="utf-8")
+        data = sock_f.readline()
         if not data:
+            sys.stderr.write("Dump failed")
             sys.exit(1)
         if args.verbose:
-            sys.stdout.write(data.decode("utf-8"))
-        sock.send(b'{ "execute": "qmp_capabilities" }\r')
-        data = sock.recv(1024)
+            sys.stdout.write(data)
+        # Exit "QEMU capabilities negotiation mode"
+        sock.send(json.dumps({"execute": "qmp_capabilities"}).encode("utf-8"))
+        data = sock_f.readline()
         if not data:
+            sys.stderr.write("Dump failed")
             sys.exit(1)
         if args.verbose:
-            sys.stdout.write(data.decode("utf-8"))
+            sys.stdout.write(data)
+        if json.loads(data) != {"return": {}}:
+            sys.stderr.write(f"Dump failed:\n{data}")
+            sys.exit(1)
         dump_file = args.dump
-        with tempfile.NamedTemporaryFile(delete=dump_file is None) as tmp:
-            msg = (
-                '{"execute":"dump-guest-memory",'
-                '"arguments":{"paging":true,'
-                '"protocol":"file:' + tmp.name + '"}}'
-                "\r"
+        with tempfile.NamedTemporaryFile(
+            delete=True, prefix="tmpvirtmedump_", 
dir=os.path.dirname(dump_file)
+        ) as tmp:
+            msg = json.dumps(
+                {
+                    "execute": "dump-guest-memory",
+                    "arguments": {"paging": True, "protocol": 
f"file:{tmp.name}"},
+                }
             )
             if args.verbose:
                 sys.stdout.write(msg + "\n")
             sock.send(msg.encode("utf-8"))
-            data = sock.recv(1024)
-            if not data:
-                sys.exit(1)
-            if args.verbose:
-                sys.stdout.write(data.decode("utf-8"))
-            data = sock.recv(1024)
-            if args.verbose:
-                sys.stdout.write(data.decode("utf-8"))
-            # Save memory dump to target file
-            shutil.move(tmp.name, dump_file)
+            while True:
+                data = sock_f.readline()
+                if not data:
+                    sys.stderr.write("Dump failed")
+                    sys.exit(1)
+                if args.verbose:
+                    sys.stdout.write(data)
+                try:
+                    data_json = json.loads(data)
+                except json.decoder.JSONDecodeError:
+                    sys.stderr.write(f"Dump failed:\n{data}")
+                    sys.exit(1)
+
+                # e.g. {"error": {"class": "GenericError", "desc": "Could not 
create 'bla.elf': Permission denied"}}
+                if "error" in data_json:
+                    sys.stderr.write(f"Dump failed:\n{data}")
+                    sys.exit(1)
+
+                if data_json.get("event", "") != "DUMP_COMPLETED":
+                    continue
+
+                # Save memory dump to target file
+                shutil.move(tmp.name, dump_file)
+
+                # e.g. {"timestamp": {"seconds": 1747057595, "microseconds": 
633224}, "event": "DUMP_COMPLETED", "data":
+                # {"result": {"total": 1073741824, "status": "failed", 
"completed": 305700864}, "error": "dump: failed
+                # to save memory: No space left on device"}}
+                if "error" in data_json["data"]:
+                    sys.stderr.write(f"Dump failed:\n{data}")
+                    sys.exit(1)
+
+                # We're done, e.g. {"timestamp": {"seconds": 1747057073, 
"microseconds": 930833}, "event":
+                # "DUMP_COMPLETED", "data": {"result": {"total": 1073741824, 
"status": "completed", "completed":
+                # 1073741824}}}
+                break
 
     def clean(self, args):
         """Clean a local or remote git repository."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virtme-ng-1.36/virtme_ng/utils.py 
new/virtme-ng-1.37/virtme_ng/utils.py
--- old/virtme-ng-1.36/virtme_ng/utils.py       2025-05-11 16:37:00.000000000 
+0200
+++ new/virtme-ng-1.37/virtme_ng/utils.py       2025-08-08 09:40:53.000000000 
+0200
@@ -3,6 +3,7 @@
 
 """virtme-ng: configuration path."""
 
+import json
 from pathlib import Path
 
 from virtme_ng.spinner import Spinner
@@ -15,6 +16,18 @@
 DEFAULT_VIRTME_SSH_HOSTNAME_CID_SEPARATOR = 
VIRTME_SSH_HOSTNAME_CID_SEPARATORS[0]
 CONF_PATH = Path(Path.home(), ".config", "virtme-ng")
 CONF_FILE = Path(CONF_PATH, "virtme-ng.conf")
+SERIAL_GETTY_FILE = Path(CACHE_DIR, "serial-getty@.service")
+
+# NOTE: this must stay in sync with README.md
+CONF_DEFAULT = {
+    "default_opts": {},
+    "systemd": {
+        "masks": [
+            # disable getty@, since we're forcing the use of serial-getty@
+            "getty@"
+        ]
+    },
+}
 
 
 def spinner_decorator(message):
@@ -27,3 +40,46 @@
         return wrapper
 
     return decorator
+
+
+def get_conf_obj():
+    """Return virtme-ng main configuration, returning the default if not 
found."""
+
+    # First check if there is a config file in the user's home config
+    # directory, then check for a single config file in ~/.virtme-ng.conf and
+    # finally check for /etc/virtme-ng.conf. If none of them exist, return the
+    # default configuration.
+    conf_paths = (
+        CONF_FILE,
+        Path(Path.home(), ".virtme-ng.conf"),
+        Path("/etc", "virtme-ng.conf"),
+    )
+    for conf_path in conf_paths:
+        if conf_path.exists():
+            with open(conf_path, encoding="utf-8") as conf_fd:
+                conf = json.loads(conf_fd.read())
+                return conf
+    return CONF_DEFAULT
+
+
+def get_conf(key_path):
+    """Return a configured value for a key_path, which might be nested
+
+    >>> get_conf("default_opts")
+    {}
+    >>> get_conf("systemd")
+    {'masks': ["getty@"]}
+    >>> get_conf("systemd.masks")
+    ["getty@"]
+    """
+    keys = key_path.split(".")
+    conf = get_conf_obj()
+    try:
+        for key in keys:
+            conf = conf[key]
+        return conf
+    except (KeyError, TypeError):
+        conf = CONF_DEFAULT
+        for key in keys:
+            conf = conf[key]
+        return conf
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virtme-ng-1.36/virtme_ng/version.py 
new/virtme-ng-1.37/virtme_ng/version.py
--- old/virtme-ng-1.36/virtme_ng/version.py     2025-05-11 16:37:00.000000000 
+0200
+++ new/virtme-ng-1.37/virtme_ng/version.py     2025-08-08 09:40:53.000000000 
+0200
@@ -7,7 +7,7 @@
 from importlib.metadata import PackageNotFoundError, version
 from subprocess import DEVNULL, CalledProcessError, check_output
 
-PKG_VERSION = "1.36"
+PKG_VERSION = "1.37"
 
 
 def get_package_version():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/virtme-ng-1.36/virtme_ng_init/src/main.rs 
new/virtme-ng-1.37/virtme_ng_init/src/main.rs
--- old/virtme-ng-1.36/virtme_ng_init/src/main.rs       2025-05-11 
16:37:00.000000000 +0200
+++ new/virtme-ng-1.37/virtme_ng_init/src/main.rs       2025-08-08 
09:40:53.000000000 +0200
@@ -192,13 +192,6 @@
 
 const USER_SCRIPT: &str = "/run/tmp/.virtme-script";
 
-fn check_init_pid() {
-    if id() != 1 {
-        log!("must be run as PID 1");
-        exit(1);
-    }
-}
-
 fn poweroff() {
     unsafe {
         libc::sync();
@@ -413,6 +406,10 @@
         // Note, get_test_tools_dir() relies on /proc, so that must be mounted
         // prior to /run.
         if mount_info.target == "/run" {
+            if id() != 1 {
+                // systemd is the current init, skip mounting /run
+                continue;
+            }
             if let Some(guest_tools_dir) = get_guest_tools_dir() {
                 if guest_tools_dir.starts_with("/run") {
                     log!("/run previously mounted, skipping");
@@ -1106,9 +1103,6 @@
 }
 
 fn main() {
-    // Make sure to always run as PID 1.
-    check_init_pid();
-
     // Basic system initialization (order is important here).
     configure_environment();
     configure_hostname();

Reply via email to