Without the --mount-proc option, calling `systemctl daemon-reload` in the chroot prints out "Running in chroot, ignoring command 'daemon-reload'" and then exits with status 0. With the --mount-proc option, calling `systemctl daemon-reload` in the chroot fails with "Failed to connect to bus: No data available" and fails with status 100. To determine if we are running in a chroot, systemd calls fstatat(2) on / and then fstatat(2) on /proc/1/root. It then compares the resulting structures, looking specially at the inode number, inode type and backing device. If anything looks different, systemd assumes we are in a chroot. Using stat(1), we can observe what happens: Without the --mount-proc option, the backing device (i.e. "Device") is different, therefore systemd assumes we are in a chroot: # stat -L / /proc/1/root File: / Size: 4096 Blocks: 8 IO Block: 4096 directory => Device: 252,0 Inode: 2 Links: 20 Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2024-03-11 08:01:50.538756312 +0000 Modify: 2024-03-11 08:01:49.398777854 +0000 Change: 2024-03-11 08:01:49.398777854 +0000 Birth: 2024-03-11 08:00:36.000000000 +0000 File: /proc/1/root Size: 260 Blocks: 0 IO Block: 4096 directory => Device: 0,28 Inode: 2 Links: 1 Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2024-03-11 08:06:22.017527026 +0000 Modify: 2024-03-11 08:00:26.458886048 +0000 Change: 2024-03-11 08:00:26.458886048 +0000 Birth: 2024-03-11 07:58:30.876000000 +0000 But with the --mount-proc option, the structures look identical, therefore systemd thinks we are not running in a chroot: File: / Size: 4096 Blocks: 8 IO Block: 4096 directory => Device: 252,0 Inode: 2 Links: 20 Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2024-03-11 08:01:50.538756312 +0000 Modify: 2024-03-11 08:01:49.398777854 +0000 Change: 2024-03-11 08:01:49.398777854 +0000 Birth: 2024-03-11 08:00:36.000000000 +0000 File: /proc/1/root Size: 4096 Blocks: 8 IO Block: 4096 directory => Device: 252,0 Inode: 2 Links: 20 Access: (0755/drwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2024-03-11 08:01:50.538756312 +0000 Modify: 2024-03-11 08:01:49.398777854 +0000 Change: 2024-03-11 08:01:49.398777854 +0000 Birth: 2024-03-11 08:00:36.000000000 +0000 Explanation ----------- * When we run a command in a ChrootableTarget, we have: ** /proc bind mounted to /target/proc ** /sys bind mounted to /target/sys ** /run bind mounted to /target/run ** /dev bind mounted to /target/dev * When we run, `unshare --pid --fork chroot /target apt-get ...` ** the content of /target/proc is inherited from outside the chroot, because of the bind-mount. ** /target/proc/1 corresponds to the process with PID 1 in the "parent" PID namespace (which is the systemd/init process) ** /target/proc/1/root is therefore the "root" of the systemd process, which is outside of the chroot ** in other words /target/proc/1/root == / ** systemd effectively compares /target/proc/1/root with /target and since they are different, it assumes we are in a chroot. * When we run, `unshare --pid --fork --mount-proc=/target chroot /target apt-get ...` ** the content of /target/proc is fresh (the bind-mount is masked) ** /target/proc/1 corresponds to the process with PID 1 in the "child" PID namespace ** /target/proc/1/root is therefore the "root" of the chroot ** in other words /target/proc/1/root == /target ** systemd effectively compares /target/proc/1/root with /target and since they are identical, it assumes we are /not/ in a chroot.