2018-09-18 09:20:24 +00:00
|
|
|
#!/usr/bin/perl
|
|
|
|
#
|
2023-01-04 06:24:14 +00:00
|
|
|
# © 2018 - 2023 Johannes Schauer Marin Rodrigues <josch@mister-muffin.de>
|
2018-09-18 09:20:24 +00:00
|
|
|
#
|
|
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
# of this software and associated documentation files (the "Software"), to
|
|
|
|
# deal in the Software without restriction, including without limitation the
|
|
|
|
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
# sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
# furnished to do so, subject to the following conditions:
|
|
|
|
#
|
|
|
|
# The above copyright notice and this permission notice shall be included in
|
|
|
|
# all copies or substantial portions of the Software.
|
2019-11-13 10:53:30 +00:00
|
|
|
#
|
|
|
|
# The software is provided "as is", without warranty of any kind, express or
|
|
|
|
# implied, including but not limited to the warranties of merchantability,
|
|
|
|
# fitness for a particular purpose and noninfringement. In no event shall the
|
|
|
|
# authors or copyright holders be liable for any claim, damages or other
|
|
|
|
# liability, whether in an action of contract, tort or otherwise, arising
|
|
|
|
# from, out of or in connection with the software or the use or other dealings
|
|
|
|
# in the software.
|
2018-09-18 09:20:24 +00:00
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
|
2024-10-28 08:16:58 +00:00
|
|
|
our $VERSION = '1.5.4';
|
2019-02-23 07:55:31 +00:00
|
|
|
|
2018-09-18 09:20:24 +00:00
|
|
|
use English;
|
|
|
|
use Getopt::Long;
|
|
|
|
use Pod::Usage;
|
|
|
|
use File::Copy;
|
2021-10-06 19:20:41 +00:00
|
|
|
use File::Path qw(make_path);
|
2018-09-18 09:20:24 +00:00
|
|
|
use File::Temp qw(tempfile tempdir);
|
2019-12-09 09:40:51 +00:00
|
|
|
use File::Basename;
|
2020-06-23 20:45:17 +00:00
|
|
|
use File::Find;
|
2020-11-13 18:02:41 +00:00
|
|
|
use Cwd qw(abs_path getcwd);
|
2022-10-16 20:03:06 +00:00
|
|
|
require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
|
|
|
|
require "sys/ioctl.ph"; ## no critic (Modules::RequireBarewordIncludes)
|
2024-06-02 06:46:59 +00:00
|
|
|
use Fcntl
|
|
|
|
qw(S_IFCHR S_IFBLK FD_CLOEXEC F_GETFD F_SETFD LOCK_EX O_RDONLY O_DIRECTORY);
|
2018-09-23 17:36:07 +00:00
|
|
|
use List::Util qw(any none);
|
2022-07-28 14:58:47 +00:00
|
|
|
use POSIX
|
|
|
|
qw(SIGINT SIGHUP SIGPIPE SIGTERM SIG_BLOCK SIG_UNBLOCK strftime isatty);
|
2019-01-20 09:39:01 +00:00
|
|
|
use Carp;
|
|
|
|
use Term::ANSIColor;
|
2019-12-09 09:40:51 +00:00
|
|
|
use Socket;
|
2020-08-25 14:06:05 +00:00
|
|
|
use Time::HiRes;
|
2021-05-04 13:01:25 +00:00
|
|
|
use Math::BigInt;
|
2022-11-08 12:02:47 +00:00
|
|
|
use Text::ParseWords;
|
2024-05-12 15:16:51 +00:00
|
|
|
use Digest::SHA;
|
2020-08-15 16:09:06 +00:00
|
|
|
use version;
|
2018-09-18 09:20:24 +00:00
|
|
|
|
2020-01-09 07:39:40 +00:00
|
|
|
## no critic (InputOutput::RequireBriefOpen)
|
|
|
|
|
2018-09-18 09:20:24 +00:00
|
|
|
# from sched.h
|
2020-01-09 07:39:40 +00:00
|
|
|
# use typeglob constants because "use constant" has several drawback as
|
|
|
|
# explained in the documentation for the Readonly CPAN module
|
2021-01-13 17:40:24 +00:00
|
|
|
*CLONE_NEWNS = \0x20000; # mount namespace
|
|
|
|
*CLONE_NEWUTS = \0x4000000; # utsname
|
|
|
|
*CLONE_NEWIPC = \0x8000000; # ipc
|
|
|
|
*CLONE_NEWUSER = \0x10000000; # user
|
|
|
|
*CLONE_NEWPID = \0x20000000; # pid
|
|
|
|
*CLONE_NEWNET = \0x40000000; # net
|
|
|
|
*_LINUX_CAPABILITY_VERSION_3 = \0x20080522;
|
|
|
|
*CAP_SYS_ADMIN = \21;
|
2021-08-27 09:53:11 +00:00
|
|
|
*PR_CAPBSET_READ = \23;
|
2022-11-14 08:59:59 +00:00
|
|
|
# from sys/mount.h
|
|
|
|
*MS_BIND = \0x1000;
|
|
|
|
*MS_REC = \0x4000;
|
|
|
|
*MNT_DETACH = \2;
|
2024-05-12 15:16:51 +00:00
|
|
|
# uuid_t NameSpace_DNS in rfc4122
|
|
|
|
*UUID_NS_DNS = \'6ba7b810-9dad-11d1-80b4-00c04fd430c8';
|
2021-08-27 09:53:11 +00:00
|
|
|
our (
|
|
|
|
$CLONE_NEWNS, $CLONE_NEWUTS,
|
|
|
|
$CLONE_NEWIPC, $CLONE_NEWUSER,
|
|
|
|
$CLONE_NEWPID, $CLONE_NEWNET,
|
|
|
|
$_LINUX_CAPABILITY_VERSION_3, $CAP_SYS_ADMIN,
|
2022-11-14 08:59:59 +00:00
|
|
|
$PR_CAPBSET_READ, $MS_BIND,
|
2024-05-12 15:16:51 +00:00
|
|
|
$MS_REC, $MNT_DETACH,
|
|
|
|
$UUID_NS_DNS
|
2021-08-27 09:53:11 +00:00
|
|
|
);
|
2018-09-18 09:20:24 +00:00
|
|
|
|
2021-03-08 07:04:35 +00:00
|
|
|
#<<<
|
2018-09-18 09:20:24 +00:00
|
|
|
# type codes:
|
|
|
|
# 0 -> normal file
|
|
|
|
# 1 -> hardlink
|
|
|
|
# 2 -> symlink
|
|
|
|
# 3 -> character special
|
|
|
|
# 4 -> block special
|
|
|
|
# 5 -> directory
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
my @linuxdevfiles = (
|
|
|
|
# file name mode type link target major minor transl.
|
|
|
|
["./dev/", oct(755), '5', undef, undef, undef, undef],
|
|
|
|
["./dev/console", oct(666), '3', undef, 5, 1, undef],
|
|
|
|
["./dev/fd", oct(777), '2', '/proc/self/fd', undef, undef, undef],
|
|
|
|
["./dev/full", oct(666), '3', undef, 1, 7, undef],
|
|
|
|
["./dev/null", oct(666), '3', undef, 1, 3, undef],
|
|
|
|
["./dev/ptmx", oct(666), '3', undef, 5, 2, undef],
|
|
|
|
["./dev/pts/", oct(755), '5', undef, undef, undef, undef],
|
|
|
|
["./dev/random", oct(666), '3', undef, 1, 8, undef],
|
|
|
|
["./dev/shm/", oct(755), '5', undef, undef, undef, undef],
|
|
|
|
["./dev/stderr", oct(777), '2', '/proc/self/fd/2', undef, undef, undef],
|
|
|
|
["./dev/stdin", oct(777), '2', '/proc/self/fd/0', undef, undef, undef],
|
|
|
|
["./dev/stdout", oct(777), '2', '/proc/self/fd/1', undef, undef, undef],
|
|
|
|
["./dev/tty", oct(666), '3', undef, 5, 0, undef],
|
|
|
|
["./dev/urandom", oct(666), '3', undef, 1, 9, undef],
|
|
|
|
["./dev/zero", oct(666), '3', undef, 1, 5, undef],
|
|
|
|
);
|
|
|
|
|
|
|
|
my @hurdfiles = (
|
|
|
|
# file name mode type link target major minor transl.
|
|
|
|
['./dev/', oct(755), '5', undef, undef, undef, undef],
|
|
|
|
['./dev/MAKEDEV', oct(755), '2', '/sbin/MAKEDEV', undef, undef, undef],
|
|
|
|
['./dev/cd0', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0@/dev/disk:cd0\0"],
|
|
|
|
['./dev/cd1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0@/dev/disk:cd1\0"],
|
|
|
|
['./dev/com0', oct(600), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/com0\0device\0com0\0"],
|
|
|
|
['./dev/com1', oct(600), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/com1\0device\0com1\0"],
|
|
|
|
['./dev/com2', oct(600), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/com2\0device\0com2\0"],
|
|
|
|
['./dev/com3', oct(600), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/com3\0device\0com3\0"],
|
|
|
|
['./dev/cons', oct(600), '0', undef, undef, undef, undef],
|
|
|
|
['./dev/console', oct(600), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/console\0device\0console\0"],
|
|
|
|
['./dev/disk', oct(755), '2', 'rumpdisk', undef, undef, undef],
|
|
|
|
['./dev/eth0', oct(660), '0', undef, undef, undef,
|
|
|
|
"/hurd/devnode\0-M\0/dev/net\0eth0\0"],
|
|
|
|
['./dev/eth1', oct(660), '0', undef, undef, undef,
|
|
|
|
"/hurd/devnode\0-M\0/dev/net\0eth1\0"],
|
|
|
|
['./dev/eth2', oct(660), '0', undef, undef, undef,
|
|
|
|
"/hurd/devnode\0-M\0/dev/net\0eth2\0"],
|
|
|
|
['./dev/eth3', oct(660), '0', undef, undef, undef,
|
|
|
|
"/hurd/devnode\0-M\0/dev/net\0eth3\0"],
|
|
|
|
['./dev/fd', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/magic\0--directory\0fd\0"],
|
|
|
|
['./dev/fd0', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0fd0\0"],
|
|
|
|
['./dev/fd1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0fd1\0"],
|
|
|
|
['./dev/full', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/null\0--full\0"],
|
|
|
|
['./dev/hd0', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0\0"],
|
|
|
|
['./dev/hd0s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s1\0"],
|
|
|
|
['./dev/hd0s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s10\0"],
|
|
|
|
['./dev/hd0s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s11\0"],
|
|
|
|
['./dev/hd0s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s12\0"],
|
|
|
|
['./dev/hd0s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s13\0"],
|
|
|
|
['./dev/hd0s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s14\0"],
|
|
|
|
['./dev/hd0s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s15\0"],
|
|
|
|
['./dev/hd0s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s16\0"],
|
|
|
|
['./dev/hd0s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s2\0"],
|
|
|
|
['./dev/hd0s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s3\0"],
|
|
|
|
['./dev/hd0s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s4\0"],
|
|
|
|
['./dev/hd0s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s5\0"],
|
|
|
|
['./dev/hd0s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s6\0"],
|
|
|
|
['./dev/hd0s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s7\0"],
|
|
|
|
['./dev/hd0s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s8\0"],
|
|
|
|
['./dev/hd0s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd0s9\0"],
|
|
|
|
['./dev/hd1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1\0"],
|
|
|
|
['./dev/hd1s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s1\0"],
|
|
|
|
['./dev/hd1s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s10\0"],
|
|
|
|
['./dev/hd1s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s11\0"],
|
|
|
|
['./dev/hd1s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s12\0"],
|
|
|
|
['./dev/hd1s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s13\0"],
|
|
|
|
['./dev/hd1s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s14\0"],
|
|
|
|
['./dev/hd1s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s15\0"],
|
|
|
|
['./dev/hd1s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s16\0"],
|
|
|
|
['./dev/hd1s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s2\0"],
|
|
|
|
['./dev/hd1s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s3\0"],
|
|
|
|
['./dev/hd1s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s4\0"],
|
|
|
|
['./dev/hd1s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s5\0"],
|
|
|
|
['./dev/hd1s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s6\0"],
|
|
|
|
['./dev/hd1s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s7\0"],
|
|
|
|
['./dev/hd1s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s8\0"],
|
|
|
|
['./dev/hd1s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd1s9\0"],
|
|
|
|
['./dev/hd2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2\0"],
|
|
|
|
['./dev/hd2s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s1\0"],
|
|
|
|
['./dev/hd2s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s10\0"],
|
|
|
|
['./dev/hd2s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s11\0"],
|
|
|
|
['./dev/hd2s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s12\0"],
|
|
|
|
['./dev/hd2s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s13\0"],
|
|
|
|
['./dev/hd2s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s14\0"],
|
|
|
|
['./dev/hd2s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s15\0"],
|
|
|
|
['./dev/hd2s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s16\0"],
|
|
|
|
['./dev/hd2s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s2\0"],
|
|
|
|
['./dev/hd2s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s3\0"],
|
|
|
|
['./dev/hd2s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s4\0"],
|
|
|
|
['./dev/hd2s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s5\0"],
|
|
|
|
['./dev/hd2s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s6\0"],
|
|
|
|
['./dev/hd2s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s7\0"],
|
|
|
|
['./dev/hd2s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s8\0"],
|
|
|
|
['./dev/hd2s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd2s9\0"],
|
|
|
|
['./dev/hd3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3\0"],
|
|
|
|
['./dev/hd3s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s1\0"],
|
|
|
|
['./dev/hd3s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s10\0"],
|
|
|
|
['./dev/hd3s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s11\0"],
|
|
|
|
['./dev/hd3s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s12\0"],
|
|
|
|
['./dev/hd3s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s13\0"],
|
|
|
|
['./dev/hd3s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s14\0"],
|
|
|
|
['./dev/hd3s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s15\0"],
|
|
|
|
['./dev/hd3s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s16\0"],
|
|
|
|
['./dev/hd3s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s2\0"],
|
|
|
|
['./dev/hd3s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s3\0"],
|
|
|
|
['./dev/hd3s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s4\0"],
|
|
|
|
['./dev/hd3s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s5\0"],
|
|
|
|
['./dev/hd3s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s6\0"],
|
|
|
|
['./dev/hd3s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s7\0"],
|
|
|
|
['./dev/hd3s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s8\0"],
|
|
|
|
['./dev/hd3s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd3s9\0"],
|
|
|
|
['./dev/hd4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4\0"],
|
|
|
|
['./dev/hd4s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s1\0"],
|
|
|
|
['./dev/hd4s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s10\0"],
|
|
|
|
['./dev/hd4s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s11\0"],
|
|
|
|
['./dev/hd4s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s12\0"],
|
|
|
|
['./dev/hd4s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s13\0"],
|
|
|
|
['./dev/hd4s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s14\0"],
|
|
|
|
['./dev/hd4s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s15\0"],
|
|
|
|
['./dev/hd4s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s16\0"],
|
|
|
|
['./dev/hd4s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s2\0"],
|
|
|
|
['./dev/hd4s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s3\0"],
|
|
|
|
['./dev/hd4s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s4\0"],
|
|
|
|
['./dev/hd4s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s5\0"],
|
|
|
|
['./dev/hd4s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s6\0"],
|
|
|
|
['./dev/hd4s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s7\0"],
|
|
|
|
['./dev/hd4s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s8\0"],
|
|
|
|
['./dev/hd4s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd4s9\0"],
|
|
|
|
['./dev/hd5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5\0"],
|
|
|
|
['./dev/hd5s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s1\0"],
|
|
|
|
['./dev/hd5s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s10\0"],
|
|
|
|
['./dev/hd5s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s11\0"],
|
|
|
|
['./dev/hd5s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s12\0"],
|
|
|
|
['./dev/hd5s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s13\0"],
|
|
|
|
['./dev/hd5s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s14\0"],
|
|
|
|
['./dev/hd5s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s15\0"],
|
|
|
|
['./dev/hd5s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s16\0"],
|
|
|
|
['./dev/hd5s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s2\0"],
|
|
|
|
['./dev/hd5s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s3\0"],
|
|
|
|
['./dev/hd5s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s4\0"],
|
|
|
|
['./dev/hd5s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s5\0"],
|
|
|
|
['./dev/hd5s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s6\0"],
|
|
|
|
['./dev/hd5s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s7\0"],
|
|
|
|
['./dev/hd5s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s8\0"],
|
|
|
|
['./dev/hd5s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0hd5s9\0"],
|
|
|
|
['./dev/kbd', oct(644), '2', 'cons/kbd', undef, undef, undef],
|
|
|
|
['./dev/klog', oct(660), '0', undef, undef, undef,
|
|
|
|
"/hurd/streamio\0kmsg\0"],
|
|
|
|
['./dev/loop0', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/null\0"],
|
|
|
|
['./dev/loop1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/null\0"],
|
|
|
|
['./dev/loop2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/null\0"],
|
|
|
|
['./dev/loop3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/null\0"],
|
|
|
|
['./dev/loop4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/null\0"],
|
|
|
|
['./dev/loop5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/null\0"],
|
|
|
|
['./dev/loop6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/null\0"],
|
|
|
|
['./dev/loop7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/null\0"],
|
|
|
|
['./dev/lpr0', oct(660), '0', undef, undef, undef,
|
|
|
|
"/hurd/streamio\0lpr0\0"],
|
|
|
|
['./dev/lpr1', oct(660), '0', undef, undef, undef,
|
|
|
|
"/hurd/streamio\0lpr1\0"],
|
|
|
|
['./dev/lpr2', oct(660), '0', undef, undef, undef,
|
|
|
|
"/hurd/streamio\0lpr2\0"],
|
|
|
|
['./dev/mem', oct(660), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0--no-cache\0mem\0"],
|
|
|
|
['./dev/mouse', oct(644), '2', 'cons/mouse', undef, undef, undef],
|
|
|
|
['./dev/net', oct(755), '2', 'netdde', undef, undef, undef],
|
|
|
|
['./dev/netdde', oct(660), '0', undef, undef, undef,
|
|
|
|
"/hurd/netdde\0"],
|
|
|
|
['./dev/null', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/null\0"],
|
|
|
|
['./dev/pseudo-root', oct(640), '4', undef, 0, 0,
|
|
|
|
"/hurd/storeio\0pseudo-root\0"],
|
|
|
|
['./dev/ptyp0', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyp0\0pty-master\0/dev/ttyp0\0"],
|
|
|
|
['./dev/ptyp1', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyp1\0pty-master\0/dev/ttyp1\0"],
|
|
|
|
['./dev/ptyp2', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyp2\0pty-master\0/dev/ttyp2\0"],
|
|
|
|
['./dev/ptyp3', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyp3\0pty-master\0/dev/ttyp3\0"],
|
|
|
|
['./dev/ptyp4', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyp4\0pty-master\0/dev/ttyp4\0"],
|
|
|
|
['./dev/ptyp5', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyp5\0pty-master\0/dev/ttyp5\0"],
|
|
|
|
['./dev/ptyp6', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyp6\0pty-master\0/dev/ttyp6\0"],
|
|
|
|
['./dev/ptyp7', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyp7\0pty-master\0/dev/ttyp7\0"],
|
|
|
|
['./dev/ptyp8', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyp8\0pty-master\0/dev/ttyp8\0"],
|
|
|
|
['./dev/ptyp9', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyp9\0pty-master\0/dev/ttyp9\0"],
|
|
|
|
['./dev/ptypa', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypa\0pty-master\0/dev/ttypa\0"],
|
|
|
|
['./dev/ptypb', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypb\0pty-master\0/dev/ttypb\0"],
|
|
|
|
['./dev/ptypc', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypc\0pty-master\0/dev/ttypc\0"],
|
|
|
|
['./dev/ptypd', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypd\0pty-master\0/dev/ttypd\0"],
|
|
|
|
['./dev/ptype', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptype\0pty-master\0/dev/ttype\0"],
|
|
|
|
['./dev/ptypf', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypf\0pty-master\0/dev/ttypf\0"],
|
|
|
|
['./dev/ptypg', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypg\0pty-master\0/dev/ttypg\0"],
|
|
|
|
['./dev/ptyph', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyph\0pty-master\0/dev/ttyph\0"],
|
|
|
|
['./dev/ptypi', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypi\0pty-master\0/dev/ttypi\0"],
|
|
|
|
['./dev/ptypj', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypj\0pty-master\0/dev/ttypj\0"],
|
|
|
|
['./dev/ptypk', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypk\0pty-master\0/dev/ttypk\0"],
|
|
|
|
['./dev/ptypl', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypl\0pty-master\0/dev/ttypl\0"],
|
|
|
|
['./dev/ptypm', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypm\0pty-master\0/dev/ttypm\0"],
|
|
|
|
['./dev/ptypn', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypn\0pty-master\0/dev/ttypn\0"],
|
|
|
|
['./dev/ptypo', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypo\0pty-master\0/dev/ttypo\0"],
|
|
|
|
['./dev/ptypp', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypp\0pty-master\0/dev/ttypp\0"],
|
|
|
|
['./dev/ptypq', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypq\0pty-master\0/dev/ttypq\0"],
|
|
|
|
['./dev/ptypr', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypr\0pty-master\0/dev/ttypr\0"],
|
|
|
|
['./dev/ptyps', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyps\0pty-master\0/dev/ttyps\0"],
|
|
|
|
['./dev/ptypt', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypt\0pty-master\0/dev/ttypt\0"],
|
|
|
|
['./dev/ptypu', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypu\0pty-master\0/dev/ttypu\0"],
|
|
|
|
['./dev/ptypv', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptypv\0pty-master\0/dev/ttypv\0"],
|
|
|
|
['./dev/ptyq0', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyq0\0pty-master\0/dev/ttyq0\0"],
|
|
|
|
['./dev/ptyq1', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyq1\0pty-master\0/dev/ttyq1\0"],
|
|
|
|
['./dev/ptyq2', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyq2\0pty-master\0/dev/ttyq2\0"],
|
|
|
|
['./dev/ptyq3', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyq3\0pty-master\0/dev/ttyq3\0"],
|
|
|
|
['./dev/ptyq4', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyq4\0pty-master\0/dev/ttyq4\0"],
|
|
|
|
['./dev/ptyq5', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyq5\0pty-master\0/dev/ttyq5\0"],
|
|
|
|
['./dev/ptyq6', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyq6\0pty-master\0/dev/ttyq6\0"],
|
|
|
|
['./dev/ptyq7', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyq7\0pty-master\0/dev/ttyq7\0"],
|
|
|
|
['./dev/ptyq8', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyq8\0pty-master\0/dev/ttyq8\0"],
|
|
|
|
['./dev/ptyq9', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyq9\0pty-master\0/dev/ttyq9\0"],
|
|
|
|
['./dev/ptyqa', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqa\0pty-master\0/dev/ttyqa\0"],
|
|
|
|
['./dev/ptyqb', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqb\0pty-master\0/dev/ttyqb\0"],
|
|
|
|
['./dev/ptyqc', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqc\0pty-master\0/dev/ttyqc\0"],
|
|
|
|
['./dev/ptyqd', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqd\0pty-master\0/dev/ttyqd\0"],
|
|
|
|
['./dev/ptyqe', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqe\0pty-master\0/dev/ttyqe\0"],
|
|
|
|
['./dev/ptyqf', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqf\0pty-master\0/dev/ttyqf\0"],
|
|
|
|
['./dev/ptyqg', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqg\0pty-master\0/dev/ttyqg\0"],
|
|
|
|
['./dev/ptyqh', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqh\0pty-master\0/dev/ttyqh\0"],
|
|
|
|
['./dev/ptyqi', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqi\0pty-master\0/dev/ttyqi\0"],
|
|
|
|
['./dev/ptyqj', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqj\0pty-master\0/dev/ttyqj\0"],
|
|
|
|
['./dev/ptyqk', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqk\0pty-master\0/dev/ttyqk\0"],
|
|
|
|
['./dev/ptyql', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyql\0pty-master\0/dev/ttyql\0"],
|
|
|
|
['./dev/ptyqm', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqm\0pty-master\0/dev/ttyqm\0"],
|
|
|
|
['./dev/ptyqn', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqn\0pty-master\0/dev/ttyqn\0"],
|
|
|
|
['./dev/ptyqo', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqo\0pty-master\0/dev/ttyqo\0"],
|
|
|
|
['./dev/ptyqp', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqp\0pty-master\0/dev/ttyqp\0"],
|
|
|
|
['./dev/ptyqq', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqq\0pty-master\0/dev/ttyqq\0"],
|
|
|
|
['./dev/ptyqr', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqr\0pty-master\0/dev/ttyqr\0"],
|
|
|
|
['./dev/ptyqs', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqs\0pty-master\0/dev/ttyqs\0"],
|
|
|
|
['./dev/ptyqt', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqt\0pty-master\0/dev/ttyqt\0"],
|
|
|
|
['./dev/ptyqu', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqu\0pty-master\0/dev/ttyqu\0"],
|
|
|
|
['./dev/ptyqv', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ptyqv\0pty-master\0/dev/ttyqv\0"],
|
|
|
|
['./dev/random', oct(644), '0', undef, undef, undef,
|
|
|
|
"/hurd/random\0--seed-file\0/var/lib/random-seed\0"],
|
|
|
|
['./dev/rumpdisk', oct(660), '0', undef, undef, undef,
|
|
|
|
"/hurd/rumpdisk\0"],
|
|
|
|
['./dev/sd0', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0\0"],
|
|
|
|
['./dev/sd0s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s1\0"],
|
|
|
|
['./dev/sd0s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s10\0"],
|
|
|
|
['./dev/sd0s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s11\0"],
|
|
|
|
['./dev/sd0s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s12\0"],
|
|
|
|
['./dev/sd0s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s13\0"],
|
|
|
|
['./dev/sd0s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s14\0"],
|
|
|
|
['./dev/sd0s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s15\0"],
|
|
|
|
['./dev/sd0s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s16\0"],
|
|
|
|
['./dev/sd0s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s2\0"],
|
|
|
|
['./dev/sd0s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s3\0"],
|
|
|
|
['./dev/sd0s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s4\0"],
|
|
|
|
['./dev/sd0s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s5\0"],
|
|
|
|
['./dev/sd0s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s6\0"],
|
|
|
|
['./dev/sd0s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s7\0"],
|
|
|
|
['./dev/sd0s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s8\0"],
|
|
|
|
['./dev/sd0s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd0s9\0"],
|
|
|
|
['./dev/sd1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1\0"],
|
|
|
|
['./dev/sd1s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s1\0"],
|
|
|
|
['./dev/sd1s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s10\0"],
|
|
|
|
['./dev/sd1s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s11\0"],
|
|
|
|
['./dev/sd1s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s12\0"],
|
|
|
|
['./dev/sd1s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s13\0"],
|
|
|
|
['./dev/sd1s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s14\0"],
|
|
|
|
['./dev/sd1s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s15\0"],
|
|
|
|
['./dev/sd1s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s16\0"],
|
|
|
|
['./dev/sd1s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s2\0"],
|
|
|
|
['./dev/sd1s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s3\0"],
|
|
|
|
['./dev/sd1s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s4\0"],
|
|
|
|
['./dev/sd1s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s5\0"],
|
|
|
|
['./dev/sd1s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s6\0"],
|
|
|
|
['./dev/sd1s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s7\0"],
|
|
|
|
['./dev/sd1s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s8\0"],
|
|
|
|
['./dev/sd1s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd1s9\0"],
|
|
|
|
['./dev/sd2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2\0"],
|
|
|
|
['./dev/sd2s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s1\0"],
|
|
|
|
['./dev/sd2s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s10\0"],
|
|
|
|
['./dev/sd2s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s11\0"],
|
|
|
|
['./dev/sd2s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s12\0"],
|
|
|
|
['./dev/sd2s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s13\0"],
|
|
|
|
['./dev/sd2s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s14\0"],
|
|
|
|
['./dev/sd2s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s15\0"],
|
|
|
|
['./dev/sd2s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s16\0"],
|
|
|
|
['./dev/sd2s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s2\0"],
|
|
|
|
['./dev/sd2s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s3\0"],
|
|
|
|
['./dev/sd2s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s4\0"],
|
|
|
|
['./dev/sd2s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s5\0"],
|
|
|
|
['./dev/sd2s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s6\0"],
|
|
|
|
['./dev/sd2s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s7\0"],
|
|
|
|
['./dev/sd2s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s8\0"],
|
|
|
|
['./dev/sd2s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd2s9\0"],
|
|
|
|
['./dev/sd3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3\0"],
|
|
|
|
['./dev/sd3s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s1\0"],
|
|
|
|
['./dev/sd3s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s10\0"],
|
|
|
|
['./dev/sd3s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s11\0"],
|
|
|
|
['./dev/sd3s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s12\0"],
|
|
|
|
['./dev/sd3s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s13\0"],
|
|
|
|
['./dev/sd3s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s14\0"],
|
|
|
|
['./dev/sd3s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s15\0"],
|
|
|
|
['./dev/sd3s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s16\0"],
|
|
|
|
['./dev/sd3s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s2\0"],
|
|
|
|
['./dev/sd3s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s3\0"],
|
|
|
|
['./dev/sd3s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s4\0"],
|
|
|
|
['./dev/sd3s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s5\0"],
|
|
|
|
['./dev/sd3s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s6\0"],
|
|
|
|
['./dev/sd3s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s7\0"],
|
|
|
|
['./dev/sd3s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s8\0"],
|
|
|
|
['./dev/sd3s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd3s9\0"],
|
|
|
|
['./dev/sd4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4\0"],
|
|
|
|
['./dev/sd4s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s1\0"],
|
|
|
|
['./dev/sd4s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s10\0"],
|
|
|
|
['./dev/sd4s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s11\0"],
|
|
|
|
['./dev/sd4s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s12\0"],
|
|
|
|
['./dev/sd4s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s13\0"],
|
|
|
|
['./dev/sd4s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s14\0"],
|
|
|
|
['./dev/sd4s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s15\0"],
|
|
|
|
['./dev/sd4s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s16\0"],
|
|
|
|
['./dev/sd4s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s2\0"],
|
|
|
|
['./dev/sd4s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s3\0"],
|
|
|
|
['./dev/sd4s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s4\0"],
|
|
|
|
['./dev/sd4s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s5\0"],
|
|
|
|
['./dev/sd4s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s6\0"],
|
|
|
|
['./dev/sd4s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s7\0"],
|
|
|
|
['./dev/sd4s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s8\0"],
|
|
|
|
['./dev/sd4s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd4s9\0"],
|
|
|
|
['./dev/sd5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5\0"],
|
|
|
|
['./dev/sd5s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s1\0"],
|
|
|
|
['./dev/sd5s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s10\0"],
|
|
|
|
['./dev/sd5s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s11\0"],
|
|
|
|
['./dev/sd5s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s12\0"],
|
|
|
|
['./dev/sd5s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s13\0"],
|
|
|
|
['./dev/sd5s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s14\0"],
|
|
|
|
['./dev/sd5s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s15\0"],
|
|
|
|
['./dev/sd5s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s16\0"],
|
|
|
|
['./dev/sd5s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s2\0"],
|
|
|
|
['./dev/sd5s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s3\0"],
|
|
|
|
['./dev/sd5s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s4\0"],
|
|
|
|
['./dev/sd5s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s5\0"],
|
|
|
|
['./dev/sd5s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s6\0"],
|
|
|
|
['./dev/sd5s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s7\0"],
|
|
|
|
['./dev/sd5s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s8\0"],
|
|
|
|
['./dev/sd5s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0sd5s9\0"],
|
|
|
|
['./dev/shm', oct(644), '2', '/tmp', undef, undef, undef],
|
|
|
|
['./dev/stderr', oct(755), '2', 'fd/2', undef, undef, undef],
|
|
|
|
['./dev/stdin', oct(755), '2', 'fd/0', undef, undef, undef],
|
|
|
|
['./dev/stdout', oct(755), '2', 'fd/1', undef, undef, undef],
|
|
|
|
['./dev/time', oct(644), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0--no-cache\0time\0"],
|
|
|
|
['./dev/tty', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/magic\0tty\0"],
|
|
|
|
['./dev/tty1', oct(600), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/tty1\0hurdio\0/dev/vcs/1/console\0"],
|
|
|
|
['./dev/tty2', oct(600), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/tty2\0hurdio\0/dev/vcs/2/console\0"],
|
|
|
|
['./dev/tty3', oct(600), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/tty3\0hurdio\0/dev/vcs/3/console\0"],
|
|
|
|
['./dev/tty4', oct(600), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/tty4\0hurdio\0/dev/vcs/4/console\0"],
|
|
|
|
['./dev/tty5', oct(600), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/tty5\0hurdio\0/dev/vcs/5/console\0"],
|
|
|
|
['./dev/tty6', oct(600), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/tty6\0hurdio\0/dev/vcs/6/console\0"],
|
|
|
|
['./dev/ttyp0', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyp0\0pty-slave\0/dev/ptyp0\0"],
|
|
|
|
['./dev/ttyp1', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyp1\0pty-slave\0/dev/ptyp1\0"],
|
|
|
|
['./dev/ttyp2', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyp2\0pty-slave\0/dev/ptyp2\0"],
|
|
|
|
['./dev/ttyp3', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyp3\0pty-slave\0/dev/ptyp3\0"],
|
|
|
|
['./dev/ttyp4', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyp4\0pty-slave\0/dev/ptyp4\0"],
|
|
|
|
['./dev/ttyp5', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyp5\0pty-slave\0/dev/ptyp5\0"],
|
|
|
|
['./dev/ttyp6', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyp6\0pty-slave\0/dev/ptyp6\0"],
|
|
|
|
['./dev/ttyp7', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyp7\0pty-slave\0/dev/ptyp7\0"],
|
|
|
|
['./dev/ttyp8', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyp8\0pty-slave\0/dev/ptyp8\0"],
|
|
|
|
['./dev/ttyp9', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyp9\0pty-slave\0/dev/ptyp9\0"],
|
|
|
|
['./dev/ttypa', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypa\0pty-slave\0/dev/ptypa\0"],
|
|
|
|
['./dev/ttypb', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypb\0pty-slave\0/dev/ptypb\0"],
|
|
|
|
['./dev/ttypc', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypc\0pty-slave\0/dev/ptypc\0"],
|
|
|
|
['./dev/ttypd', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypd\0pty-slave\0/dev/ptypd\0"],
|
|
|
|
['./dev/ttype', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttype\0pty-slave\0/dev/ptype\0"],
|
|
|
|
['./dev/ttypf', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypf\0pty-slave\0/dev/ptypf\0"],
|
|
|
|
['./dev/ttypg', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypg\0pty-slave\0/dev/ptypg\0"],
|
|
|
|
['./dev/ttyph', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyph\0pty-slave\0/dev/ptyph\0"],
|
|
|
|
['./dev/ttypi', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypi\0pty-slave\0/dev/ptypi\0"],
|
|
|
|
['./dev/ttypj', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypj\0pty-slave\0/dev/ptypj\0"],
|
|
|
|
['./dev/ttypk', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypk\0pty-slave\0/dev/ptypk\0"],
|
|
|
|
['./dev/ttypl', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypl\0pty-slave\0/dev/ptypl\0"],
|
|
|
|
['./dev/ttypm', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypm\0pty-slave\0/dev/ptypm\0"],
|
|
|
|
['./dev/ttypn', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypn\0pty-slave\0/dev/ptypn\0"],
|
|
|
|
['./dev/ttypo', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypo\0pty-slave\0/dev/ptypo\0"],
|
|
|
|
['./dev/ttypp', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypp\0pty-slave\0/dev/ptypp\0"],
|
|
|
|
['./dev/ttypq', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypq\0pty-slave\0/dev/ptypq\0"],
|
|
|
|
['./dev/ttypr', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypr\0pty-slave\0/dev/ptypr\0"],
|
|
|
|
['./dev/ttyps', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyps\0pty-slave\0/dev/ptyps\0"],
|
|
|
|
['./dev/ttypt', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypt\0pty-slave\0/dev/ptypt\0"],
|
|
|
|
['./dev/ttypu', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypu\0pty-slave\0/dev/ptypu\0"],
|
|
|
|
['./dev/ttypv', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttypv\0pty-slave\0/dev/ptypv\0"],
|
|
|
|
['./dev/ttyq0', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyq0\0pty-slave\0/dev/ptyq0\0"],
|
|
|
|
['./dev/ttyq1', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyq1\0pty-slave\0/dev/ptyq1\0"],
|
|
|
|
['./dev/ttyq2', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyq2\0pty-slave\0/dev/ptyq2\0"],
|
|
|
|
['./dev/ttyq3', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyq3\0pty-slave\0/dev/ptyq3\0"],
|
|
|
|
['./dev/ttyq4', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyq4\0pty-slave\0/dev/ptyq4\0"],
|
|
|
|
['./dev/ttyq5', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyq5\0pty-slave\0/dev/ptyq5\0"],
|
|
|
|
['./dev/ttyq6', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyq6\0pty-slave\0/dev/ptyq6\0"],
|
|
|
|
['./dev/ttyq7', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyq7\0pty-slave\0/dev/ptyq7\0"],
|
|
|
|
['./dev/ttyq8', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyq8\0pty-slave\0/dev/ptyq8\0"],
|
|
|
|
['./dev/ttyq9', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyq9\0pty-slave\0/dev/ptyq9\0"],
|
|
|
|
['./dev/ttyqa', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqa\0pty-slave\0/dev/ptyqa\0"],
|
|
|
|
['./dev/ttyqb', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqb\0pty-slave\0/dev/ptyqb\0"],
|
|
|
|
['./dev/ttyqc', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqc\0pty-slave\0/dev/ptyqc\0"],
|
|
|
|
['./dev/ttyqd', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqd\0pty-slave\0/dev/ptyqd\0"],
|
|
|
|
['./dev/ttyqe', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqe\0pty-slave\0/dev/ptyqe\0"],
|
|
|
|
['./dev/ttyqf', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqf\0pty-slave\0/dev/ptyqf\0"],
|
|
|
|
['./dev/ttyqg', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqg\0pty-slave\0/dev/ptyqg\0"],
|
|
|
|
['./dev/ttyqh', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqh\0pty-slave\0/dev/ptyqh\0"],
|
|
|
|
['./dev/ttyqi', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqi\0pty-slave\0/dev/ptyqi\0"],
|
|
|
|
['./dev/ttyqj', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqj\0pty-slave\0/dev/ptyqj\0"],
|
|
|
|
['./dev/ttyqk', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqk\0pty-slave\0/dev/ptyqk\0"],
|
|
|
|
['./dev/ttyql', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyql\0pty-slave\0/dev/ptyql\0"],
|
|
|
|
['./dev/ttyqm', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqm\0pty-slave\0/dev/ptyqm\0"],
|
|
|
|
['./dev/ttyqn', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqn\0pty-slave\0/dev/ptyqn\0"],
|
|
|
|
['./dev/ttyqo', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqo\0pty-slave\0/dev/ptyqo\0"],
|
|
|
|
['./dev/ttyqp', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqp\0pty-slave\0/dev/ptyqp\0"],
|
|
|
|
['./dev/ttyqq', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqq\0pty-slave\0/dev/ptyqq\0"],
|
|
|
|
['./dev/ttyqr', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqr\0pty-slave\0/dev/ptyqr\0"],
|
|
|
|
['./dev/ttyqs', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqs\0pty-slave\0/dev/ptyqs\0"],
|
|
|
|
['./dev/ttyqt', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqt\0pty-slave\0/dev/ptyqt\0"],
|
|
|
|
['./dev/ttyqu', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqu\0pty-slave\0/dev/ptyqu\0"],
|
|
|
|
['./dev/ttyqv', oct(666), '0', undef, undef, undef,
|
|
|
|
"/hurd/term\0/dev/ttyqv\0pty-slave\0/dev/ptyqv\0"],
|
|
|
|
['./dev/urandom', oct(755), '2', 'random', undef, undef,
|
|
|
|
"/hurd/random\0--seed-file\0/var/lib/random-seed\0--fast\0"],
|
|
|
|
['./dev/vcs', oct(600), '0', undef, undef, undef,
|
|
|
|
"/hurd/console\0"],
|
|
|
|
['./dev/wd0', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:1:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:10:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:11:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:12:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:13:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:14:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:15:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:16:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:2:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:3:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:4:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:5:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:6:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:7:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:8:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd0s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:9:device:@/dev/disk:wd0\0"],
|
|
|
|
['./dev/wd1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:1:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:10:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:11:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:12:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:13:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:14:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:15:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:16:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:2:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:3:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:4:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:5:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:6:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:7:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:8:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd1s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:9:device:@/dev/disk:wd1\0"],
|
|
|
|
['./dev/wd2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:1:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:10:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:11:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:12:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:13:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:14:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:15:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:16:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:2:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:3:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:4:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:5:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:6:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:7:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:8:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd2s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:9:device:@/dev/disk:wd2\0"],
|
|
|
|
['./dev/wd3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:1:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:10:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:11:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:12:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:13:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:14:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:15:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:16:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:2:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:3:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:4:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:5:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:6:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:7:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:8:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd3s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:9:device:@/dev/disk:wd3\0"],
|
|
|
|
['./dev/wd4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:1:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:10:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:11:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:12:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:13:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:14:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:15:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:16:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:2:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:3:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:4:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:5:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:6:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:7:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:8:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd4s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:9:device:@/dev/disk:wd4\0"],
|
|
|
|
['./dev/wd5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s1', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:1:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s10', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:10:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s11', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:11:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s12', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:12:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s13', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:13:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s14', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:14:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s15', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:15:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s16', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:16:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s2', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:2:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s3', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:3:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s4', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:4:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s5', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:5:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s6', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:6:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s7', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:7:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s8', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:8:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/wd5s9', oct(640), '0', undef, undef, undef,
|
|
|
|
"/hurd/storeio\0-T\0typed\0part:9:device:@/dev/disk:wd5\0"],
|
|
|
|
['./dev/xconsole', oct(755), '2', '/run/xconsole', undef, undef, undef],
|
|
|
|
['./dev/zero', oct(666), '0', undef, undef, undef,
|
|
|
|
"/bin/nullauth\0--\0/hurd/storeio\0-Tzero\0"],
|
|
|
|
# file name mode type link tgt major minor transl.
|
|
|
|
['./servers/', oct(755), '5', undef, undef, undef, undef],
|
|
|
|
['./servers/acpi', oct(644), '0', undef, undef, undef,
|
|
|
|
"/hurd/acpi\0"],
|
|
|
|
['./servers/bus/', oct(755), '5', undef, undef, undef, undef],
|
|
|
|
['./servers/bus/pci/', oct(755), '5', undef, undef, undef,
|
|
|
|
"/hurd/pci-arbiter\0"],
|
|
|
|
['./servers/crash', oct(644), '2', 'crash-dump-core', undef, undef,
|
|
|
|
undef],
|
|
|
|
['./servers/crash-dump-core', oct(644), '0', undef, undef, undef,
|
|
|
|
"/hurd/crash\0--dump-core\0"],
|
|
|
|
['./servers/crash-kill', oct(644), '0', undef, undef, undef,
|
|
|
|
"/hurd/crash\0--kill\0"],
|
|
|
|
['./servers/crash-suspend', oct(644), '0', undef, undef, undef,
|
|
|
|
"/hurd/crash\0--suspend\0"],
|
|
|
|
['./servers/default-pager', oct(755), '0', undef, undef, undef,
|
|
|
|
"/hurd/proxy-defpager\0"],
|
|
|
|
['./servers/exec', oct(644), '0', undef, undef, undef,
|
|
|
|
"/hurd/exec\0"],
|
|
|
|
['./servers/password', oct(644), '0', undef, undef, undef,
|
|
|
|
"/hurd/password\0"],
|
|
|
|
['./servers/shutdown', oct(644), '0', undef, undef, undef,
|
|
|
|
"/hurd/shutdown\0"],
|
|
|
|
['./servers/socket/', oct(755), '5', undef, undef, undef, undef],
|
|
|
|
['./servers/socket/1', oct(644), '0', undef, undef, undef,
|
|
|
|
"/hurd/pflocal\0"],
|
|
|
|
['./servers/socket/2', oct(644), '0', undef, undef, undef,
|
|
|
|
"/hurd/pfinet\0-6\0/servers/socket/26\0"],
|
|
|
|
['./servers/socket/26', oct(644), '0', undef, undef, undef,
|
|
|
|
"/hurd/pfinet\0-4\0/servers/socket/2\0"],
|
|
|
|
['./servers/socket/inet', oct(644), '2', "2", undef, undef, undef],
|
|
|
|
['./servers/socket/inet6', oct(644), '2', "26", undef, undef, undef],
|
|
|
|
['./servers/socket/local', oct(644), '2', "1", undef, undef, undef],
|
|
|
|
['./servers/startup', oct(644), '0', undef, undef, undef, undef]
|
2018-09-18 09:20:24 +00:00
|
|
|
);
|
2021-03-08 07:04:35 +00:00
|
|
|
#>>>
|
2018-09-18 09:20:24 +00:00
|
|
|
|
2019-01-20 09:39:01 +00:00
|
|
|
# verbosity levels:
|
|
|
|
# 0 -> print nothing
|
|
|
|
# 1 -> normal output and progress bars
|
|
|
|
# 2 -> verbose output
|
|
|
|
# 3 -> debug output
|
|
|
|
my $verbosity_level = 1;
|
|
|
|
|
2022-01-07 13:41:22 +00:00
|
|
|
my $is_covering = 0;
|
|
|
|
{
|
|
|
|
# make $@ local, so we don't print "Undefined subroutine called"
|
|
|
|
# in other parts where we evaluate $@
|
|
|
|
local $@ = '';
|
|
|
|
$is_covering = !!(eval { Devel::Cover::get_coverage() });
|
|
|
|
}
|
2020-01-08 14:33:49 +00:00
|
|
|
|
2020-08-19 06:16:19 +00:00
|
|
|
# the reason why Perl::Critic warns about this is, that it suspects that the
|
|
|
|
# programmer wants to implement a test whether the terminal is interactive or
|
|
|
|
# not, in which case, complex interactions with the magic *ARGV indeed make it
|
|
|
|
# advisable to use IO::Interactive. In our case, we do not want to create an
|
|
|
|
# interactivity check but just want to check whether STDERR is opened to a tty,
|
|
|
|
# so our use of -t is fine and not "fragile and complicated" as is written in
|
|
|
|
# the description of InputOutput::ProhibitInteractiveTest. Also see
|
|
|
|
# https://github.com/Perl-Critic/Perl-Critic/issues/918
|
|
|
|
sub stderr_is_tty() {
|
|
|
|
## no critic (InputOutput::ProhibitInteractiveTest)
|
|
|
|
if (-t STDERR) {
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-20 09:39:01 +00:00
|
|
|
sub debug {
|
|
|
|
if ($verbosity_level < 3) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2019-01-20 09:39:01 +00:00
|
|
|
}
|
|
|
|
my $msg = shift;
|
2020-01-03 23:37:49 +00:00
|
|
|
my ($package, $filename, $line) = caller;
|
|
|
|
$msg = "D: $PID $line $msg";
|
2020-08-19 06:16:19 +00:00
|
|
|
if (stderr_is_tty()) {
|
2020-01-08 16:44:07 +00:00
|
|
|
$msg = colored($msg, 'clear');
|
2019-01-20 09:39:01 +00:00
|
|
|
}
|
|
|
|
print STDERR "$msg\n";
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2019-01-20 09:39:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub info {
|
|
|
|
if ($verbosity_level == 0) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2019-01-20 09:39:01 +00:00
|
|
|
}
|
|
|
|
my $msg = shift;
|
2020-01-03 23:37:49 +00:00
|
|
|
if ($verbosity_level >= 3) {
|
2020-01-08 14:41:49 +00:00
|
|
|
my ($package, $filename, $line) = caller;
|
2020-01-08 16:44:07 +00:00
|
|
|
$msg = "$PID $line $msg";
|
2020-01-03 23:37:49 +00:00
|
|
|
}
|
2019-01-20 09:39:01 +00:00
|
|
|
$msg = "I: $msg";
|
2020-08-19 06:16:19 +00:00
|
|
|
if (stderr_is_tty()) {
|
2020-01-08 16:44:07 +00:00
|
|
|
$msg = colored($msg, 'green');
|
2019-01-20 09:39:01 +00:00
|
|
|
}
|
|
|
|
print STDERR "$msg\n";
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2019-01-20 09:39:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub warning {
|
|
|
|
if ($verbosity_level == 0) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2019-01-20 09:39:01 +00:00
|
|
|
}
|
|
|
|
my $msg = shift;
|
|
|
|
$msg = "W: $msg";
|
2020-08-19 06:16:19 +00:00
|
|
|
if (stderr_is_tty()) {
|
2020-01-08 16:44:07 +00:00
|
|
|
$msg = colored($msg, 'bold yellow');
|
2019-01-20 09:39:01 +00:00
|
|
|
}
|
|
|
|
print STDERR "$msg\n";
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2019-01-20 09:39:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub error {
|
|
|
|
# if error() is called with the string from a previous error() that was
|
|
|
|
# caught inside an eval(), then the string will have a newline which we
|
|
|
|
# are stripping here
|
2020-01-08 16:44:07 +00:00
|
|
|
chomp(my $msg = shift);
|
2019-01-20 09:39:01 +00:00
|
|
|
$msg = "E: $msg";
|
2020-08-19 06:16:19 +00:00
|
|
|
if (stderr_is_tty()) {
|
2020-01-08 16:44:07 +00:00
|
|
|
$msg = colored($msg, 'bold red');
|
2019-01-20 09:39:01 +00:00
|
|
|
}
|
|
|
|
if ($verbosity_level == 3) {
|
2020-08-19 06:16:19 +00:00
|
|
|
croak $msg; # produces a backtrace
|
2019-01-20 09:39:01 +00:00
|
|
|
} else {
|
2020-01-08 14:41:49 +00:00
|
|
|
die "$msg\n";
|
2019-01-20 09:39:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-04 13:01:25 +00:00
|
|
|
# The encoding of dev_t is MMMM Mmmm mmmM MMmm, where M is a hex digit of
|
|
|
|
# the major number and m is a hex digit of the minor number.
|
|
|
|
sub major {
|
|
|
|
my $rdev = shift;
|
|
|
|
my $right
|
|
|
|
= Math::BigInt->from_hex("0x00000000000fff00")->band($rdev)->brsft(8);
|
|
|
|
my $left
|
|
|
|
= Math::BigInt->from_hex("0xfffff00000000000")->band($rdev)->brsft(32);
|
|
|
|
return $right->bior($left);
|
|
|
|
}
|
|
|
|
|
|
|
|
sub minor {
|
|
|
|
my $rdev = shift;
|
|
|
|
my $right = Math::BigInt->from_hex("0x00000000000000ff")->band($rdev);
|
|
|
|
my $left
|
|
|
|
= Math::BigInt->from_hex("0x00000ffffff00000")->band($rdev)->brsft(12);
|
|
|
|
return $right->bior($left);
|
|
|
|
}
|
|
|
|
|
2022-05-24 13:40:38 +00:00
|
|
|
sub can_execute {
|
2024-05-12 15:16:51 +00:00
|
|
|
my $tool = shift;
|
|
|
|
my $verbose = shift // '--version';
|
|
|
|
my $pid = open my $fh, '-|' // return 0;
|
2022-05-24 13:40:38 +00:00
|
|
|
if ($pid == 0) {
|
|
|
|
open(STDERR, '>&', STDOUT) or die;
|
2024-05-12 15:16:51 +00:00
|
|
|
exec {$tool} $tool, $verbose or die;
|
2022-05-24 13:40:38 +00:00
|
|
|
}
|
|
|
|
chomp(
|
|
|
|
my $content = do { local $/; <$fh> }
|
|
|
|
);
|
|
|
|
close $fh;
|
|
|
|
if ($? != 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (length $content == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-12-02 22:54:48 +00:00
|
|
|
# check whether a directory is mounted by comparing the device number of the
|
|
|
|
# directory itself with its parent
|
2020-01-09 07:39:40 +00:00
|
|
|
sub is_mountpoint {
|
2019-12-02 22:54:48 +00:00
|
|
|
my $dir = shift;
|
2020-01-08 16:44:07 +00:00
|
|
|
if (!-e $dir) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return 0;
|
2019-12-02 22:54:48 +00:00
|
|
|
}
|
|
|
|
my @a = stat "$dir/.";
|
|
|
|
my @b = stat "$dir/..";
|
|
|
|
# if the device number is different, then the directory must be mounted
|
|
|
|
if ($a[0] != $b[0]) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return 1;
|
2019-12-02 22:54:48 +00:00
|
|
|
}
|
|
|
|
# if the inode number is the same, then the directory must be mounted
|
|
|
|
if ($a[1] == $b[1]) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return 1;
|
2019-12-02 22:54:48 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-18 09:20:24 +00:00
|
|
|
# tar cannot figure out the decompression program when receiving data on
|
|
|
|
# standard input, thus we do it ourselves. This is copied from tar's
|
|
|
|
# src/suffix.c
|
2020-01-09 07:39:40 +00:00
|
|
|
sub get_tar_compressor {
|
2018-09-18 09:20:24 +00:00
|
|
|
my $filename = shift;
|
2019-01-20 09:41:29 +00:00
|
|
|
if ($filename eq '-') {
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2019-01-20 09:41:29 +00:00
|
|
|
} elsif ($filename =~ /\.tar$/) {
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2019-01-20 09:41:29 +00:00
|
|
|
} elsif ($filename =~ /\.(gz|tgz|taz)$/) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return ['gzip'];
|
2018-09-18 09:20:24 +00:00
|
|
|
} elsif ($filename =~ /\.(Z|taZ)$/) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return ['compress'];
|
2018-09-18 09:20:24 +00:00
|
|
|
} elsif ($filename =~ /\.(bz2|tbz|tbz2|tz2)$/) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return ['bzip2'];
|
2018-09-18 09:20:24 +00:00
|
|
|
} elsif ($filename =~ /\.lz$/) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return ['lzip'];
|
2018-09-18 09:20:24 +00:00
|
|
|
} elsif ($filename =~ /\.(lzma|tlz)$/) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return ['lzma'];
|
2018-09-18 09:20:24 +00:00
|
|
|
} elsif ($filename =~ /\.lzo$/) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return ['lzop'];
|
2018-09-18 09:20:24 +00:00
|
|
|
} elsif ($filename =~ /\.lz4$/) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return ['lz4'];
|
2018-09-18 09:20:24 +00:00
|
|
|
} elsif ($filename =~ /\.(xz|txz)$/) {
|
2021-09-24 20:01:21 +00:00
|
|
|
return ['xz'];
|
2019-01-20 09:41:29 +00:00
|
|
|
} elsif ($filename =~ /\.zst$/) {
|
2021-09-24 20:01:21 +00:00
|
|
|
return ['zstd'];
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2021-08-27 17:50:11 +00:00
|
|
|
# avoid dependency on String::ShellQuote by implementing the mechanism
|
|
|
|
# from python's shlex.quote function
|
|
|
|
sub shellescape {
|
|
|
|
my $string = shift;
|
|
|
|
if (length $string == 0) {
|
|
|
|
return "''";
|
|
|
|
}
|
|
|
|
# search for occurrences of characters that are not safe
|
|
|
|
# the 'a' regex modifier makes sure that \w only matches ASCII
|
|
|
|
if ($string !~ m/[^\w@\%+=:,.\/-]/a) {
|
|
|
|
return $string;
|
|
|
|
}
|
|
|
|
# wrap the string in single quotes and handle existing single quotes by
|
|
|
|
# putting them outside of the single-quoted string
|
|
|
|
$string =~ s/'/'"'"'/g;
|
|
|
|
return "'$string'";
|
|
|
|
}
|
|
|
|
|
2024-05-12 15:16:51 +00:00
|
|
|
sub create_v5_uuid {
|
|
|
|
use bytes;
|
|
|
|
my $ns_uuid = shift;
|
|
|
|
my $name = shift;
|
|
|
|
my $version = 0x50;
|
|
|
|
# convert the namespace uuid to binary
|
|
|
|
$ns_uuid =~ tr/-//d;
|
|
|
|
$ns_uuid = pack 'H*', $ns_uuid;
|
|
|
|
# concatenate namespace and name and take sha1
|
|
|
|
my $digest = Digest::SHA->new(1);
|
|
|
|
$digest->add($ns_uuid);
|
|
|
|
$digest->add($name);
|
|
|
|
# only the first 16 bytes matter
|
|
|
|
my $uuid = substr($digest->digest(), 0, 16);
|
|
|
|
# set the version
|
|
|
|
substr $uuid, 6, 1, chr(ord(substr($uuid, 6, 1)) & 0x0f | $version);
|
|
|
|
substr $uuid, 8, 1, chr(ord(substr $uuid, 8, 1) & 0x3f | 0x80);
|
|
|
|
# convert binary back to uuid formatting
|
|
|
|
return join '-', map { unpack 'H*', $_ }
|
|
|
|
map { substr $uuid, 0, $_, '' } (4, 2, 2, 2, 6);
|
|
|
|
}
|
|
|
|
|
2021-01-13 15:05:57 +00:00
|
|
|
sub test_unshare_userns {
|
2023-03-15 16:08:12 +00:00
|
|
|
my $verbose = shift;
|
|
|
|
|
2023-03-16 07:14:39 +00:00
|
|
|
local *maybe_error = sub {
|
2023-03-15 16:08:12 +00:00
|
|
|
my $msg = shift;
|
2020-01-08 14:41:49 +00:00
|
|
|
if ($verbose) {
|
2023-03-16 07:14:39 +00:00
|
|
|
error $msg;
|
2020-01-08 14:41:49 +00:00
|
|
|
} else {
|
|
|
|
debug $msg;
|
|
|
|
}
|
2023-03-15 16:08:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if ($EFFECTIVE_USER_ID == 0) {
|
2023-03-16 07:14:39 +00:00
|
|
|
maybe_error("cannot unshare user namespace when executing as root");
|
2020-01-08 14:41:49 +00:00
|
|
|
return 0;
|
2018-09-24 18:07:46 +00:00
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
# arguments to syscalls have to be stored in their own variable or
|
|
|
|
# otherwise we will get "Modification of a read-only value attempted"
|
2020-01-09 07:39:40 +00:00
|
|
|
my $unshare_flags = $CLONE_NEWUSER;
|
2018-09-18 09:20:24 +00:00
|
|
|
# we spawn a new per process because if unshare succeeds, we would
|
2018-10-01 15:14:59 +00:00
|
|
|
# otherwise have unshared the mmdebstrap process itself which we don't want
|
2019-01-20 09:39:01 +00:00
|
|
|
my $pid = fork() // error "fork() failed: $!";
|
2018-09-18 09:20:24 +00:00
|
|
|
if ($pid == 0) {
|
2020-01-09 07:39:40 +00:00
|
|
|
my $ret = syscall(&SYS_unshare, $unshare_flags);
|
2020-01-08 14:41:49 +00:00
|
|
|
if ($ret == 0) {
|
|
|
|
exit 0;
|
|
|
|
} else {
|
2023-03-16 07:14:39 +00:00
|
|
|
maybe_error("unshare syscall failed: $!");
|
2020-01-08 14:41:49 +00:00
|
|
|
exit 1;
|
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
waitpid($pid, 0);
|
|
|
|
if (($? >> 8) != 0) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return 0;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
2018-09-24 18:09:08 +00:00
|
|
|
# if newuidmap and newgidmap exist, the exit status will be 1 when
|
|
|
|
# executed without parameters
|
|
|
|
system "newuidmap 2>/dev/null";
|
|
|
|
if (($? >> 8) != 1) {
|
2020-01-08 14:41:49 +00:00
|
|
|
if (($? >> 8) == 127) {
|
2023-03-16 07:14:39 +00:00
|
|
|
maybe_error("cannot find newuidmap");
|
2020-01-08 14:41:49 +00:00
|
|
|
} else {
|
2023-03-16 07:14:39 +00:00
|
|
|
maybe_error("newuidmap returned unknown exit status: $?");
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
|
|
|
return 0;
|
2018-09-24 18:09:08 +00:00
|
|
|
}
|
|
|
|
system "newgidmap 2>/dev/null";
|
|
|
|
if (($? >> 8) != 1) {
|
2020-01-08 14:41:49 +00:00
|
|
|
if (($? >> 8) == 127) {
|
2023-03-16 07:14:39 +00:00
|
|
|
maybe_error("cannot find newgidmap");
|
2020-01-08 14:41:49 +00:00
|
|
|
} else {
|
2023-03-16 07:14:39 +00:00
|
|
|
maybe_error("newgidmap returned unknown exit status: $?");
|
2023-03-15 16:08:12 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
my @idmap = read_subuid_subgid($verbose);
|
|
|
|
if (scalar @idmap == 0) {
|
2023-03-16 07:14:39 +00:00
|
|
|
maybe_error("failed to parse /etc/subuid and /etc/subgid");
|
2023-03-15 16:08:12 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
# too much can go wrong when doing the dance required to unsharing the user
|
2023-03-16 07:14:39 +00:00
|
|
|
# namespace, so instead of adding more complexity to support maybe_error()
|
2023-03-15 16:08:12 +00:00
|
|
|
# to a function that is already too complex, we use eval()
|
|
|
|
eval {
|
|
|
|
$pid = get_unshare_cmd(
|
|
|
|
sub {
|
|
|
|
if ($EFFECTIVE_USER_ID == 0) {
|
|
|
|
exit 0;
|
|
|
|
} else {
|
|
|
|
exit 1;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
\@idmap
|
|
|
|
);
|
|
|
|
waitpid $pid, 0;
|
|
|
|
if ($? != 0) {
|
2023-03-16 07:14:39 +00:00
|
|
|
maybe_error("failed to unshare the user namespace");
|
2023-03-15 16:08:12 +00:00
|
|
|
return 0;
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2023-03-15 16:08:12 +00:00
|
|
|
};
|
|
|
|
if ($@) {
|
2023-03-16 07:14:39 +00:00
|
|
|
maybe_error($@);
|
2020-01-08 14:41:49 +00:00
|
|
|
return 0;
|
2018-09-24 18:09:08 +00:00
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-03-15 16:08:12 +00:00
|
|
|
sub read_subuid_subgid {
|
|
|
|
my $verbose = shift;
|
|
|
|
my @result = ();
|
2021-08-19 10:59:11 +00:00
|
|
|
my $username = getpwuid $REAL_USER_ID;
|
2018-09-18 09:20:24 +00:00
|
|
|
my ($subid, $num_subid, $fh, $n);
|
|
|
|
|
2023-03-15 16:08:12 +00:00
|
|
|
local *maybe_warn = sub {
|
|
|
|
my $msg = shift;
|
|
|
|
if ($verbose) {
|
|
|
|
warning $msg;
|
|
|
|
} else {
|
|
|
|
debug $msg;
|
|
|
|
}
|
|
|
|
};
|
2020-01-08 16:44:07 +00:00
|
|
|
if (!-e "/etc/subuid") {
|
2023-03-15 16:08:12 +00:00
|
|
|
maybe_warn("/etc/subuid doesn't exist");
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
2020-01-08 16:44:07 +00:00
|
|
|
if (!-r "/etc/subuid") {
|
2023-03-15 16:08:12 +00:00
|
|
|
maybe_warn("/etc/subuid is not readable");
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2020-01-08 16:44:07 +00:00
|
|
|
open $fh, "<", "/etc/subuid"
|
2023-03-15 16:08:12 +00:00
|
|
|
or maybe_warn("cannot open /etc/subuid for reading: $!");
|
|
|
|
if (!$fh) {
|
|
|
|
return;
|
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
while (my $line = <$fh>) {
|
2020-01-08 14:41:49 +00:00
|
|
|
($n, $subid, $num_subid) = split(/:/, $line, 3);
|
|
|
|
last if ($n eq $username);
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
close $fh;
|
2021-08-18 20:15:05 +00:00
|
|
|
if (!length $subid) {
|
2023-03-15 16:08:12 +00:00
|
|
|
maybe_warn("/etc/subuid is empty");
|
2021-08-18 20:15:05 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ($n ne $username) {
|
2023-03-15 16:08:12 +00:00
|
|
|
maybe_warn("no entry in /etc/subuid for $username");
|
2021-08-18 20:15:05 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
push @result, ["u", 0, $subid, $num_subid];
|
|
|
|
|
|
|
|
if (scalar(@result) < 1) {
|
2023-03-15 16:08:12 +00:00
|
|
|
maybe_warn("/etc/subuid does not contain an entry for $username");
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
if (scalar(@result) > 1) {
|
2023-03-15 16:08:12 +00:00
|
|
|
maybe_warn("/etc/subuid contains multiple entries for $username");
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2021-08-19 10:59:11 +00:00
|
|
|
if (!-e "/etc/subgid") {
|
2023-03-15 16:08:12 +00:00
|
|
|
maybe_warn("/etc/subgid doesn't exist");
|
2021-08-19 10:59:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!-r "/etc/subgid") {
|
2023-03-15 16:08:12 +00:00
|
|
|
maybe_warn("/etc/subgid is not readable");
|
2021-08-19 10:59:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-08 16:44:07 +00:00
|
|
|
open $fh, "<", "/etc/subgid"
|
2023-03-15 16:08:12 +00:00
|
|
|
or maybe_warn("cannot open /etc/subgid for reading: $!");
|
|
|
|
if (!$fh) {
|
|
|
|
return;
|
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
while (my $line = <$fh>) {
|
2020-01-08 14:41:49 +00:00
|
|
|
($n, $subid, $num_subid) = split(/:/, $line, 3);
|
2022-11-18 18:42:12 +00:00
|
|
|
last if ($n eq $username);
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
close $fh;
|
2021-08-18 20:15:05 +00:00
|
|
|
if (!length $subid) {
|
2023-03-15 16:08:12 +00:00
|
|
|
maybe_warn("/etc/subgid is empty");
|
2021-08-18 20:15:05 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-11-18 18:42:12 +00:00
|
|
|
if ($n ne $username) {
|
2023-03-15 16:08:12 +00:00
|
|
|
maybe_warn("no entry in /etc/subgid for $username");
|
2021-08-18 20:15:05 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
push @result, ["g", 0, $subid, $num_subid];
|
|
|
|
|
|
|
|
if (scalar(@result) < 2) {
|
2023-03-15 16:08:12 +00:00
|
|
|
maybe_warn("/etc/subgid does not contain an entry for $username");
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
if (scalar(@result) > 2) {
|
2023-03-15 16:08:12 +00:00
|
|
|
maybe_warn("/etc/subgid contains multiple entries for $username");
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return @result;
|
|
|
|
}
|
|
|
|
|
|
|
|
# This function spawns two child processes forming the following process tree
|
|
|
|
#
|
|
|
|
# A
|
|
|
|
# |
|
|
|
|
# fork()
|
|
|
|
# | \
|
|
|
|
# B C
|
|
|
|
# | |
|
|
|
|
# | fork()
|
|
|
|
# | | \
|
|
|
|
# | D E
|
|
|
|
# | | |
|
|
|
|
# |unshare()
|
|
|
|
# | close()
|
|
|
|
# | | |
|
|
|
|
# | | read()
|
|
|
|
# | | newuidmap(D)
|
|
|
|
# | | newgidmap(D)
|
|
|
|
# | | /
|
|
|
|
# | waitpid()
|
|
|
|
# | |
|
|
|
|
# | fork()
|
|
|
|
# | | \
|
|
|
|
# | F G
|
|
|
|
# | | |
|
|
|
|
# | | exec()
|
|
|
|
# | | /
|
|
|
|
# | waitpid()
|
|
|
|
# | /
|
|
|
|
# waitpid()
|
|
|
|
#
|
|
|
|
# To better refer to each individual part, we give each process a new
|
|
|
|
# identifier after calling fork(). Process A is the main process. After
|
|
|
|
# executing fork() we call the parent and child B and C, respectively. This
|
|
|
|
# first fork() is done because we do not want to modify A. B then remains
|
|
|
|
# waiting for its child C to finish. C calls fork() again, splitting into
|
|
|
|
# the parent D and its child E. In the parent D we call unshare() and close a
|
|
|
|
# pipe shared by D and E to signal to E that D is done with calling unshare().
|
|
|
|
# E notices this by using read() and follows up with executing the tools
|
|
|
|
# new[ug]idmap on D. E finishes and D continues with doing another fork().
|
|
|
|
# This is because when unsharing the PID namespace, we need a PID 1 to be kept
|
|
|
|
# alive or otherwise any child processes cannot fork() anymore themselves. So
|
|
|
|
# we keep F as PID 1 and finally call exec() in G.
|
2020-01-09 07:39:40 +00:00
|
|
|
sub get_unshare_cmd {
|
2020-01-08 16:44:07 +00:00
|
|
|
my $cmd = shift;
|
2018-09-18 09:20:24 +00:00
|
|
|
my $idmap = shift;
|
|
|
|
|
2021-01-13 15:05:57 +00:00
|
|
|
# unsharing the mount namespace (NEWNS) requires CAP_SYS_ADMIN
|
2020-01-08 16:44:07 +00:00
|
|
|
my $unshare_flags
|
2021-01-13 15:05:57 +00:00
|
|
|
= $CLONE_NEWNS | $CLONE_NEWPID | $CLONE_NEWUTS | $CLONE_NEWIPC;
|
|
|
|
|
|
|
|
# we only need to add CLONE_NEWUSER if we are not yet root
|
|
|
|
if ($EFFECTIVE_USER_ID != 0) {
|
|
|
|
$unshare_flags |= $CLONE_NEWUSER;
|
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
|
|
|
|
if (0) {
|
2020-01-09 07:39:40 +00:00
|
|
|
$unshare_flags |= $CLONE_NEWNET;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# fork a new process and let the child get unshare()ed
|
|
|
|
# we don't want to unshare the parent process
|
2019-01-20 09:39:01 +00:00
|
|
|
my $gcpid = fork() // error "fork() failed: $!";
|
2018-09-18 09:20:24 +00:00
|
|
|
if ($gcpid == 0) {
|
2020-01-08 15:23:34 +00:00
|
|
|
# Create a pipe for the parent process to signal the child process that
|
|
|
|
# it is done with calling unshare() so that the child can go ahead
|
|
|
|
# setting up uid_map and gid_map.
|
2020-01-08 14:41:49 +00:00
|
|
|
pipe my $rfh, my $wfh;
|
2020-01-08 15:23:34 +00:00
|
|
|
# We have to do this dance with forking a process and then modifying
|
|
|
|
# the parent from the child because:
|
|
|
|
# - new[ug]idmap can only be called on a process id after that process
|
|
|
|
# has unshared the user namespace
|
|
|
|
# - a process looses its capabilities if it performs an execve() with
|
|
|
|
# nonzero user ids see the capabilities(7) man page for details.
|
|
|
|
# - a process that unshared the user namespace by default does not
|
|
|
|
# have the privileges to call new[ug]idmap on itself
|
2020-01-08 14:41:49 +00:00
|
|
|
#
|
2020-01-08 15:23:34 +00:00
|
|
|
# this also works the other way around (the child setting up a user
|
|
|
|
# namespace and being modified from the parent) but that way, the
|
|
|
|
# parent would have to stay around until the child exited (so a pid
|
|
|
|
# would be wasted). Additionally, that variant would require an
|
|
|
|
# additional pipe to let the parent signal the child that it is done
|
|
|
|
# with calling new[ug]idmap. The way it is done here, this signaling
|
|
|
|
# can instead be done by wait()-ing for the exit of the child.
|
|
|
|
|
2020-01-08 14:41:49 +00:00
|
|
|
my $ppid = $$;
|
|
|
|
my $cpid = fork() // error "fork() failed: $!";
|
|
|
|
if ($cpid == 0) {
|
|
|
|
# child
|
|
|
|
|
|
|
|
# Close the writing descriptor at our end of the pipe so that we
|
|
|
|
# see EOF when parent closes its descriptor.
|
|
|
|
close $wfh;
|
|
|
|
|
|
|
|
# Wait for the parent process to finish its unshare() call by
|
|
|
|
# waiting for an EOF.
|
|
|
|
0 == sysread $rfh, my $c, 1 or error "read() did not receive EOF";
|
|
|
|
|
2021-01-13 15:05:57 +00:00
|
|
|
# the process is already root, so no need for newuidmap/newgidmap
|
|
|
|
if ($EFFECTIVE_USER_ID == 0) {
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
|
2020-01-08 14:41:49 +00:00
|
|
|
# The program's new[ug]idmap have to be used because they are
|
|
|
|
# setuid root. These privileges are needed to map the ids from
|
|
|
|
# /etc/sub[ug]id to the user namespace set up by the parent.
|
|
|
|
# Without these privileges, only the id of the user itself can be
|
|
|
|
# mapped into the new namespace.
|
|
|
|
#
|
|
|
|
# Since new[ug]idmap is setuid root we also don't need to write
|
|
|
|
# "deny" to /proc/$$/setgroups beforehand (this is otherwise
|
|
|
|
# required for unprivileged processes trying to write to
|
|
|
|
# /proc/$$/gid_map since kernel version 3.19 for security reasons)
|
|
|
|
# and therefore the parent process keeps its ability to change its
|
|
|
|
# own group here.
|
|
|
|
#
|
|
|
|
# Since /proc/$ppid/[ug]id_map can only be written to once,
|
|
|
|
# respectively, instead of making multiple calls to new[ug]idmap,
|
|
|
|
# we assemble a command line that makes one call each.
|
|
|
|
my $uidmapcmd = "";
|
|
|
|
my $gidmapcmd = "";
|
|
|
|
foreach (@{$idmap}) {
|
|
|
|
my ($t, $hostid, $nsid, $range) = @{$_};
|
|
|
|
if ($t ne "u" and $t ne "g" and $t ne "b") {
|
|
|
|
error "invalid idmap type: $t";
|
|
|
|
}
|
|
|
|
if ($t eq "u" or $t eq "b") {
|
|
|
|
$uidmapcmd .= " $hostid $nsid $range";
|
|
|
|
}
|
|
|
|
if ($t eq "g" or $t eq "b") {
|
|
|
|
$gidmapcmd .= " $hostid $nsid $range";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
my $idmapcmd = '';
|
|
|
|
if ($uidmapcmd ne "") {
|
2020-01-08 16:44:07 +00:00
|
|
|
0 == system "newuidmap $ppid $uidmapcmd"
|
|
|
|
or error "newuidmap $ppid $uidmapcmd failed: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
|
|
|
if ($gidmapcmd ne "") {
|
2020-01-08 16:44:07 +00:00
|
|
|
0 == system "newgidmap $ppid $gidmapcmd"
|
|
|
|
or error "newgidmap $ppid $gidmapcmd failed: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
# parent
|
|
|
|
|
|
|
|
# After fork()-ing, the parent immediately calls unshare...
|
2020-01-08 16:44:07 +00:00
|
|
|
0 == syscall &SYS_unshare, $unshare_flags
|
|
|
|
or error "unshare() failed: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
|
|
|
|
# .. and then signals the child process that we are done with the
|
|
|
|
# unshare() call by sending an EOF.
|
|
|
|
close $wfh;
|
|
|
|
|
|
|
|
# Wait for the child process to finish its setup by waiting for its
|
|
|
|
# exit.
|
|
|
|
$cpid == waitpid $cpid, 0 or error "waitpid() failed: $!";
|
|
|
|
my $exit = $? >> 8;
|
|
|
|
if ($exit != 0) {
|
|
|
|
error "child had a non-zero exit status: $exit";
|
|
|
|
}
|
|
|
|
|
|
|
|
# Currently we are nobody (uid and gid are 65534). So we become root
|
|
|
|
# user and group instead.
|
|
|
|
#
|
|
|
|
# We are using direct syscalls instead of setting $(, $), $< and $>
|
|
|
|
# because then perl would do additional stuff which we don't need or
|
|
|
|
# want here, like checking /proc/sys/kernel/ngroups_max (which might
|
|
|
|
# not exist). It would also also call setgroups() in a way that makes
|
|
|
|
# the root user be part of the group unknown.
|
2021-01-13 15:05:57 +00:00
|
|
|
if ($EFFECTIVE_USER_ID != 0) {
|
2021-12-14 15:10:25 +00:00
|
|
|
0 == syscall &SYS_setgid, 0 or error "setgid failed: $!";
|
|
|
|
0 == syscall &SYS_setuid, 0 or error "setuid failed: $!";
|
2021-01-13 15:05:57 +00:00
|
|
|
0 == syscall &SYS_setgroups, 0, 0 or error "setgroups failed: $!";
|
|
|
|
}
|
2020-01-08 14:41:49 +00:00
|
|
|
|
|
|
|
if (1) {
|
|
|
|
# When the pid namespace is also unshared, then processes expect a
|
|
|
|
# master pid to always be alive within the namespace. To achieve
|
|
|
|
# this, we fork() here instead of exec() to always have one dummy
|
|
|
|
# process running as pid 1 inside the namespace. This is also what
|
|
|
|
# the unshare tool does when used with the --fork option.
|
|
|
|
#
|
|
|
|
# Otherwise, without a pid 1, new processes cannot be forked
|
|
|
|
# anymore after pid 1 finished.
|
|
|
|
my $cpid = fork() // error "fork() failed: $!";
|
|
|
|
if ($cpid != 0) {
|
|
|
|
# The parent process will stay alive as pid 1 in this
|
|
|
|
# namespace until the child finishes executing. This is
|
|
|
|
# important because pid 1 must never die or otherwise nothing
|
|
|
|
# new can be forked.
|
|
|
|
$cpid == waitpid $cpid, 0 or error "waitpid() failed: $!";
|
2020-01-08 16:44:07 +00:00
|
|
|
exit($? >> 8);
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
&{$cmd}();
|
|
|
|
|
|
|
|
exit 0;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# parent
|
|
|
|
return $gcpid;
|
|
|
|
}
|
|
|
|
|
2020-01-09 07:39:40 +00:00
|
|
|
sub havemknod {
|
2020-01-08 16:44:07 +00:00
|
|
|
my $root = shift;
|
2018-09-18 09:20:24 +00:00
|
|
|
my $havemknod = 0;
|
|
|
|
if (-e "$root/test-dev-null") {
|
2020-01-08 14:41:49 +00:00
|
|
|
error "/test-dev-null already exists";
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
2020-01-08 16:44:07 +00:00
|
|
|
TEST: {
|
2020-01-08 14:41:49 +00:00
|
|
|
# we fork so that we can read STDERR
|
|
|
|
my $pid = open my $fh, '-|' // error "failed to fork(): $!";
|
|
|
|
if ($pid == 0) {
|
|
|
|
open(STDERR, '>&', STDOUT) or error "cannot open STDERR: $!";
|
|
|
|
# we use mknod(1) instead of the system call because creating the
|
|
|
|
# right dev_t argument requires makedev(3)
|
|
|
|
exec 'mknod', "$root/test-dev-null", 'c', '1', '3';
|
|
|
|
}
|
2020-01-08 16:44:07 +00:00
|
|
|
chomp(
|
|
|
|
my $content = do { local $/; <$fh> }
|
|
|
|
);
|
2020-01-08 14:41:49 +00:00
|
|
|
close $fh;
|
|
|
|
{
|
|
|
|
last TEST unless $? == 0 and $content eq '';
|
|
|
|
last TEST unless -c "$root/test-dev-null";
|
|
|
|
last TEST unless open my $fh, '>', "$root/test-dev-null";
|
|
|
|
last TEST unless print $fh 'test';
|
|
|
|
}
|
|
|
|
$havemknod = 1;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
if (-e "$root/test-dev-null") {
|
2020-01-08 16:44:07 +00:00
|
|
|
unlink "$root/test-dev-null"
|
|
|
|
or error "cannot unlink /test-dev-null: $!";
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
return $havemknod;
|
|
|
|
}
|
|
|
|
|
2022-10-16 20:03:06 +00:00
|
|
|
# inspired by /usr/share/perl/5.34/pod/perlfaq8.pod
|
|
|
|
sub terminal_width {
|
|
|
|
if (!stderr_is_tty()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!defined &TIOCGWINSZ) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!-e "/dev/tty") {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
my $tty_fh;
|
|
|
|
if (!open($tty_fh, "+<", "/dev/tty")) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
my $winsize = '';
|
|
|
|
if (!ioctl($tty_fh, &TIOCGWINSZ, $winsize)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
my (undef, $col, undef, undef) = unpack('S4', $winsize);
|
|
|
|
return $col;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Prints the current status, the percentage and a progress bar on STDERR if
|
|
|
|
# it is an interactive tty and if verbosity is set to 1.
|
|
|
|
#
|
|
|
|
# * first 12 chars: status
|
|
|
|
# * following 7 chars: percentage
|
|
|
|
# * progress bar until 79 chars are filled
|
2018-09-23 17:47:14 +00:00
|
|
|
sub print_progress {
|
2019-01-20 09:39:01 +00:00
|
|
|
if ($verbosity_level != 1) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2019-01-20 09:39:01 +00:00
|
|
|
}
|
2020-08-19 06:16:19 +00:00
|
|
|
if (!stderr_is_tty()) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2018-09-23 17:47:14 +00:00
|
|
|
}
|
2022-10-16 20:03:06 +00:00
|
|
|
my $perc = shift;
|
|
|
|
my $status = shift;
|
|
|
|
my $len_status = 12;
|
|
|
|
my $len_perc = 7;
|
|
|
|
my $len_prog_min = 10;
|
|
|
|
my $len_prog_max = 60;
|
|
|
|
my $twidth = terminal_width();
|
|
|
|
|
|
|
|
if ($twidth <= $len_status) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
# \e[2K clears everything on the current line (i.e. the progress bar)
|
|
|
|
print STDERR "\e[2K";
|
2018-09-23 17:47:14 +00:00
|
|
|
if ($perc eq "done") {
|
2022-10-16 20:03:06 +00:00
|
|
|
print STDERR "done\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (defined $status) {
|
|
|
|
printf STDERR "%*s", -$len_status, "$status:";
|
|
|
|
} else {
|
|
|
|
print STDERR (" " x $len_status);
|
|
|
|
}
|
|
|
|
if ($twidth <= $len_status + $len_perc) {
|
|
|
|
print STDERR "\r";
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2018-09-23 17:47:14 +00:00
|
|
|
}
|
|
|
|
if ($perc >= 100) {
|
2020-01-08 14:41:49 +00:00
|
|
|
$perc = 100;
|
2018-09-23 17:47:14 +00:00
|
|
|
}
|
2022-10-16 20:03:06 +00:00
|
|
|
printf STDERR "%*.2f", $len_perc, $perc;
|
|
|
|
if ($twidth <= $len_status + $len_perc + $len_prog_min) {
|
|
|
|
print STDERR "\r";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
my $len_prog = $twidth - $len_perc - $len_status;
|
|
|
|
if ($len_prog > $len_prog_max) {
|
|
|
|
$len_prog = $len_prog_max;
|
|
|
|
}
|
|
|
|
my $num_x = int($perc * ($len_prog - 3) / 100);
|
2020-01-08 16:44:07 +00:00
|
|
|
my $bar = '=' x $num_x;
|
2022-10-16 20:03:06 +00:00
|
|
|
if ($num_x != ($len_prog - 3)) {
|
2020-01-08 14:41:49 +00:00
|
|
|
$bar .= '>';
|
2022-10-16 20:03:06 +00:00
|
|
|
$bar .= ' ' x ($len_prog - $num_x - 4);
|
2018-09-23 17:47:14 +00:00
|
|
|
}
|
2022-10-16 20:03:06 +00:00
|
|
|
print STDERR " [$bar]\r";
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2018-09-23 17:47:14 +00:00
|
|
|
}
|
|
|
|
|
2019-01-13 21:04:25 +00:00
|
|
|
sub run_progress {
|
2019-04-25 06:49:28 +00:00
|
|
|
my ($get_exec, $line_handler, $line_has_error, $chdir) = @_;
|
2018-09-23 17:47:14 +00:00
|
|
|
pipe my $rfh, my $wfh;
|
2019-01-13 09:17:46 +00:00
|
|
|
my $got_signal = 0;
|
2020-01-08 16:44:07 +00:00
|
|
|
my $ignore = sub {
|
2020-01-08 14:41:49 +00:00
|
|
|
info "run_progress() received signal $_[0]: waiting for child...";
|
2019-01-13 09:17:46 +00:00
|
|
|
};
|
|
|
|
|
2020-04-10 10:55:02 +00:00
|
|
|
debug("run_progress: exec " . (join ' ', ($get_exec->('${FD}'))));
|
|
|
|
|
2019-01-13 09:17:46 +00:00
|
|
|
# delay signals so that we can fork and change behaviour of the signal
|
|
|
|
# handler in parent and child without getting interrupted
|
|
|
|
my $sigset = POSIX::SigSet->new(SIGINT, SIGHUP, SIGPIPE, SIGTERM);
|
2019-01-20 09:39:01 +00:00
|
|
|
POSIX::sigprocmask(SIG_BLOCK, $sigset) or error "Can't block signals: $!";
|
2019-01-13 09:17:46 +00:00
|
|
|
|
2019-01-20 09:39:01 +00:00
|
|
|
my $pid1 = open(my $pipe, '-|') // error "failed to fork(): $!";
|
2019-01-13 09:17:46 +00:00
|
|
|
|
2019-01-13 21:04:25 +00:00
|
|
|
if ($pid1 == 0) {
|
2020-01-08 14:41:49 +00:00
|
|
|
# child: default signal handlers
|
2020-01-09 07:39:40 +00:00
|
|
|
local $SIG{'INT'} = 'DEFAULT';
|
|
|
|
local $SIG{'HUP'} = 'DEFAULT';
|
|
|
|
local $SIG{'PIPE'} = 'DEFAULT';
|
|
|
|
local $SIG{'TERM'} = 'DEFAULT';
|
2020-01-08 14:41:49 +00:00
|
|
|
|
|
|
|
# unblock all delayed signals (and possibly handle them)
|
2020-01-08 16:44:07 +00:00
|
|
|
POSIX::sigprocmask(SIG_UNBLOCK, $sigset)
|
|
|
|
or error "Can't unblock signals: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
|
|
|
|
close $rfh;
|
|
|
|
# Unset the close-on-exec flag, so that the file descriptor does not
|
|
|
|
# get closed when we exec
|
2020-01-08 16:44:07 +00:00
|
|
|
my $flags = fcntl($wfh, F_GETFD, 0) or error "fcntl F_GETFD: $!";
|
|
|
|
fcntl($wfh, F_SETFD, $flags & ~FD_CLOEXEC)
|
|
|
|
or error "fcntl F_SETFD: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
my $fd = fileno $wfh;
|
|
|
|
# redirect stderr to stdout so that we can capture it
|
|
|
|
open(STDERR, '>&', STDOUT) or error "cannot open STDOUT: $!";
|
|
|
|
my @execargs = $get_exec->($fd);
|
|
|
|
# before apt 1.5, "apt-get update" attempted to chdir() into the
|
|
|
|
# working directory. This will fail if the current working directory
|
|
|
|
# is not accessible by the user (for example in unshare mode). See
|
|
|
|
# Debian bug #860738
|
|
|
|
if (defined $chdir) {
|
|
|
|
chdir $chdir or error "failed chdir() to $chdir: $!";
|
|
|
|
}
|
2020-01-09 07:39:40 +00:00
|
|
|
eval { Devel::Cover::set_coverage("none") } if $is_covering;
|
2020-01-08 16:44:07 +00:00
|
|
|
exec { $execargs[0] } @execargs
|
|
|
|
or error 'cannot exec() ' . (join ' ', @execargs);
|
2018-09-23 17:47:14 +00:00
|
|
|
}
|
|
|
|
close $wfh;
|
|
|
|
|
|
|
|
# spawn two processes:
|
2019-01-13 21:04:25 +00:00
|
|
|
# parent will parse stdout to look for errors
|
2018-09-23 17:47:14 +00:00
|
|
|
# child will parse $rfh for the progress meter
|
2019-01-20 09:39:01 +00:00
|
|
|
my $pid2 = fork() // error "failed to fork(): $!";
|
2019-01-13 21:04:25 +00:00
|
|
|
if ($pid2 == 0) {
|
2020-01-08 14:41:49 +00:00
|
|
|
# child: default signal handlers
|
2020-01-09 07:39:40 +00:00
|
|
|
local $SIG{'INT'} = 'IGNORE';
|
|
|
|
local $SIG{'HUP'} = 'IGNORE';
|
|
|
|
local $SIG{'PIPE'} = 'IGNORE';
|
|
|
|
local $SIG{'TERM'} = 'IGNORE';
|
2019-01-13 09:17:46 +00:00
|
|
|
|
2020-01-08 14:41:49 +00:00
|
|
|
# unblock all delayed signals (and possibly handle them)
|
2020-01-08 16:44:07 +00:00
|
|
|
POSIX::sigprocmask(SIG_UNBLOCK, $sigset)
|
|
|
|
or error "Can't unblock signals: $!";
|
2019-01-13 09:17:46 +00:00
|
|
|
|
2022-10-16 20:03:06 +00:00
|
|
|
if ($verbosity_level != 1 || !stderr_is_tty()) {
|
|
|
|
# no need to print any progress
|
|
|
|
# we still need to consume everything from $rfh or otherwise apt
|
|
|
|
# will block forever if there is too much output
|
|
|
|
local $/;
|
|
|
|
<$rfh>;
|
|
|
|
close $rfh;
|
|
|
|
exit 0;
|
|
|
|
}
|
2020-08-18 12:31:38 +00:00
|
|
|
my $progress = 0.0;
|
|
|
|
my $status = undef;
|
|
|
|
print_progress($progress);
|
2020-01-08 14:41:49 +00:00
|
|
|
while (my $line = <$rfh>) {
|
2020-08-18 12:31:38 +00:00
|
|
|
my ($newprogress, $newstatus) = $line_handler->($line);
|
|
|
|
next unless $newprogress;
|
|
|
|
# start a new line if the new progress value is less than the
|
|
|
|
# previous one
|
|
|
|
if ($newprogress < $progress) {
|
|
|
|
print_progress("done");
|
|
|
|
}
|
|
|
|
if (defined $newstatus) {
|
|
|
|
$status = $newstatus;
|
|
|
|
}
|
2022-10-16 20:03:06 +00:00
|
|
|
print_progress($newprogress, $status);
|
2020-08-18 12:31:38 +00:00
|
|
|
$progress = $newprogress;
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2020-01-09 07:39:40 +00:00
|
|
|
print_progress("done");
|
2018-09-23 17:47:14 +00:00
|
|
|
|
2020-01-08 14:41:49 +00:00
|
|
|
exit 0;
|
2018-09-23 17:47:14 +00:00
|
|
|
}
|
|
|
|
|
2019-01-13 09:17:46 +00:00
|
|
|
# parent: ignore signals
|
|
|
|
# by using "local", the original is automatically restored once the
|
|
|
|
# function returns
|
2020-01-08 16:44:07 +00:00
|
|
|
local $SIG{'INT'} = $ignore;
|
|
|
|
local $SIG{'HUP'} = $ignore;
|
2019-01-13 09:17:46 +00:00
|
|
|
local $SIG{'PIPE'} = $ignore;
|
|
|
|
local $SIG{'TERM'} = $ignore;
|
|
|
|
|
|
|
|
# unblock all delayed signals (and possibly handle them)
|
2020-01-08 16:44:07 +00:00
|
|
|
POSIX::sigprocmask(SIG_UNBLOCK, $sigset)
|
|
|
|
or error "Can't unblock signals: $!";
|
2019-01-13 09:17:46 +00:00
|
|
|
|
2020-01-08 16:44:07 +00:00
|
|
|
my $output = '';
|
2019-01-13 21:04:25 +00:00
|
|
|
my $has_error = 0;
|
|
|
|
while (my $line = <$pipe>) {
|
2020-01-08 14:41:49 +00:00
|
|
|
$has_error = $line_has_error->($line);
|
|
|
|
if ($verbosity_level >= 2) {
|
|
|
|
print STDERR $line;
|
|
|
|
} else {
|
|
|
|
# forward captured apt output
|
|
|
|
$output .= $line;
|
|
|
|
}
|
2018-09-23 17:47:14 +00:00
|
|
|
}
|
2019-01-13 21:04:25 +00:00
|
|
|
|
|
|
|
close($pipe);
|
2018-09-23 17:47:14 +00:00
|
|
|
my $fail = 0;
|
2019-01-13 21:04:25 +00:00
|
|
|
if ($? != 0 or $has_error) {
|
2020-01-08 14:41:49 +00:00
|
|
|
$fail = 1;
|
2018-09-23 17:47:14 +00:00
|
|
|
}
|
|
|
|
|
2019-01-13 21:04:25 +00:00
|
|
|
waitpid $pid2, 0;
|
2019-01-20 09:39:01 +00:00
|
|
|
$? == 0 or error "progress parsing failed";
|
2018-09-23 17:47:14 +00:00
|
|
|
|
2019-01-13 09:17:46 +00:00
|
|
|
if ($got_signal) {
|
2020-01-08 14:41:49 +00:00
|
|
|
error "run_progress() received signal: $got_signal";
|
2019-01-13 09:17:46 +00:00
|
|
|
}
|
|
|
|
|
2019-01-13 21:04:25 +00:00
|
|
|
# only print failure after progress output finished or otherwise it
|
|
|
|
# might interfere with the remaining output
|
2018-09-23 17:47:14 +00:00
|
|
|
if ($fail) {
|
2020-01-08 14:41:49 +00:00
|
|
|
if ($verbosity_level >= 1) {
|
|
|
|
print STDERR $output;
|
|
|
|
}
|
2020-01-08 16:44:07 +00:00
|
|
|
error((join ' ', $get_exec->('<$fd>')) . ' failed');
|
2018-09-23 17:47:14 +00:00
|
|
|
}
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2018-09-23 17:47:14 +00:00
|
|
|
}
|
|
|
|
|
2019-01-13 21:04:25 +00:00
|
|
|
sub run_dpkg_progress {
|
2018-12-27 20:08:53 +00:00
|
|
|
my $options = shift;
|
2020-01-08 16:44:07 +00:00
|
|
|
my @debs = @{ $options->{PKGS} // [] };
|
|
|
|
my $get_exec
|
|
|
|
= sub { return @{ $options->{ARGV} }, "--status-fd=$_[0]", @debs; };
|
2019-01-13 21:04:25 +00:00
|
|
|
my $line_has_error = sub { return 0; };
|
2020-01-08 16:44:07 +00:00
|
|
|
my $num = 0;
|
2019-01-13 21:04:25 +00:00
|
|
|
# each package has one install and one configure step, thus the total
|
|
|
|
# number is twice the number of packages
|
2020-01-08 16:44:07 +00:00
|
|
|
my $total = (scalar @debs) * 2;
|
2019-01-13 21:04:25 +00:00
|
|
|
my $line_handler = sub {
|
2020-08-18 12:31:38 +00:00
|
|
|
my $status = undef;
|
2020-01-08 14:41:49 +00:00
|
|
|
if ($_[0] =~ /^processing: (install|configure): /) {
|
2020-08-18 12:31:38 +00:00
|
|
|
if ($1 eq 'install') {
|
|
|
|
$status = 'installing';
|
|
|
|
} elsif ($1 eq 'configure') {
|
|
|
|
$status = 'configuring';
|
|
|
|
} else {
|
|
|
|
error "unknown status: $1";
|
|
|
|
}
|
2020-01-08 14:41:49 +00:00
|
|
|
$num += 1;
|
|
|
|
}
|
2022-12-22 09:13:01 +00:00
|
|
|
if ($total == 0) {
|
|
|
|
return 0, $status;
|
|
|
|
} else {
|
|
|
|
return $num / $total * 100, $status;
|
|
|
|
}
|
2019-01-13 21:04:25 +00:00
|
|
|
};
|
2019-01-20 09:39:01 +00:00
|
|
|
run_progress $get_exec, $line_handler, $line_has_error;
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2019-01-13 21:04:25 +00:00
|
|
|
}
|
2019-01-13 09:17:46 +00:00
|
|
|
|
2019-01-13 21:04:25 +00:00
|
|
|
sub run_apt_progress {
|
2023-02-01 17:04:49 +00:00
|
|
|
my $options = shift;
|
|
|
|
my @debs = @{ $options->{PKGS} // [] };
|
|
|
|
|
|
|
|
if ($verbosity_level >= 3) {
|
|
|
|
my @apt_debug_opts = qw(
|
|
|
|
-oDebug::pkgProblemResolver=true
|
|
|
|
-oDebug::pkgDepCache::Marker=1
|
|
|
|
-oDebug::pkgDepCache::AutoInstall=1
|
|
|
|
);
|
|
|
|
push @{ $options->{ARGV} }, @apt_debug_opts;
|
|
|
|
}
|
|
|
|
|
2019-01-13 21:04:25 +00:00
|
|
|
my $get_exec = sub {
|
2020-11-29 01:30:03 +00:00
|
|
|
my @prefix = ();
|
|
|
|
my @opts = ();
|
2020-01-08 14:41:49 +00:00
|
|
|
return (
|
2020-11-13 18:02:41 +00:00
|
|
|
@prefix,
|
2020-01-08 16:44:07 +00:00
|
|
|
@{ $options->{ARGV} },
|
2020-11-13 18:02:41 +00:00
|
|
|
@opts,
|
2020-01-08 14:41:49 +00:00
|
|
|
"-oAPT::Status-Fd=$_[0]",
|
|
|
|
# prevent apt from messing up the terminal and allow dpkg to
|
|
|
|
# receive SIGINT and quit immediately without waiting for
|
|
|
|
# maintainer script to finish
|
|
|
|
'-oDpkg::Use-Pty=false',
|
|
|
|
@debs
|
2020-01-08 16:44:07 +00:00
|
|
|
);
|
|
|
|
};
|
2019-04-29 22:07:35 +00:00
|
|
|
my $line_has_error = sub { return 0; };
|
|
|
|
if ($options->{FIND_APT_WARNINGS}) {
|
2020-01-08 14:41:49 +00:00
|
|
|
$line_has_error = sub {
|
|
|
|
# apt-get doesn't report a non-zero exit if the update failed.
|
|
|
|
# Thus, we have to parse its output. See #778357, #776152, #696335
|
2021-05-31 09:17:39 +00:00
|
|
|
# and #745735 for the parsing bugs as well as #594813, #696335,
|
|
|
|
# #776152, #778357 and #953726 for non-zero exit on transient
|
|
|
|
# network errors.
|
|
|
|
#
|
|
|
|
# For example, we want to fail with the following warning:
|
|
|
|
# W: Some index files failed to download. They have been ignored,
|
|
|
|
# or old ones used instead.
|
|
|
|
# But since this message is meant for human consumption it is not
|
|
|
|
# guaranteed to be stable across different apt versions and may
|
|
|
|
# change arbitrarily in the future. Thus, we error out on any W:
|
|
|
|
# lines as well. The downside is, that apt also unconditionally
|
|
|
|
# and by design prints a warning for unsigned repositories, even
|
|
|
|
# if they were allowed with Acquire::AllowInsecureRepositories "1"
|
|
|
|
# or with trusted=yes.
|
|
|
|
#
|
|
|
|
# A workaround was introduced by apt 2.1.16 with the --error-on=any
|
|
|
|
# option to apt-get update.
|
2020-01-08 14:41:49 +00:00
|
|
|
if ($_[0] =~ /^(W: |Err:)/) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
};
|
2019-04-29 22:07:35 +00:00
|
|
|
}
|
2019-01-13 21:04:25 +00:00
|
|
|
my $line_handler = sub {
|
2020-01-08 14:41:49 +00:00
|
|
|
if ($_[0] =~ /(pmstatus|dlstatus):[^:]+:(\d+\.\d+):.*/) {
|
2020-08-18 12:31:38 +00:00
|
|
|
my $status = undef;
|
|
|
|
if ($1 eq 'pmstatus') {
|
|
|
|
$status = "installing";
|
|
|
|
} elsif ($1 eq 'dlstatus') {
|
|
|
|
$status = "downloading";
|
|
|
|
} else {
|
|
|
|
error "unknown status: $1";
|
|
|
|
}
|
|
|
|
return $2, $status;
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2019-01-13 21:04:25 +00:00
|
|
|
};
|
2019-04-25 06:49:28 +00:00
|
|
|
run_progress $get_exec, $line_handler, $line_has_error, $options->{CHDIR};
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2018-09-23 17:47:14 +00:00
|
|
|
}
|
|
|
|
|
2022-05-24 09:47:16 +00:00
|
|
|
sub run_apt_download_progress {
|
|
|
|
my $options = shift;
|
|
|
|
if ($options->{dryrun}) {
|
|
|
|
info "simulate downloading packages with apt...";
|
|
|
|
} else {
|
|
|
|
info "downloading packages with apt...";
|
|
|
|
}
|
2022-08-20 15:05:11 +00:00
|
|
|
|
2022-05-24 09:47:16 +00:00
|
|
|
pipe my $rfh, my $wfh;
|
|
|
|
my $pid = open my $fh, '-|' // error "fork() failed: $!";
|
|
|
|
if ($pid == 0) {
|
|
|
|
close $wfh;
|
|
|
|
# read until parent process closes $wfh
|
|
|
|
my $content = do { local $/; <$rfh> };
|
|
|
|
close $rfh;
|
|
|
|
# the parent is done -- pass what we read back to it
|
|
|
|
print $content;
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
close $rfh;
|
|
|
|
# Unset the close-on-exec flag, so that the file descriptor does not
|
|
|
|
# get closed when we exec
|
|
|
|
my $flags = fcntl($wfh, F_GETFD, 0) or error "fcntl F_GETFD: $!";
|
|
|
|
fcntl($wfh, F_SETFD, $flags & ~FD_CLOEXEC) or error "fcntl F_SETFD: $!";
|
|
|
|
my $fd = fileno $wfh;
|
2022-08-30 19:55:57 +00:00
|
|
|
# run_apt_progress() can raise an exception which would leave this function
|
|
|
|
# without cleaning up the other thread we started, making mmdebstrap hang
|
|
|
|
# in case run_apt_progress() fails -- so wrap this in eval() instead
|
|
|
|
eval {
|
|
|
|
# 2022-05-02, #debian-apt on OFTC, times in UTC+2
|
|
|
|
# 16:57 < josch> DonKult: how is -oDebug::pkgDpkgPm=1
|
|
|
|
# -oDir::Log=/dev/null a "fancy no-op"?
|
|
|
|
# 11:52 < DonKult> josch: "fancy no-op" in sofar as it does nothing to
|
|
|
|
# the system even through its not in a special mode
|
|
|
|
# ala simulation or download-only. It does all the
|
|
|
|
# things it normally does, except that it just prints
|
|
|
|
# the dpkg calls instead of execv() them which in
|
|
|
|
# practice amounts means it does nothing (the Dir::Log
|
|
|
|
# just prevents libapt from creating the /var/log/apt
|
|
|
|
# directories. As the code creates them even if no
|
|
|
|
# logs will be placed there…). As said, midterm an apt
|
|
|
|
# --print-install-packages or something would be nice
|
|
|
|
# to avoid running everything.
|
|
|
|
run_apt_progress({
|
|
|
|
ARGV => [
|
|
|
|
'apt-get',
|
|
|
|
'--yes',
|
|
|
|
'-oDebug::pkgDpkgPm=1',
|
|
|
|
'-oDir::Log=/dev/null',
|
|
|
|
$options->{dryrun}
|
|
|
|
? '-oAPT::Get::Simulate=true'
|
|
|
|
: (
|
|
|
|
"-oAPT::Keep-Fds::=$fd",
|
|
|
|
"-oDPkg::Tools::options::'cat >&$fd'::InfoFD=$fd",
|
|
|
|
"-oDpkg::Pre-Install-Pkgs::=cat >&$fd",
|
|
|
|
# no need to lock the database if we are just downloading
|
|
|
|
"-oDebug::NoLocking=1",
|
|
|
|
# no need for pty magic if we write no log
|
|
|
|
"-oDpkg::Use-Pty=0",
|
2023-03-22 08:27:11 +00:00
|
|
|
# unset this or otherwise "cat >&$fd" will fail
|
|
|
|
"-oDPkg::Chroot-Directory=",
|
2022-08-30 19:55:57 +00:00
|
|
|
),
|
|
|
|
@{ $options->{APT_ARGV} },
|
|
|
|
],
|
|
|
|
});
|
|
|
|
};
|
|
|
|
my $err = '';
|
|
|
|
if ($@) {
|
|
|
|
$err = "apt download failed: $@";
|
|
|
|
}
|
2022-05-24 09:47:16 +00:00
|
|
|
# signal the child process that we are done
|
|
|
|
close $wfh;
|
|
|
|
# and then read from it what it got
|
|
|
|
my @listofdebs = <$fh>;
|
|
|
|
close $fh;
|
|
|
|
if ($? != 0) {
|
2022-08-30 19:55:57 +00:00
|
|
|
$err = "status child failed";
|
|
|
|
}
|
|
|
|
if ($err) {
|
|
|
|
error $err;
|
2022-05-24 09:47:16 +00:00
|
|
|
}
|
|
|
|
# remove trailing newlines
|
|
|
|
chomp @listofdebs;
|
|
|
|
return @listofdebs;
|
|
|
|
}
|
|
|
|
|
2022-11-10 13:53:36 +00:00
|
|
|
sub setup_mounts {
|
2019-01-13 09:17:46 +00:00
|
|
|
my $options = shift;
|
|
|
|
|
|
|
|
my @cleanup_tasks = ();
|
|
|
|
|
|
|
|
eval {
|
2020-01-08 14:41:49 +00:00
|
|
|
if (any { $_ eq $options->{mode} } ('root', 'unshare')) {
|
2024-06-02 05:44:17 +00:00
|
|
|
0 == system('mount', "--make-rprivate", "/")
|
|
|
|
or warning("mount --make-rprivate / failed: $?");
|
2020-01-08 14:41:49 +00:00
|
|
|
# if more than essential should be installed, make the system look
|
2020-01-08 15:23:34 +00:00
|
|
|
# more like a real one by creating or bind-mounting the device
|
|
|
|
# nodes
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
foreach my $file (@linuxdevfiles) {
|
|
|
|
my ($fname, $mode, $type, $linkname, $devmajor, $devminor,
|
|
|
|
undef)
|
2020-01-08 16:44:07 +00:00
|
|
|
= @{$file};
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
next if $fname eq './dev/';
|
|
|
|
if ($type eq '0') { # normal file
|
2020-01-08 14:41:49 +00:00
|
|
|
error "type 0 not implemented";
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
} elsif ($type eq '1') { # hardlink
|
2020-01-08 14:41:49 +00:00
|
|
|
error "type 1 not implemented";
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
} elsif ($type eq '2') { # symlink
|
2020-01-08 14:41:49 +00:00
|
|
|
if (!$options->{havemknod}) {
|
2021-03-08 07:04:35 +00:00
|
|
|
# If we had mknod, then the symlink was already created
|
|
|
|
# in the run_setup function.
|
|
|
|
if (!-d "$options->{root}/dev") {
|
|
|
|
warning(
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
"skipping creation of $fname because the"
|
2021-03-08 07:04:35 +00:00
|
|
|
. " /dev directory is missing in the target"
|
|
|
|
);
|
2020-01-08 14:41:49 +00:00
|
|
|
next;
|
|
|
|
}
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
if (-e "$options->{root}/$fname") {
|
2023-10-23 08:33:37 +00:00
|
|
|
warning(
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
"skipping creation of $fname because it"
|
2023-10-23 08:33:37 +00:00
|
|
|
. " already exists in the target");
|
|
|
|
next;
|
|
|
|
}
|
2021-03-08 07:04:35 +00:00
|
|
|
push @cleanup_tasks, sub {
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
unlink "$options->{root}/$fname"
|
2022-05-28 10:52:36 +00:00
|
|
|
or warning("cannot unlink ./dev/$fname: $!");
|
2021-03-08 07:04:35 +00:00
|
|
|
};
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
symlink $linkname, "$options->{root}/$fname"
|
2023-10-23 08:33:54 +00:00
|
|
|
or warning
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
"cannot create symlink $fname -> $linkname";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
} elsif ($type eq '3' or $type eq '4') {
|
2020-01-08 15:23:34 +00:00
|
|
|
# character/block special
|
2022-11-14 13:34:15 +00:00
|
|
|
if (any { $_ =~ '^chroot/mount(?:/dev)?$' }
|
|
|
|
@{ $options->{skip} }) {
|
2022-09-02 21:27:27 +00:00
|
|
|
info "skipping chroot/mount/dev as requested";
|
|
|
|
} elsif (!$options->{canmount}) {
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
warning "skipping bind-mounting $fname";
|
2021-01-13 17:40:24 +00:00
|
|
|
} elsif (!$options->{havemknod}) {
|
2021-03-08 07:04:35 +00:00
|
|
|
if (!-d "$options->{root}/dev") {
|
|
|
|
warning(
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
"skipping creation of $fname because the"
|
2021-03-08 07:04:35 +00:00
|
|
|
. " /dev directory is missing in the target"
|
|
|
|
);
|
|
|
|
next;
|
|
|
|
}
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
if ($fname eq "./dev/ptmx") {
|
2022-06-14 06:26:48 +00:00
|
|
|
# We must not bind-mount ptmx from the outside or
|
|
|
|
# otherwise posix_openpt() will fail. Instead
|
|
|
|
# /dev/ptmx must refer to /dev/pts/ptmx either by
|
|
|
|
# symlink or by bind-mounting. We choose a symlink.
|
|
|
|
symlink '/dev/pts/ptmx',
|
|
|
|
"$options->{root}/dev/ptmx"
|
|
|
|
or error "cannot create /dev/pts/ptmx symlink";
|
|
|
|
push @cleanup_tasks, sub {
|
|
|
|
unlink "$options->{root}/dev/ptmx"
|
2022-11-07 15:10:55 +00:00
|
|
|
or warning "unlink /dev/ptmx";
|
2022-06-14 06:26:48 +00:00
|
|
|
};
|
|
|
|
next;
|
|
|
|
}
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
if (!-e "/$fname") {
|
|
|
|
warning("skipping creation of $fname because"
|
|
|
|
. " $fname does not exist"
|
2021-03-08 07:04:35 +00:00
|
|
|
. " on the outside");
|
|
|
|
next;
|
|
|
|
}
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
if (!-c "/$fname") {
|
|
|
|
warning("skipping creation of $fname because"
|
|
|
|
. " $fname on the outside is not a"
|
2021-03-08 07:04:35 +00:00
|
|
|
. " character special file");
|
|
|
|
next;
|
|
|
|
}
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
open my $fh, '>', "$options->{root}/$fname"
|
|
|
|
or error "cannot open $options->{root}/$fname: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
close $fh;
|
2021-03-08 07:04:35 +00:00
|
|
|
my @umountopts = ();
|
2020-01-08 14:41:49 +00:00
|
|
|
if ($options->{mode} eq 'unshare') {
|
2021-03-08 07:04:35 +00:00
|
|
|
push @umountopts, '--no-mtab';
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2021-03-08 07:04:35 +00:00
|
|
|
push @cleanup_tasks, sub {
|
|
|
|
0 == system('umount', @umountopts,
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
"$options->{root}/$fname")
|
|
|
|
or warning("umount $fname failed: $?");
|
|
|
|
unlink "$options->{root}/$fname"
|
|
|
|
or warning("cannot unlink $fname: $!");
|
2021-03-08 07:04:35 +00:00
|
|
|
};
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
0 == system('mount', '-o', 'bind', "/$fname",
|
|
|
|
"$options->{root}/$fname")
|
|
|
|
or error "mount $fname failed: $?";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
} elsif ($type eq '5') {
|
2022-09-02 21:27:27 +00:00
|
|
|
# directory
|
2022-11-14 13:34:15 +00:00
|
|
|
if (any { $_ =~ '^chroot/mount(?:/dev)?$' }
|
|
|
|
@{ $options->{skip} }) {
|
2022-09-02 21:27:27 +00:00
|
|
|
info "skipping chroot/mount/dev as requested";
|
|
|
|
} elsif (!$options->{canmount}) {
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
warning "skipping bind-mounting $fname";
|
2022-09-02 21:27:27 +00:00
|
|
|
} else {
|
|
|
|
if (!-d "$options->{root}/dev") {
|
|
|
|
warning(
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
"skipping creation of $fname because the"
|
2022-09-02 21:27:27 +00:00
|
|
|
. " /dev directory is missing in the target"
|
|
|
|
);
|
|
|
|
next;
|
|
|
|
}
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
if (!-e "/$fname" && $fname ne "./dev/pts/") {
|
|
|
|
warning("skipping creation of $fname because"
|
|
|
|
. " $fname does not exist"
|
2022-09-02 21:27:27 +00:00
|
|
|
. " on the outside");
|
|
|
|
next;
|
|
|
|
}
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
if (!-d "/$fname" && $fname ne "./dev/pts/") {
|
|
|
|
warning("skipping creation of $fname because"
|
|
|
|
. " $fname on the outside is not a"
|
2022-09-02 21:27:27 +00:00
|
|
|
. " directory");
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
if (!$options->{havemknod}) {
|
2023-09-27 05:52:35 +00:00
|
|
|
# If had mknod, then the directory to bind-mount
|
|
|
|
# into was already created in the run_setup
|
|
|
|
# function.
|
2022-09-02 21:27:27 +00:00
|
|
|
push @cleanup_tasks, sub {
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
rmdir "$options->{root}/$fname"
|
|
|
|
or warning("cannot rmdir $fname: $!");
|
2022-09-02 21:27:27 +00:00
|
|
|
};
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
if (-e "$options->{root}/$fname") {
|
|
|
|
if (!-d "$options->{root}/$fname") {
|
|
|
|
error "$fname already exists but is not"
|
2022-09-02 21:27:27 +00:00
|
|
|
. " a directory";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
my $num_created
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
= make_path "$options->{root}/$fname",
|
2022-09-02 21:27:27 +00:00
|
|
|
{ error => \my $err };
|
|
|
|
if ($err && @$err) {
|
|
|
|
error(
|
|
|
|
join "; ",
|
|
|
|
(
|
|
|
|
map {
|
|
|
|
"cannot create "
|
|
|
|
. (join ": ", %{$_})
|
|
|
|
} @$err
|
|
|
|
));
|
|
|
|
} elsif ($num_created == 0) {
|
|
|
|
error( "cannot create $options->{root}"
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
. "$fname");
|
2022-09-02 21:27:27 +00:00
|
|
|
}
|
|
|
|
}
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
chmod $mode, "$options->{root}/$fname"
|
|
|
|
or error "cannot chmod $fname: $!";
|
2022-09-02 21:27:27 +00:00
|
|
|
}
|
|
|
|
my @umountopts = ();
|
|
|
|
if ($options->{mode} eq 'unshare') {
|
|
|
|
push @umountopts, '--no-mtab';
|
|
|
|
}
|
2021-03-08 07:04:35 +00:00
|
|
|
push @cleanup_tasks, sub {
|
2022-09-02 21:27:27 +00:00
|
|
|
0 == system('umount', @umountopts,
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
"$options->{root}/$fname")
|
|
|
|
or warning("umount $fname failed: $?");
|
2021-03-08 07:04:35 +00:00
|
|
|
};
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
if ($fname eq "./dev/pts/") {
|
2023-09-27 05:52:35 +00:00
|
|
|
# We cannot just bind-mount /dev/pts from the host
|
|
|
|
# as doing so will make posix_openpt() fail.
|
|
|
|
# Instead, we need to mount a new devpts.
|
|
|
|
# We need ptmxmode=666 because /dev/ptmx is a
|
|
|
|
# symlink to /dev/pts/ptmx and without it
|
|
|
|
# posix_openpt() will fail if we are not the root
|
|
|
|
# user. See also:
|
|
|
|
# kernel.o/doc/Documentation/filesystems/devpts.txt
|
|
|
|
# salsa.d.o/debian/schroot/-/merge_requests/2
|
|
|
|
# https://bugs.debian.org/856877
|
|
|
|
# https://bugs.debian.org/817236
|
2022-09-02 21:27:27 +00:00
|
|
|
0 == system(
|
|
|
|
'mount',
|
|
|
|
'-t',
|
|
|
|
'devpts',
|
|
|
|
'none',
|
|
|
|
"$options->{root}/dev/pts",
|
|
|
|
'-o',
|
|
|
|
'noexec,nosuid,uid=5,mode=620,ptmxmode=666'
|
|
|
|
) or error "mount /dev/pts failed";
|
2020-01-08 14:41:49 +00:00
|
|
|
} else {
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
0 == system('mount', '-o', 'bind', "/$fname",
|
|
|
|
"$options->{root}/$fname")
|
|
|
|
or error "mount $fname failed: $?";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2022-06-14 06:26:48 +00:00
|
|
|
}
|
2020-01-08 14:41:49 +00:00
|
|
|
} else {
|
|
|
|
error "unsupported type: $type";
|
|
|
|
}
|
|
|
|
}
|
2022-09-05 03:50:50 +00:00
|
|
|
} elsif (any { $_ eq $options->{mode} } ('fakechroot', 'chrootless')) {
|
|
|
|
# we cannot mount in fakechroot mode
|
2020-01-08 14:41:49 +00:00
|
|
|
} else {
|
|
|
|
error "unknown mode: $options->{mode}";
|
|
|
|
}
|
|
|
|
# We can only mount /proc and /sys after extracting the essential
|
|
|
|
# set because if we mount it before, then base-files will not be able
|
|
|
|
# to extract those
|
2022-09-05 03:58:50 +00:00
|
|
|
if ( (any { $_ eq $options->{mode} } ('root', 'unshare'))
|
|
|
|
&& (any { $_ =~ '^chroot/mount(?:/sys)?$' } @{ $options->{skip} }))
|
|
|
|
{
|
2022-09-02 21:27:27 +00:00
|
|
|
info "skipping chroot/mount/sys as requested";
|
|
|
|
} elsif ((any { $_ eq $options->{mode} } ('root', 'unshare'))
|
2021-08-26 13:40:27 +00:00
|
|
|
&& !$options->{canmount}) {
|
2021-01-13 17:40:24 +00:00
|
|
|
warning "skipping mount sysfs";
|
2021-08-26 13:40:27 +00:00
|
|
|
} elsif ((any { $_ eq $options->{mode} } ('root', 'unshare'))
|
|
|
|
&& !-d "$options->{root}/sys") {
|
2021-03-08 07:04:35 +00:00
|
|
|
warning("skipping mounting of sysfs because the"
|
|
|
|
. " /sys directory is missing in the target");
|
2021-08-26 13:40:27 +00:00
|
|
|
} elsif ((any { $_ eq $options->{mode} } ('root', 'unshare'))
|
|
|
|
&& !-e "/sys") {
|
2023-02-09 10:16:36 +00:00
|
|
|
warning("skipping mounting /sys because"
|
2021-08-26 13:40:27 +00:00
|
|
|
. " /sys does not exist on the outside");
|
|
|
|
} elsif ((any { $_ eq $options->{mode} } ('root', 'unshare'))
|
|
|
|
&& !-d "/sys") {
|
2023-02-09 10:16:36 +00:00
|
|
|
warning("skipping mounting /sys because"
|
2021-08-26 13:40:27 +00:00
|
|
|
. " /sys on the outside is not a directory");
|
2021-01-13 17:40:24 +00:00
|
|
|
} elsif ($options->{mode} eq 'root') {
|
2022-03-25 13:25:54 +00:00
|
|
|
# we don't know whether we run in root mode inside an unshared
|
|
|
|
# user namespace or as real root so we first try the real mount and
|
|
|
|
# then fall back to mounting in a way that works in unshared mode
|
|
|
|
if (
|
|
|
|
0 == system(
|
|
|
|
'mount', '-t',
|
|
|
|
'sysfs', '-o',
|
|
|
|
'ro,nosuid,nodev,noexec', 'sys',
|
|
|
|
"$options->{root}/sys"
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
push @cleanup_tasks, sub {
|
|
|
|
0 == system('umount', "$options->{root}/sys")
|
2022-05-28 10:52:36 +00:00
|
|
|
or warning("umount /sys failed: $?");
|
2022-03-25 13:25:54 +00:00
|
|
|
};
|
|
|
|
} elsif (
|
|
|
|
0 == system('mount', '-o', 'rbind', '/sys',
|
|
|
|
"$options->{root}/sys")) {
|
|
|
|
push @cleanup_tasks, sub {
|
|
|
|
# since we cannot write to /etc/mtab we need --no-mtab
|
|
|
|
# unmounting /sys only seems to be successful with --lazy
|
|
|
|
0 == system(
|
|
|
|
'umount', '--no-mtab',
|
|
|
|
'--lazy', "$options->{root}/sys"
|
2022-05-28 10:52:36 +00:00
|
|
|
) or warning("umount /sys failed: $?");
|
2022-03-25 13:25:54 +00:00
|
|
|
};
|
|
|
|
} else {
|
|
|
|
error "mount /sys failed: $?";
|
|
|
|
}
|
2020-01-08 14:41:49 +00:00
|
|
|
} elsif ($options->{mode} eq 'unshare') {
|
2020-01-08 15:23:34 +00:00
|
|
|
# naturally we have to clean up after ourselves in sudo mode where
|
|
|
|
# we do a real mount. But we also need to unmount in unshare mode
|
|
|
|
# because otherwise, even with the --one-file-system tar option,
|
|
|
|
# the permissions of the mount source will be stored and not the
|
|
|
|
# mount target (the directory)
|
2020-01-08 14:41:49 +00:00
|
|
|
push @cleanup_tasks, sub {
|
|
|
|
# since we cannot write to /etc/mtab we need --no-mtab
|
|
|
|
# unmounting /sys only seems to be successful with --lazy
|
2020-01-08 16:44:07 +00:00
|
|
|
0 == system('umount', '--no-mtab', '--lazy',
|
|
|
|
"$options->{root}/sys")
|
2022-05-28 10:52:36 +00:00
|
|
|
or warning("umount /sys failed: $?");
|
2020-01-08 14:41:49 +00:00
|
|
|
};
|
|
|
|
# without the network namespace unshared, we cannot mount a new
|
|
|
|
# sysfs. Since we need network, we just bind-mount.
|
|
|
|
#
|
|
|
|
# we have to rbind because just using bind results in "wrong fs
|
|
|
|
# type, bad option, bad superblock" error
|
2020-01-08 16:44:07 +00:00
|
|
|
0 == system('mount', '-o', 'rbind', '/sys', "$options->{root}/sys")
|
|
|
|
or error "mount /sys failed: $?";
|
2022-09-05 03:50:50 +00:00
|
|
|
} elsif (any { $_ eq $options->{mode} } ('fakechroot', 'chrootless')) {
|
|
|
|
# we cannot mount in fakechroot mode
|
2020-01-08 14:41:49 +00:00
|
|
|
} else {
|
|
|
|
error "unknown mode: $options->{mode}";
|
|
|
|
}
|
2022-09-05 03:58:50 +00:00
|
|
|
if (
|
|
|
|
(any { $_ eq $options->{mode} } ('root', 'unshare'))
|
|
|
|
&& (any { $_ =~ '^chroot/mount(?:/proc)?$' } @{ $options->{skip} })
|
|
|
|
) {
|
2022-09-02 21:27:27 +00:00
|
|
|
info "skipping chroot/mount/proc as requested";
|
|
|
|
} elsif ((any { $_ eq $options->{mode} } ('root', 'unshare'))
|
2021-08-26 13:40:27 +00:00
|
|
|
&& !$options->{canmount}) {
|
2021-01-13 17:40:24 +00:00
|
|
|
warning "skipping mount proc";
|
2021-08-26 13:40:27 +00:00
|
|
|
} elsif ((any { $_ eq $options->{mode} } ('root', 'unshare'))
|
|
|
|
&& !-d "$options->{root}/proc") {
|
2021-03-08 07:04:35 +00:00
|
|
|
warning("skipping mounting of proc because the"
|
|
|
|
. " /proc directory is missing in the target");
|
2021-08-26 13:40:27 +00:00
|
|
|
} elsif ((any { $_ eq $options->{mode} } ('root', 'unshare'))
|
|
|
|
&& !-e "/proc") {
|
2023-02-09 10:16:36 +00:00
|
|
|
warning("skipping mounting /proc because"
|
2021-08-26 13:40:27 +00:00
|
|
|
. " /proc does not exist on the outside");
|
|
|
|
} elsif ((any { $_ eq $options->{mode} } ('root', 'unshare'))
|
|
|
|
&& !-d "/proc") {
|
2023-02-09 10:16:36 +00:00
|
|
|
warning("skipping mounting /proc because"
|
2021-08-26 13:40:27 +00:00
|
|
|
. " /proc on the outside is not a directory");
|
2023-02-09 09:19:51 +00:00
|
|
|
} elsif (any { $_ eq $options->{mode} } ('root', 'unshare')) {
|
2022-03-25 13:25:54 +00:00
|
|
|
# we don't know whether we run in root mode inside an unshared
|
|
|
|
# user namespace or as real root so we first try the real mount and
|
|
|
|
# then fall back to mounting in a way that works in unshared
|
|
|
|
if (
|
2023-02-09 09:19:51 +00:00
|
|
|
$options->{mode} eq 'root'
|
|
|
|
&& 0 == system(
|
2022-03-25 13:25:54 +00:00
|
|
|
'mount', '-t', 'proc', '-o', 'ro', 'proc',
|
|
|
|
"$options->{root}/proc"
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
push @cleanup_tasks, sub {
|
|
|
|
# some maintainer scripts mount additional stuff into /proc
|
|
|
|
# which we need to unmount beforehand
|
|
|
|
if (
|
|
|
|
is_mountpoint(
|
|
|
|
$options->{root} . "/proc/sys/fs/binfmt_misc"
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
0 == system('umount',
|
|
|
|
"$options->{root}/proc/sys/fs/binfmt_misc")
|
2022-05-28 10:52:36 +00:00
|
|
|
or warning(
|
|
|
|
"umount /proc/sys/fs/binfmt_misc failed: $?");
|
2022-03-25 13:25:54 +00:00
|
|
|
}
|
|
|
|
0 == system('umount', "$options->{root}/proc")
|
2022-05-28 10:52:36 +00:00
|
|
|
or warning("umount /proc failed: $?");
|
2022-03-25 13:25:54 +00:00
|
|
|
};
|
|
|
|
} elsif (
|
|
|
|
0 == system('mount', '-t', 'proc', 'proc',
|
|
|
|
"$options->{root}/proc")) {
|
|
|
|
push @cleanup_tasks, sub {
|
|
|
|
# since we cannot write to /etc/mtab we need --no-mtab
|
|
|
|
0 == system('umount', '--no-mtab', "$options->{root}/proc")
|
2022-05-28 10:52:36 +00:00
|
|
|
or warning("umount /proc failed: $?");
|
2022-03-25 13:25:54 +00:00
|
|
|
};
|
2023-02-09 09:19:51 +00:00
|
|
|
} elsif (
|
|
|
|
# if mounting proc failed, try bind-mounting it read-only as a
|
|
|
|
# last resort
|
|
|
|
0 == system(
|
2023-02-10 12:26:24 +00:00
|
|
|
'mount', '-o',
|
2023-02-09 09:19:51 +00:00
|
|
|
'rbind', '/proc',
|
|
|
|
"$options->{root}/proc"
|
|
|
|
)
|
|
|
|
) {
|
2023-02-10 12:26:24 +00:00
|
|
|
warning("since mounting /proc normally failed, /proc is now "
|
|
|
|
. "bind-mounted instead");
|
|
|
|
# to make sure that changes (like unmounting) to the
|
|
|
|
# bind-mounted /proc do not affect the outside /proc, change
|
|
|
|
# all the bind-mounts under /proc to be a slave mount.
|
|
|
|
if (
|
|
|
|
0 != system('mount', '--make-rslave',
|
|
|
|
"$options->{root}/proc")) {
|
|
|
|
warning("mount --make-rslave /proc failed");
|
|
|
|
}
|
2023-02-09 09:19:51 +00:00
|
|
|
push @cleanup_tasks, sub {
|
|
|
|
# since we cannot write to /etc/mtab we need --no-mtab
|
2023-02-10 12:26:24 +00:00
|
|
|
0 == system(
|
|
|
|
'umount', '--no-mtab',
|
|
|
|
'--lazy', "$options->{root}/proc"
|
|
|
|
) or warning("umount /proc failed: $?");
|
2023-02-09 09:19:51 +00:00
|
|
|
};
|
2022-03-25 13:25:54 +00:00
|
|
|
} else {
|
|
|
|
error "mount /proc failed: $?";
|
|
|
|
}
|
2022-09-05 03:50:50 +00:00
|
|
|
} elsif (any { $_ eq $options->{mode} } ('fakechroot', 'chrootless')) {
|
|
|
|
# we cannot mount in fakechroot mode
|
2020-01-08 14:41:49 +00:00
|
|
|
} else {
|
|
|
|
error "unknown mode: $options->{mode}";
|
|
|
|
}
|
|
|
|
|
|
|
|
# prevent daemons from starting
|
|
|
|
# the directory might not exist in custom variant, for example
|
2020-03-07 22:39:53 +00:00
|
|
|
#
|
|
|
|
# ideally, we should use update-alternatives but we cannot rely on it
|
|
|
|
# existing inside the chroot
|
|
|
|
#
|
|
|
|
# See #911290 for more problems of this interface
|
2022-09-02 21:25:48 +00:00
|
|
|
if (any { $_ eq 'chroot/policy-rc.d' } @{ $options->{skip} }) {
|
|
|
|
info "skipping chroot/policy-rc.d as requested";
|
|
|
|
} else {
|
2022-11-10 13:53:36 +00:00
|
|
|
push @cleanup_tasks, sub {
|
|
|
|
if (-f "$options->{root}/usr/sbin/policy-rc.d") {
|
|
|
|
unlink "$options->{root}/usr/sbin/policy-rc.d"
|
|
|
|
or error "cannot unlink policy-rc.d: $!";
|
|
|
|
}
|
|
|
|
};
|
2022-09-02 21:25:48 +00:00
|
|
|
if (-d "$options->{root}/usr/sbin/") {
|
|
|
|
open my $fh, '>', "$options->{root}/usr/sbin/policy-rc.d"
|
|
|
|
or error "cannot open policy-rc.d: $!";
|
|
|
|
print $fh "#!/bin/sh\n";
|
|
|
|
print $fh "exit 101\n";
|
|
|
|
close $fh;
|
|
|
|
chmod 0755, "$options->{root}/usr/sbin/policy-rc.d"
|
|
|
|
or error "cannot chmod policy-rc.d: $!";
|
|
|
|
}
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# the file might not exist if it was removed in a hook
|
2022-09-02 21:25:48 +00:00
|
|
|
if (any { $_ eq 'chroot/start-stop-daemon' } @{ $options->{skip} }) {
|
|
|
|
info "skipping chroot/start-stop-daemon as requested";
|
|
|
|
} else {
|
2024-01-30 06:41:08 +00:00
|
|
|
# $options->{root} must not be part of $ssdloc but must instead be
|
|
|
|
# evaluated at the time the cleanup is run or otherwise, when
|
|
|
|
# performing a pivot-root, the ssd location will still be prefixed
|
|
|
|
# with the chroot path even though we changed root
|
2024-01-25 08:30:26 +00:00
|
|
|
my $ssdloc;
|
|
|
|
if (-f "$options->{root}/sbin/start-stop-daemon") {
|
2024-01-30 06:41:08 +00:00
|
|
|
$ssdloc = "/sbin/start-stop-daemon";
|
2024-01-25 08:30:26 +00:00
|
|
|
} elsif (-f "$options->{root}/usr/sbin/start-stop-daemon") {
|
2024-01-30 06:41:08 +00:00
|
|
|
$ssdloc = "/usr/sbin/start-stop-daemon";
|
2024-01-25 08:30:26 +00:00
|
|
|
}
|
2022-11-10 13:53:36 +00:00
|
|
|
push @cleanup_tasks, sub {
|
2024-01-25 08:30:26 +00:00
|
|
|
return unless length $ssdloc;
|
2024-01-30 06:41:08 +00:00
|
|
|
if (-e "$options->{root}/$ssdloc.REAL") {
|
|
|
|
move(
|
|
|
|
"$options->{root}/$ssdloc.REAL",
|
|
|
|
"$options->{root}/$ssdloc"
|
|
|
|
) or error "cannot move start-stop-daemon: $!";
|
2022-11-10 13:53:36 +00:00
|
|
|
}
|
|
|
|
};
|
2024-01-25 08:30:26 +00:00
|
|
|
if (length $ssdloc) {
|
2024-01-30 06:41:08 +00:00
|
|
|
if (-e "$options->{root}/$ssdloc.REAL") {
|
|
|
|
error "$options->{root}/$ssdloc.REAL already exists";
|
2022-09-02 21:25:48 +00:00
|
|
|
}
|
2024-01-30 06:41:08 +00:00
|
|
|
move(
|
|
|
|
"$options->{root}/$ssdloc",
|
|
|
|
"$options->{root}/$ssdloc.REAL"
|
|
|
|
) or error "cannot move start-stop-daemon: $!";
|
|
|
|
open my $fh, '>', "$options->{root}/$ssdloc"
|
2022-09-02 21:25:48 +00:00
|
|
|
or error "cannot open start-stop-daemon: $!";
|
|
|
|
print $fh "#!/bin/sh\n";
|
|
|
|
print $fh
|
|
|
|
"echo \"Warning: Fake start-stop-daemon called, doing"
|
|
|
|
. " nothing\">&2\n";
|
|
|
|
close $fh;
|
2024-01-30 06:41:08 +00:00
|
|
|
chmod 0755, "$options->{root}/$ssdloc"
|
2022-09-02 21:25:48 +00:00
|
|
|
or error "cannot chmod start-stop-daemon: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-13 09:17:46 +00:00
|
|
|
};
|
|
|
|
|
2022-11-10 13:53:36 +00:00
|
|
|
if ($@) {
|
|
|
|
error "setup_mounts failed: $@";
|
2019-01-13 09:17:46 +00:00
|
|
|
}
|
2022-11-10 13:53:36 +00:00
|
|
|
return @cleanup_tasks;
|
2019-01-13 09:17:46 +00:00
|
|
|
}
|
|
|
|
|
2020-01-09 07:39:40 +00:00
|
|
|
sub run_hooks {
|
2022-12-23 09:02:04 +00:00
|
|
|
my $name = shift;
|
|
|
|
my $options = shift;
|
|
|
|
my $essential_pkgs = shift;
|
2019-02-20 12:32:49 +00:00
|
|
|
|
2020-01-08 16:44:07 +00:00
|
|
|
if (scalar @{ $options->{"${name}_hook"} } == 0) {
|
2020-01-08 14:41:49 +00:00
|
|
|
return;
|
2019-02-20 12:32:49 +00:00
|
|
|
}
|
|
|
|
|
2020-01-10 10:44:15 +00:00
|
|
|
if ($options->{dryrun}) {
|
|
|
|
info "not running ${name}-hooks because of --dry-run";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-09 18:41:59 +00:00
|
|
|
my @env_opts = ();
|
2021-02-04 16:46:39 +00:00
|
|
|
# At this point TMPDIR is set to "$options->{root}/tmp". This is to have a
|
|
|
|
# writable TMPDIR even in unshare mode. But if TMPDIR is still set when
|
|
|
|
# running hooks, then every hook script calling chroot, will have to wrap
|
|
|
|
# that into an "env --unset=TMPDIR". To avoid this, we unset TMPDIR here.
|
|
|
|
# If the hook script needs a writable TMPDIR, then it can always use /tmp
|
|
|
|
# inside the chroot. This is also why we do not set a new MMDEBSTRAP_TMPDIR
|
|
|
|
# environment variable.
|
2021-03-08 06:54:04 +00:00
|
|
|
if (length $ENV{TMPDIR}) {
|
2021-02-04 16:46:39 +00:00
|
|
|
push @env_opts, '--unset=TMPDIR';
|
|
|
|
}
|
2021-01-09 18:41:59 +00:00
|
|
|
# The APT_CONFIG variable, if set, will confuse any manual calls to
|
|
|
|
# apt-get. If you want to use the same config used by mmdebstrap, the
|
|
|
|
# original value is stored in MMDEBSTRAP_APT_CONFIG.
|
2021-03-08 06:54:04 +00:00
|
|
|
if (length $ENV{APT_CONFIG}) {
|
2021-01-09 18:41:59 +00:00
|
|
|
push @env_opts, '--unset=APT_CONFIG';
|
|
|
|
}
|
2021-03-08 06:54:04 +00:00
|
|
|
if (length $ENV{APT_CONFIG}) {
|
2021-01-09 18:41:59 +00:00
|
|
|
push @env_opts, "MMDEBSTRAP_APT_CONFIG=$ENV{APT_CONFIG}";
|
|
|
|
}
|
2023-06-19 11:10:49 +00:00
|
|
|
# A hook script that wants to call mmdebstrap with --hook-helper needs to
|
2023-03-19 07:58:53 +00:00
|
|
|
# know how mmdebstrap was executed
|
|
|
|
push @env_opts, "MMDEBSTRAP_ARGV0=$PROGRAM_NAME";
|
2021-01-09 18:41:59 +00:00
|
|
|
# Storing the mode is important for hook scripts to potentially change
|
|
|
|
# their behavior depending on the mode. It's also important for when the
|
|
|
|
# hook wants to use the mmdebstrap --hook-helper.
|
|
|
|
push @env_opts, "MMDEBSTRAP_MODE=$options->{mode}";
|
2023-06-19 11:10:49 +00:00
|
|
|
if (defined $options->{suite}) {
|
|
|
|
push @env_opts, "MMDEBSTRAP_SUITE=$options->{suite}";
|
|
|
|
}
|
2023-10-23 08:35:07 +00:00
|
|
|
push @env_opts, "MMDEBSTRAP_FORMAT=$options->{format}";
|
2021-02-06 08:18:05 +00:00
|
|
|
# Storing the hook name is important for hook scripts to potentially change
|
|
|
|
# their behavior depending on the hook. It's also important for when the
|
|
|
|
# hook wants to use the mmdebstrap --hook-helper.
|
|
|
|
push @env_opts, "MMDEBSTRAP_HOOK=$name";
|
2021-01-09 18:41:59 +00:00
|
|
|
# This is the file descriptor of the socket that the mmdebstrap
|
|
|
|
# --hook-helper can write to and read from to communicate with the outside.
|
|
|
|
push @env_opts, ("MMDEBSTRAP_HOOKSOCK=" . fileno($options->{hooksock}));
|
2022-05-24 02:14:08 +00:00
|
|
|
# Store the verbosity of mmdebstrap so that hooks can be just as verbose
|
|
|
|
# as the mmdebstrap invocation that called them.
|
|
|
|
push @env_opts, ("MMDEBSTRAP_VERBOSITY=" . $verbosity_level);
|
2022-09-02 22:03:40 +00:00
|
|
|
# Store the packages given via --include in an environment variable so that
|
|
|
|
# hooks can, for example, make .deb files available inside the chroot.
|
|
|
|
{
|
|
|
|
my @escaped_includes = @{ $options->{include} };
|
|
|
|
foreach my $incl (@escaped_includes) {
|
|
|
|
# We have to encode commas so that values containing commas can
|
|
|
|
# be stored in the list. Since we encode using percent-encoding
|
|
|
|
# (urlencoding) we also have to encode the percent sign.
|
|
|
|
$incl =~ s/%/%25/g;
|
|
|
|
$incl =~ s/,/%2C/g;
|
|
|
|
}
|
|
|
|
push @env_opts,
|
|
|
|
("MMDEBSTRAP_INCLUDE=" . (join ",", @escaped_includes));
|
|
|
|
}
|
2022-12-23 09:02:04 +00:00
|
|
|
# Give the extract hook access to the essential packages that are about to
|
|
|
|
# be installed
|
|
|
|
if ($name eq "extract" and scalar @{$essential_pkgs} > 0) {
|
|
|
|
push @env_opts,
|
|
|
|
("MMDEBSTRAP_ESSENTIAL=" . (join " ", @{$essential_pkgs}));
|
|
|
|
}
|
2023-09-27 05:56:49 +00:00
|
|
|
if ($options->{mode} eq 'unshare') {
|
|
|
|
push @env_opts, "container=mmdebstrap-unshare";
|
|
|
|
}
|
2021-01-09 18:41:59 +00:00
|
|
|
|
2022-11-10 13:53:36 +00:00
|
|
|
# Unset the close-on-exec flag, so that the file descriptor does not
|
|
|
|
# get closed when we exec
|
|
|
|
my $flags = fcntl($options->{hooksock}, F_GETFD, 0)
|
|
|
|
or error "fcntl F_GETFD: $!";
|
|
|
|
fcntl($options->{hooksock}, F_SETFD, $flags & ~FD_CLOEXEC)
|
|
|
|
or error "fcntl F_SETFD: $!";
|
|
|
|
|
|
|
|
{
|
2020-01-08 16:44:07 +00:00
|
|
|
foreach my $script (@{ $options->{"${name}_hook"} }) {
|
2022-11-14 08:59:59 +00:00
|
|
|
my $type = $script->[0];
|
|
|
|
$script = $script->[1];
|
|
|
|
|
|
|
|
if ($type eq "pivoted") {
|
|
|
|
info "running --chrooted-$name-hook in shell: sh -c "
|
|
|
|
. "'$script'";
|
|
|
|
my $pid = fork() // error "fork() failed: $!";
|
|
|
|
if ($pid == 0) {
|
|
|
|
# child
|
|
|
|
my @cmdprefix = ();
|
|
|
|
if ($options->{mode} eq 'fakechroot') {
|
|
|
|
# we are calling the chroot executable instead of
|
|
|
|
# chrooting the process so that fakechroot can handle
|
|
|
|
# it
|
|
|
|
@cmdprefix = ('chroot', $options->{root});
|
|
|
|
} elsif ($options->{mode} eq 'root') {
|
|
|
|
# unsharing the mount namespace is not enough for
|
|
|
|
# pivot_root to work as root (why?) unsharing the user
|
|
|
|
# namespace as well (but without remapping) makes
|
|
|
|
# pivot_root work (why??) but still makes later lazy
|
|
|
|
# umounts fail (why???). Since pivot_root is mainly
|
|
|
|
# useful for being able to run unshare mode inside
|
|
|
|
# unshare mode, we fall back to just calling chroot()
|
|
|
|
# until somebody has motivation and time to figure out
|
|
|
|
# what is going on.
|
|
|
|
chroot $options->{root}
|
|
|
|
or error "failed to chroot(): $!";
|
|
|
|
$options->{root} = "/";
|
|
|
|
chdir "/" or error "failed chdir() to /: $!";
|
|
|
|
} elsif ($options->{mode} eq 'unshare') {
|
|
|
|
0 == syscall &SYS_unshare, $CLONE_NEWNS
|
|
|
|
or error "unshare() failed: $!";
|
|
|
|
pivot_root($options->{root});
|
|
|
|
} else {
|
|
|
|
error "unknown mode: $options->{mode}";
|
|
|
|
}
|
|
|
|
0 == system(@cmdprefix, 'env', @env_opts, 'sh', '-c',
|
|
|
|
$script)
|
|
|
|
or error "command failed: $script";
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
waitpid($pid, 0);
|
|
|
|
$? == 0 or error "chrooted hook failed with exit code $?";
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
|
|
|
|
# inode and device number of chroot before
|
|
|
|
my ($dev_before, $ino_before, undef) = stat($options->{root});
|
|
|
|
|
2020-01-16 09:38:14 +00:00
|
|
|
if (
|
|
|
|
$script =~ /^(
|
|
|
|
copy-in|copy-out
|
|
|
|
|tar-in|tar-out
|
|
|
|
|upload|download
|
|
|
|
|sync-in|sync-out
|
|
|
|
)\ /x
|
|
|
|
) {
|
2020-01-08 14:41:49 +00:00
|
|
|
info "running special hook: $script";
|
2022-09-05 03:50:50 +00:00
|
|
|
if ((any { $_ eq $options->{variant} } ('extract', 'custom'))
|
|
|
|
and $options->{mode} eq 'fakechroot'
|
|
|
|
and $name ne 'setup') {
|
2020-01-08 16:41:46 +00:00
|
|
|
info "the copy-in, copy-out, tar-in and tar-out commands"
|
2022-09-05 03:50:50 +00:00
|
|
|
. " in fakechroot mode might fail in"
|
2020-01-08 16:41:46 +00:00
|
|
|
. " extract and custom variants because there might be"
|
|
|
|
. " no tar inside the chroot";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
my $pid = fork() // error "fork() failed: $!";
|
|
|
|
if ($pid == 0) {
|
|
|
|
# whatever the script writes on stdout is sent to the
|
|
|
|
# socket
|
|
|
|
# whatever is written to the socket, send to stdin
|
2020-01-08 16:44:07 +00:00
|
|
|
open(STDOUT, '>&', $options->{hooksock})
|
|
|
|
or error "cannot open STDOUT: $!";
|
|
|
|
open(STDIN, '<&', $options->{hooksock})
|
|
|
|
or error "cannot open STDIN: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
|
2022-11-08 12:02:47 +00:00
|
|
|
# Text::ParseWords::shellwords does for perl what shlex
|
|
|
|
# does for python
|
|
|
|
my @args = shellwords $script;
|
|
|
|
hookhelper($options->{root}, $options->{mode}, $name,
|
2023-10-23 08:41:46 +00:00
|
|
|
(join ',', @{ $options->{skip} }),
|
|
|
|
$verbosity_level, @args);
|
2022-11-08 12:02:47 +00:00
|
|
|
exit 0;
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
|
|
|
waitpid($pid, 0);
|
|
|
|
$? == 0 or error "special hook failed with exit code $?";
|
2020-01-08 16:44:07 +00:00
|
|
|
} elsif (-x $script || $script !~ m/[^\w@\%+=:,.\/-]/a) {
|
2020-01-08 14:41:49 +00:00
|
|
|
info "running --$name-hook directly: $script $options->{root}";
|
|
|
|
# execute it directly if it's an executable file
|
|
|
|
# or if it there are no shell metacharacters
|
|
|
|
# (the /a regex modifier makes \w match only ASCII)
|
2021-01-09 18:41:59 +00:00
|
|
|
0 == system('env', @env_opts, $script, $options->{root})
|
2020-01-08 16:44:07 +00:00
|
|
|
or error "command failed: $script";
|
2020-01-08 14:41:49 +00:00
|
|
|
} else {
|
2020-01-08 16:41:46 +00:00
|
|
|
info "running --$name-hook in shell: sh -c '$script' exec"
|
|
|
|
. " $options->{root}";
|
2020-01-08 14:41:49 +00:00
|
|
|
# otherwise, wrap everything in sh -c
|
2021-01-09 18:41:59 +00:00
|
|
|
0 == system('env', @env_opts,
|
2020-03-07 01:06:11 +00:00
|
|
|
'sh', '-c', $script, 'exec', $options->{root})
|
2020-01-08 16:44:07 +00:00
|
|
|
or error "command failed: $script";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2022-11-14 08:59:59 +00:00
|
|
|
|
|
|
|
# If the chroot directory vanished, check if pivot_root was
|
|
|
|
# performed.
|
|
|
|
#
|
|
|
|
# Running pivot_root is only really useful in the customize-hooks
|
|
|
|
# because mmdebstrap uses apt from the outside to install packages
|
|
|
|
# and that will fail after pivot_root because the process doesn't
|
|
|
|
# have access to the system on the outside anymore.
|
|
|
|
if (!-e $options->{root}) {
|
|
|
|
my ($dev_root, $ino_root, undef) = stat("/");
|
|
|
|
if ($dev_before == $dev_root and $ino_before == $ino_root) {
|
|
|
|
info "detected pivot_root, changing chroot directory to /";
|
|
|
|
# the old chroot directory is now /
|
|
|
|
# the hook probably executed pivot_root
|
|
|
|
$options->{root} = "/";
|
|
|
|
chdir "/" or error "failed chdir() to /: $!";
|
|
|
|
} else {
|
|
|
|
error "chroot directory $options->{root} vanished";
|
|
|
|
}
|
|
|
|
}
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2019-02-20 12:32:49 +00:00
|
|
|
};
|
|
|
|
|
2021-01-09 18:41:59 +00:00
|
|
|
# Restore flags
|
|
|
|
fcntl($options->{hooksock}, F_SETFD, $flags) or error "fcntl F_SETFD: $!";
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2019-02-20 12:32:49 +00:00
|
|
|
}
|
|
|
|
|
2018-09-18 09:20:24 +00:00
|
|
|
sub setup {
|
|
|
|
my $options = shift;
|
|
|
|
|
2019-01-20 09:39:01 +00:00
|
|
|
foreach my $key (sort keys %{$options}) {
|
2020-01-08 14:41:49 +00:00
|
|
|
my $value = $options->{$key};
|
|
|
|
if (!defined $value) {
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
if (ref $value eq '') {
|
|
|
|
debug "$key: $options->{$key}";
|
|
|
|
} elsif (ref $value eq 'ARRAY') {
|
|
|
|
debug "$key: [" . (join ', ', @{$value}) . "]";
|
|
|
|
} elsif (ref $value eq 'GLOB') {
|
|
|
|
debug "$key: GLOB";
|
|
|
|
} else {
|
|
|
|
error "unknown type for key $key: " . (ref $value);
|
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2020-01-21 23:27:57 +00:00
|
|
|
if (-e $options->{apttrusted} && !-r $options->{apttrusted}) {
|
|
|
|
warning "cannot read $options->{apttrusted}";
|
|
|
|
}
|
|
|
|
if (-e $options->{apttrustedparts} && !-r $options->{apttrustedparts}) {
|
|
|
|
warning "cannot read $options->{apttrustedparts}";
|
|
|
|
}
|
|
|
|
|
2021-08-17 09:11:00 +00:00
|
|
|
if (any { $_ eq 'setup' } @{ $options->{skip} }) {
|
|
|
|
info "skipping setup as requested";
|
|
|
|
} else {
|
|
|
|
run_setup($options);
|
|
|
|
}
|
2020-04-09 21:07:02 +00:00
|
|
|
|
|
|
|
run_hooks('setup', $options);
|
|
|
|
|
2023-03-19 08:04:06 +00:00
|
|
|
# apt runs dpkg from inside the chroot and directly passes the filename to
|
|
|
|
# dpkg. Hence, the included files on the outside must be present under the
|
|
|
|
# same path on the inside. If they are not, dpkg cannot find them.
|
|
|
|
if (scalar(grep { /^\// } @{ $options->{include} }) > 0) {
|
|
|
|
my $ret = 0;
|
|
|
|
foreach my $f (grep { /^\// } @{ $options->{include} }) {
|
|
|
|
next if -e "$options->{root}/$f";
|
|
|
|
warning
|
|
|
|
"path given via --include is not present inside the chroot: $f";
|
|
|
|
$ret = 1;
|
|
|
|
}
|
|
|
|
if ($ret != 0) {
|
|
|
|
warning("apt runs chrooted dpkg which needs access to the "
|
|
|
|
. "package paths given via --include inside the chroot.");
|
|
|
|
warning "maybe try running mmdebstrap with "
|
|
|
|
. "--hook-dir=/usr/share/mmdebstrap/hooks/file-mirror-automount";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-17 09:11:00 +00:00
|
|
|
if (any { $_ eq 'update' } @{ $options->{skip} }) {
|
|
|
|
info "skipping update as requested";
|
|
|
|
} else {
|
|
|
|
run_update($options);
|
|
|
|
}
|
2020-04-09 21:07:02 +00:00
|
|
|
|
2021-11-09 06:31:56 +00:00
|
|
|
(my $essential_pkgs, my $cached_debs) = run_download($options);
|
2020-04-09 21:07:02 +00:00
|
|
|
|
2021-08-17 21:39:20 +00:00
|
|
|
# in theory, we don't have to extract the packages in chrootless mode
|
|
|
|
# but we do it anyways because otherwise directory creation timestamps
|
|
|
|
# will differ compared to non-chrootless and we want to create bit-by-bit
|
|
|
|
# identical tar output
|
|
|
|
#
|
|
|
|
# FIXME: dpkg could be changed to produce the same results
|
|
|
|
run_extract($options, $essential_pkgs);
|
2020-04-09 21:07:02 +00:00
|
|
|
|
2022-11-10 13:53:36 +00:00
|
|
|
# setup mounts
|
|
|
|
my @cleanup_tasks = ();
|
|
|
|
my $cleanup = sub {
|
|
|
|
my $signal = $_[0];
|
|
|
|
while (my $task = pop @cleanup_tasks) {
|
|
|
|
$task->();
|
2020-04-09 21:07:02 +00:00
|
|
|
}
|
2022-11-10 13:53:36 +00:00
|
|
|
if ($signal) {
|
|
|
|
warning "pid $PID cought signal: $signal";
|
|
|
|
exit 1;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
# we only need to setup the mounts if there is anything to do
|
|
|
|
if ( $options->{variant} ne 'custom'
|
|
|
|
or scalar @{ $options->{include} } > 0
|
|
|
|
or scalar @{ $options->{"extract_hook"} } > 0
|
|
|
|
or scalar @{ $options->{"essential_hook"} } > 0
|
|
|
|
or scalar @{ $options->{"customize_hook"} } > 0) {
|
|
|
|
local $SIG{INT} = $cleanup;
|
|
|
|
local $SIG{HUP} = $cleanup;
|
|
|
|
local $SIG{PIPE} = $cleanup;
|
|
|
|
local $SIG{TERM} = $cleanup;
|
|
|
|
|
|
|
|
@cleanup_tasks = setup_mounts($options);
|
|
|
|
}
|
|
|
|
|
|
|
|
eval {
|
2022-12-22 10:51:01 +00:00
|
|
|
my $chrootcmd = [];
|
2022-11-10 13:53:36 +00:00
|
|
|
if ($options->{variant} ne 'extract') {
|
|
|
|
if ($options->{mode} ne 'chrootless') {
|
|
|
|
$chrootcmd = run_prepare($options);
|
|
|
|
}
|
2022-12-22 10:51:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
run_hooks('extract', $options, $essential_pkgs);
|
2020-04-09 21:07:02 +00:00
|
|
|
|
2022-12-22 10:51:01 +00:00
|
|
|
if ($options->{variant} ne 'extract') {
|
2022-11-10 13:53:36 +00:00
|
|
|
run_essential($options, $essential_pkgs, $chrootcmd, $cached_debs);
|
2020-04-09 21:07:02 +00:00
|
|
|
|
2022-11-10 13:53:36 +00:00
|
|
|
run_hooks('essential', $options);
|
2020-04-09 21:07:02 +00:00
|
|
|
|
2022-11-10 13:53:36 +00:00
|
|
|
run_install($options);
|
2020-04-09 21:07:02 +00:00
|
|
|
|
2022-11-10 13:53:36 +00:00
|
|
|
run_hooks('customize', $options);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
my $msg = $@;
|
|
|
|
|
2024-08-18 11:10:18 +00:00
|
|
|
# Wait for (reap) potential zombies and otherwise long-running background
|
|
|
|
# processes or otherwise they might hog resources like /dev/null which can
|
|
|
|
# then not be unmounted resulting in their mountpoints (the regular files)
|
|
|
|
# not being removable and then the removal of device nodes in run_cleanup
|
|
|
|
# (if mmdebstrap is run with --skip=output/dev) will fail.
|
|
|
|
if (any { $_ eq 'zombie-reaping' } @{ $options->{skip} }) {
|
|
|
|
info "skipping zombie-reaping as requested";
|
|
|
|
} else {
|
|
|
|
if (waitpid(-1, POSIX::WNOHANG) >= 0) {
|
|
|
|
info "waiting for background processes to finish...";
|
|
|
|
}
|
|
|
|
while ((my $child = waitpid(-1, 0)) > 0) {
|
|
|
|
my $status = $? >> 8;
|
|
|
|
info "PID $child exited with exit code $status";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-10 13:53:36 +00:00
|
|
|
$cleanup->(0);
|
|
|
|
if ($msg) {
|
|
|
|
error "setup failed: $msg";
|
2020-04-09 21:07:02 +00:00
|
|
|
}
|
|
|
|
|
2021-08-17 09:11:00 +00:00
|
|
|
if (any { $_ eq 'cleanup' } @{ $options->{skip} }) {
|
|
|
|
info "skipping cleanup as requested";
|
|
|
|
} else {
|
|
|
|
run_cleanup($options);
|
|
|
|
}
|
2020-04-09 21:07:02 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub run_setup() {
|
|
|
|
my $options = shift;
|
|
|
|
|
2020-03-07 22:40:55 +00:00
|
|
|
{
|
|
|
|
my @directories = (
|
|
|
|
'/etc/apt/apt.conf.d', '/etc/apt/sources.list.d',
|
|
|
|
'/etc/apt/preferences.d', '/var/cache/apt',
|
2020-08-15 16:09:06 +00:00
|
|
|
'/var/lib/apt/lists/partial', '/tmp'
|
2020-03-07 22:40:55 +00:00
|
|
|
);
|
2020-08-15 16:09:06 +00:00
|
|
|
# we need /var/lib/dpkg in case we need to write to /var/lib/dpkg/arch
|
|
|
|
push @directories, '/var/lib/dpkg';
|
2020-08-24 14:28:32 +00:00
|
|
|
# since we do not know the dpkg version inside the chroot at this
|
|
|
|
# point, we can only omit it in chrootless mode
|
2021-10-07 06:12:12 +00:00
|
|
|
if ($options->{mode} ne 'chrootless'
|
2024-01-09 10:21:53 +00:00
|
|
|
or length $options->{dpkgopts} > 0) {
|
2020-08-15 16:09:06 +00:00
|
|
|
push @directories, '/etc/dpkg/dpkg.cfg.d/';
|
|
|
|
}
|
2020-03-07 22:40:55 +00:00
|
|
|
# if dpkg and apt operate from the outside we need some more
|
|
|
|
# directories because dpkg and apt might not even be installed inside
|
2021-08-17 21:39:20 +00:00
|
|
|
# the chroot. Thus, the following block is not strictly necessary in
|
|
|
|
# chrootless mode. We unconditionally add it anyways, so that the
|
|
|
|
# output with and without chrootless mode is equal.
|
|
|
|
{
|
2020-08-15 16:09:06 +00:00
|
|
|
push @directories, '/var/log/apt';
|
2020-08-24 14:28:32 +00:00
|
|
|
# since we do not know the dpkg version inside the chroot at this
|
|
|
|
# point, we can only omit it in chrootless mode
|
2021-10-07 06:12:12 +00:00
|
|
|
if ($options->{mode} ne 'chrootless') {
|
2020-08-15 16:09:06 +00:00
|
|
|
push @directories, '/var/lib/dpkg/triggers',
|
|
|
|
'/var/lib/dpkg/info', '/var/lib/dpkg/alternatives',
|
|
|
|
'/var/lib/dpkg/updates';
|
|
|
|
}
|
2020-03-07 22:40:55 +00:00
|
|
|
}
|
|
|
|
foreach my $dir (@directories) {
|
|
|
|
if (-e "$options->{root}/$dir") {
|
|
|
|
if (!-d "$options->{root}/$dir") {
|
|
|
|
error "$dir already exists but is not a directory";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
my $num_created = make_path "$options->{root}/$dir",
|
|
|
|
{ error => \my $err };
|
|
|
|
if ($err && @$err) {
|
|
|
|
error(
|
|
|
|
join "; ",
|
|
|
|
(map { "cannot create " . (join ": ", %{$_}) } @$err));
|
|
|
|
} elsif ($num_created == 0) {
|
|
|
|
error "cannot create $options->{root}/$dir";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-03 15:18:34 +00:00
|
|
|
# make sure /tmp is not 0755 like the rest
|
|
|
|
chmod 01777, "$options->{root}/tmp" or error "cannot chmod /tmp: $!";
|
2020-03-07 22:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# The TMPDIR set by the user or even /tmp might be inaccessible by the
|
|
|
|
# unshared user. Thus, we place all temporary files in /tmp inside the new
|
|
|
|
# rootfs.
|
|
|
|
#
|
|
|
|
# This will affect calls to tempfile() as well as runs of "apt-get update"
|
|
|
|
# which will create temporary clearsigned.message.XXXXXX files to verify
|
|
|
|
# signatures.
|
2021-08-25 03:20:46 +00:00
|
|
|
#
|
|
|
|
# Setting TMPDIR to inside the chroot is also necessary for when packages
|
|
|
|
# are installed with apt from outside the chroot with
|
|
|
|
# DPkg::Chroot-Directory
|
2020-03-07 22:40:55 +00:00
|
|
|
{
|
|
|
|
## no critic (Variables::RequireLocalizedPunctuationVars)
|
|
|
|
$ENV{"TMPDIR"} = "$options->{root}/tmp";
|
|
|
|
}
|
|
|
|
|
2020-03-07 01:11:35 +00:00
|
|
|
my ($conf, $tmpfile)
|
2020-03-07 22:40:55 +00:00
|
|
|
= tempfile("mmdebstrap.apt.conf.XXXXXXXXXXXX", TMPDIR => 1)
|
2020-01-08 16:44:07 +00:00
|
|
|
or error "cannot open apt.conf: $!";
|
2018-09-18 09:20:24 +00:00
|
|
|
print $conf "Apt::Architecture \"$options->{nativearch}\";\n";
|
|
|
|
# the host system might have configured additional architectures
|
|
|
|
# force only the native architecture
|
2020-01-08 16:44:07 +00:00
|
|
|
if (scalar @{ $options->{foreignarchs} } > 0) {
|
2020-01-08 14:41:49 +00:00
|
|
|
print $conf "Apt::Architectures { \"$options->{nativearch}\"; ";
|
2020-01-08 16:44:07 +00:00
|
|
|
foreach my $arch (@{ $options->{foreignarchs} }) {
|
2020-01-08 14:41:49 +00:00
|
|
|
print $conf "\"$arch\"; ";
|
|
|
|
}
|
|
|
|
print $conf "};\n";
|
2018-09-18 09:20:24 +00:00
|
|
|
} else {
|
2020-01-08 14:41:49 +00:00
|
|
|
print $conf "Apt::Architectures \"$options->{nativearch}\";\n";
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
2019-02-28 11:22:42 +00:00
|
|
|
print $conf "Dir \"$options->{root}\";\n";
|
2023-03-22 08:27:11 +00:00
|
|
|
print $conf "DPkg::Chroot-Directory \"$options->{root}\";\n";
|
2019-04-25 06:51:42 +00:00
|
|
|
# not needed anymore for apt 1.3 and newer
|
2020-01-08 16:44:07 +00:00
|
|
|
print $conf
|
|
|
|
"Dir::State::Status \"$options->{root}/var/lib/dpkg/status\";\n";
|
2018-09-18 09:20:24 +00:00
|
|
|
# for authentication, use the keyrings from the host
|
2019-12-03 09:16:39 +00:00
|
|
|
print $conf "Dir::Etc::Trusted \"$options->{apttrusted}\";\n";
|
|
|
|
print $conf "Dir::Etc::TrustedParts \"$options->{apttrustedparts}\";\n";
|
2024-06-03 05:59:51 +00:00
|
|
|
# apt considers itself essential. Thus, when generating an EDSP document
|
|
|
|
# for an external solver, it will add the Essential:yes field to the apt
|
|
|
|
# package stanza. This is unnecessary because we compile the set of
|
|
|
|
# packages we consider essential ourselves and for the 'essential' variant
|
|
|
|
# it would even be wrong to add apt. This workaround is only needed when
|
|
|
|
# apt is used with an external solver but doesn't hurt otherwise and we
|
|
|
|
# don't have a good way to figure out whether apt is using an external
|
|
|
|
# solver or not short of parsing the --aptopt options.
|
|
|
|
print $conf "pkgCacheGen::ForceEssential \",\";\n";
|
|
|
|
|
2018-09-18 09:20:24 +00:00
|
|
|
close $conf;
|
|
|
|
|
2018-09-23 17:43:14 +00:00
|
|
|
# We put certain configuration items in their own configuration file
|
|
|
|
# because they have to be valid for apt invocation from outside as well as
|
|
|
|
# from inside the chroot.
|
|
|
|
# The config filename is chosen such that any settings in it will be
|
|
|
|
# overridden by what the user specified with --aptopt.
|
2022-01-07 13:44:01 +00:00
|
|
|
if (!-e "$options->{root}/etc/apt/apt.conf.d/00mmdebstrap") {
|
2020-01-08 16:44:07 +00:00
|
|
|
open my $fh, '>', "$options->{root}/etc/apt/apt.conf.d/00mmdebstrap"
|
|
|
|
or error "cannot open /etc/apt/apt.conf.d/00mmdebstrap: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
print $fh "Apt::Install-Recommends false;\n";
|
|
|
|
print $fh "Acquire::Languages \"none\";\n";
|
|
|
|
close $fh;
|
2018-09-23 17:43:14 +00:00
|
|
|
}
|
|
|
|
|
2020-08-15 16:09:06 +00:00
|
|
|
# apt-get update requires this
|
2022-01-07 13:44:01 +00:00
|
|
|
if (!-e "$options->{root}/var/lib/dpkg/status") {
|
2020-01-08 16:44:07 +00:00
|
|
|
open my $fh, '>', "$options->{root}/var/lib/dpkg/status"
|
|
|
|
or error "failed to open(): $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
close $fh;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2022-09-22 12:22:37 +00:00
|
|
|
# In theory, /var/lib/dpkg/arch is only useful if there are foreign
|
|
|
|
# architectures configured or if the architecture of a chrootless chroot
|
|
|
|
# is different from the native architecture outside the chroot.
|
|
|
|
# We nevertheless always add /var/lib/dpkg/arch to make a chroot built the
|
|
|
|
# normal way bit-by-bit identical to a foreign arch chroot built in
|
|
|
|
# chrootless mode.
|
|
|
|
if ((!-e "$options->{root}/var/lib/dpkg/arch")) {
|
2020-01-08 16:44:07 +00:00
|
|
|
open my $fh, '>', "$options->{root}/var/lib/dpkg/arch"
|
|
|
|
or error "cannot open /var/lib/dpkg/arch: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
print $fh "$options->{nativearch}\n";
|
2020-01-08 16:44:07 +00:00
|
|
|
foreach my $arch (@{ $options->{foreignarchs} }) {
|
2020-01-08 14:41:49 +00:00
|
|
|
print $fh "$arch\n";
|
|
|
|
}
|
|
|
|
close $fh;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2024-01-09 10:21:53 +00:00
|
|
|
if (length $options->{aptopts} > 0
|
2022-01-07 13:44:01 +00:00
|
|
|
and (!-e "$options->{root}/etc/apt/apt.conf.d/99mmdebstrap")) {
|
2020-01-08 16:44:07 +00:00
|
|
|
open my $fh, '>', "$options->{root}/etc/apt/apt.conf.d/99mmdebstrap"
|
|
|
|
or error "cannot open /etc/apt/apt.conf.d/99mmdebstrap: $!";
|
2024-01-09 10:21:53 +00:00
|
|
|
print $fh $options->{aptopts};
|
2020-01-08 14:41:49 +00:00
|
|
|
close $fh;
|
2020-04-10 10:55:31 +00:00
|
|
|
if ($verbosity_level >= 3) {
|
|
|
|
debug "content of /etc/apt/apt.conf.d/99mmdebstrap:";
|
|
|
|
copy("$options->{root}/etc/apt/apt.conf.d/99mmdebstrap", \*STDERR);
|
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2024-01-09 10:21:53 +00:00
|
|
|
if (length $options->{dpkgopts} > 0
|
2022-01-07 13:44:01 +00:00
|
|
|
and (!-e "$options->{root}/etc/dpkg/dpkg.cfg.d/99mmdebstrap")) {
|
2020-01-08 14:41:49 +00:00
|
|
|
# FIXME: in chrootless mode, dpkg will only read the configuration
|
2021-02-23 11:49:46 +00:00
|
|
|
# from the host -- see #808203
|
|
|
|
if ($options->{mode} eq 'chrootless') {
|
|
|
|
warning('dpkg is unable to read an alternative configuration in'
|
|
|
|
. 'chrootless mode -- see Debian bug #808203');
|
|
|
|
}
|
2020-01-08 16:44:07 +00:00
|
|
|
open my $fh, '>', "$options->{root}/etc/dpkg/dpkg.cfg.d/99mmdebstrap"
|
|
|
|
or error "cannot open /etc/dpkg/dpkg.cfg.d/99mmdebstrap: $!";
|
2024-01-09 10:21:53 +00:00
|
|
|
print $fh $options->{dpkgopts};
|
2020-01-08 14:41:49 +00:00
|
|
|
close $fh;
|
2020-04-10 10:55:31 +00:00
|
|
|
if ($verbosity_level >= 3) {
|
|
|
|
debug "content of /etc/dpkg/dpkg.cfg.d/99mmdebstrap:";
|
|
|
|
copy("$options->{root}/etc/dpkg/dpkg.cfg.d/99mmdebstrap",
|
|
|
|
\*STDERR);
|
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2022-01-07 13:44:01 +00:00
|
|
|
if (!-e "$options->{root}/etc/fstab") {
|
2020-01-08 16:44:07 +00:00
|
|
|
open my $fh, '>', "$options->{root}/etc/fstab"
|
|
|
|
or error "cannot open fstab: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
print $fh "# UNCONFIGURED FSTAB FOR BASE SYSTEM\n";
|
|
|
|
close $fh;
|
2020-01-08 16:44:07 +00:00
|
|
|
chmod 0644, "$options->{root}/etc/fstab"
|
|
|
|
or error "cannot chmod fstab: $!";
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2020-01-22 22:30:28 +00:00
|
|
|
# write /etc/apt/sources.list and files in /etc/apt/sources.list.d/
|
2023-01-16 14:13:39 +00:00
|
|
|
if (scalar @{ $options->{sourceslists} } > 0) {
|
2020-01-22 22:30:28 +00:00
|
|
|
my $firstentry = $options->{sourceslists}->[0];
|
|
|
|
# if the first sources.list entry is of one-line type and without
|
|
|
|
# explicit filename, then write out an actual /etc/apt/sources.list
|
|
|
|
# otherwise everything goes into /etc/apt/sources.list.d
|
|
|
|
my $fname;
|
|
|
|
if ($firstentry->{type} eq 'one-line'
|
|
|
|
&& !defined $firstentry->{fname}) {
|
|
|
|
$fname = "$options->{root}/etc/apt/sources.list";
|
|
|
|
} else {
|
|
|
|
$fname = "$options->{root}/etc/apt/sources.list.d/0000";
|
|
|
|
if (defined $firstentry->{fname}) {
|
|
|
|
$fname .= $firstentry->{fname};
|
|
|
|
if ( $firstentry->{fname} !~ /\.list/
|
|
|
|
&& $firstentry->{fname} !~ /\.sources/) {
|
|
|
|
if ($firstentry->{type} eq 'one-line') {
|
|
|
|
$fname .= '.list';
|
|
|
|
} elsif ($firstentry->{type} eq 'deb822') {
|
|
|
|
$fname .= '.sources';
|
|
|
|
} else {
|
|
|
|
error "invalid type: $firstentry->{type}";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
# if no filename is given, then this must be a deb822 file
|
|
|
|
# because if it was a one-line type file, then it would've been
|
|
|
|
# written to /etc/apt/sources.list
|
|
|
|
$fname .= 'main.sources';
|
|
|
|
}
|
|
|
|
}
|
2022-01-07 13:44:01 +00:00
|
|
|
if (!-e $fname) {
|
|
|
|
open my $fh, '>', "$fname" or error "cannot open $fname: $!";
|
|
|
|
print $fh $firstentry->{content};
|
|
|
|
close $fh;
|
|
|
|
}
|
2020-01-22 22:30:28 +00:00
|
|
|
# everything else goes into /etc/apt/sources.list.d/
|
|
|
|
for (my $i = 1 ; $i < scalar @{ $options->{sourceslists} } ; $i++) {
|
|
|
|
my $entry = $options->{sourceslists}->[$i];
|
|
|
|
my $fname = "$options->{root}/etc/apt/sources.list.d/"
|
|
|
|
. sprintf("%04d", $i);
|
|
|
|
if (defined $entry->{fname}) {
|
|
|
|
$fname .= $entry->{fname};
|
|
|
|
if ( $entry->{fname} !~ /\.list/
|
|
|
|
&& $entry->{fname} !~ /\.sources/) {
|
|
|
|
if ($entry->{type} eq 'one-line') {
|
|
|
|
$fname .= '.list';
|
|
|
|
} elsif ($entry->{type} eq 'deb822') {
|
|
|
|
$fname .= '.sources';
|
|
|
|
} else {
|
|
|
|
error "invalid type: $entry->{type}";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ($entry->{type} eq 'one-line') {
|
|
|
|
$fname .= 'main.list';
|
|
|
|
} elsif ($entry->{type} eq 'deb822') {
|
|
|
|
$fname .= 'main.sources';
|
|
|
|
} else {
|
|
|
|
error "invalid type: $entry->{type}";
|
|
|
|
}
|
|
|
|
}
|
2022-01-07 13:44:01 +00:00
|
|
|
if (!-e $fname) {
|
|
|
|
open my $fh, '>', "$fname" or error "cannot open $fname: $!";
|
|
|
|
print $fh $entry->{content};
|
|
|
|
close $fh;
|
|
|
|
}
|
2020-01-22 22:30:28 +00:00
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2018-10-22 15:05:56 +00:00
|
|
|
# allow network access from within
|
2020-11-29 19:54:31 +00:00
|
|
|
foreach my $file ("/etc/resolv.conf", "/etc/hostname") {
|
2022-01-07 13:44:01 +00:00
|
|
|
if (-e $file && !-e "$options->{root}/$file") {
|
2020-11-29 19:54:31 +00:00
|
|
|
# this will create a new file with 644 permissions and copy
|
|
|
|
# contents only even if $file was a symlink
|
|
|
|
copy($file, "$options->{root}/$file")
|
|
|
|
or error "cannot copy $file: $!";
|
|
|
|
# if the source was a regular file, preserve the permissions
|
|
|
|
if (-f $file) {
|
|
|
|
my $mode = (stat($file))[2];
|
|
|
|
$mode &= oct(7777); # mask off bits that aren't the mode
|
|
|
|
chmod $mode, "$options->{root}/$file"
|
|
|
|
or error "cannot chmod $file: $!";
|
|
|
|
}
|
2024-01-09 08:47:35 +00:00
|
|
|
} elsif (-e $file && -e "$options->{root}/$file") {
|
|
|
|
info "rootfs alreday contains $file";
|
2020-11-29 19:54:31 +00:00
|
|
|
} else {
|
|
|
|
warning("Host system does not have a $file to copy into the"
|
|
|
|
. " rootfs.");
|
|
|
|
}
|
2019-09-15 12:12:49 +00:00
|
|
|
}
|
2018-10-22 15:05:56 +00:00
|
|
|
|
|
|
|
if ($options->{havemknod}) {
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
foreach my $file (@linuxdevfiles) {
|
|
|
|
my ($fname, $mode, $type, $linkname, $devmajor, $devminor, undef)
|
2020-01-08 16:44:07 +00:00
|
|
|
= @{$file};
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
if ($type eq '0') { # normal file
|
2020-01-08 14:41:49 +00:00
|
|
|
error "type 0 not implemented";
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
} elsif ($type eq '1') { # hardlink
|
2020-01-08 14:41:49 +00:00
|
|
|
error "type 1 not implemented";
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
} elsif ($type eq '2') { # symlink
|
2020-01-08 16:44:07 +00:00
|
|
|
if ( $options->{mode} eq 'fakechroot'
|
|
|
|
and $linkname =~ /^\/proc/) {
|
2020-01-08 14:41:49 +00:00
|
|
|
# there is no /proc in fakechroot mode
|
|
|
|
next;
|
|
|
|
}
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
symlink $linkname, "$options->{root}/$fname"
|
|
|
|
or error "cannot create symlink $fname";
|
2021-12-14 15:10:25 +00:00
|
|
|
next; # chmod cannot work on symlinks
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
} elsif ($type eq '3') { # character special
|
|
|
|
0 == system('mknod', "$options->{root}/$fname", 'c',
|
2020-01-08 16:44:07 +00:00
|
|
|
$devmajor, $devminor)
|
|
|
|
or error "mknod failed: $?";
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
} elsif ($type eq '4') { # block special
|
|
|
|
0 == system('mknod', "$options->{root}/$fname", 'b',
|
2020-01-08 16:44:07 +00:00
|
|
|
$devmajor, $devminor)
|
|
|
|
or error "mknod failed: $?";
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
} elsif ($type eq '5') { # directory
|
|
|
|
if (-e "$options->{root}/$fname") {
|
|
|
|
if (!-d "$options->{root}/$fname") {
|
|
|
|
error "$fname already exists but is not a directory";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
|
|
|
} else {
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
my $num_created = make_path "$options->{root}/$fname",
|
2020-01-08 16:44:07 +00:00
|
|
|
{ error => \my $err };
|
2020-01-08 14:41:49 +00:00
|
|
|
if ($err && @$err) {
|
2020-01-08 16:44:07 +00:00
|
|
|
error(
|
|
|
|
join "; ",
|
|
|
|
(
|
|
|
|
map { "cannot create " . (join ": ", %{$_}) }
|
|
|
|
@$err
|
|
|
|
));
|
2020-01-08 14:41:49 +00:00
|
|
|
} elsif ($num_created == 0) {
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
error "cannot create $options->{root}/$fname";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error "unsupported type: $type";
|
|
|
|
}
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
chmod $mode, "$options->{root}/$fname"
|
|
|
|
or error "cannot chmod $fname: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2018-10-22 15:05:56 +00:00
|
|
|
}
|
|
|
|
|
2018-09-18 09:20:24 +00:00
|
|
|
# we tell apt about the configuration via a config file passed via the
|
|
|
|
# APT_CONFIG environment variable instead of using the --option command
|
|
|
|
# line arguments because configuration settings like Dir::Etc have already
|
|
|
|
# been evaluated at the time that apt takes its command line arguments
|
|
|
|
# into account.
|
2020-01-09 07:39:40 +00:00
|
|
|
{
|
|
|
|
## no critic (Variables::RequireLocalizedPunctuationVars)
|
|
|
|
$ENV{"APT_CONFIG"} = "$tmpfile";
|
|
|
|
}
|
2020-11-13 18:02:41 +00:00
|
|
|
# we have to make the config file world readable so that a possible
|
|
|
|
# /usr/lib/apt/solvers/apt process which is run by the _apt user is also
|
|
|
|
# able to read it
|
2023-03-16 20:23:41 +00:00
|
|
|
chmod 0644, "$tmpfile" or error "cannot chmod $tmpfile: $!";
|
2020-01-21 12:12:44 +00:00
|
|
|
if ($verbosity_level >= 3) {
|
2020-04-09 10:51:24 +00:00
|
|
|
0 == system('apt-get', '--version')
|
|
|
|
or error "apt-get --version failed: $?";
|
2020-01-21 12:12:44 +00:00
|
|
|
0 == system('apt-config', 'dump') or error "apt-config failed: $?";
|
2020-03-07 01:13:26 +00:00
|
|
|
debug "content of $tmpfile:";
|
|
|
|
copy($tmpfile, \*STDERR);
|
2020-01-21 12:12:44 +00:00
|
|
|
}
|
2018-09-21 06:04:40 +00:00
|
|
|
|
2022-09-05 03:50:50 +00:00
|
|
|
if ($options->{mode} ne 'fakechroot') {
|
2020-06-08 13:45:22 +00:00
|
|
|
# Apt dropping privileges to another user than root is not useful in
|
2022-09-05 03:50:50 +00:00
|
|
|
# fakechroot mode because all users are faked and thus there is no real
|
|
|
|
# privilege difference anyways. We could set APT::Sandbox::User "root"
|
|
|
|
# in fakechroot mode but we don't because if we would, then
|
|
|
|
# /var/cache/apt/archives/partial/ and /var/lib/apt/lists/partial/
|
|
|
|
# would not be owned by the _apt user if mmdebstrap was run in
|
|
|
|
# fakechroot mode.
|
2021-08-27 17:50:11 +00:00
|
|
|
#
|
2020-06-08 13:45:22 +00:00
|
|
|
# when apt-get update is run by the root user, then apt will attempt to
|
|
|
|
# drop privileges to the _apt user. This will fail if the _apt user
|
|
|
|
# does not have permissions to read the root directory. In that case,
|
|
|
|
# we have to disable apt sandboxing. This can for example happen in
|
|
|
|
# root mode when the path of the chroot is not in a world-readable
|
|
|
|
# location.
|
2020-01-08 14:41:49 +00:00
|
|
|
my $partial = '/var/lib/apt/lists/partial';
|
2023-01-26 08:28:35 +00:00
|
|
|
my @testcmd = (
|
|
|
|
'/usr/lib/apt/apt-helper', 'drop-privs', '--', 'test',
|
|
|
|
'-r', "$options->{root}$partial"
|
|
|
|
);
|
|
|
|
my $pid = fork() // error "fork() failed: $!";
|
|
|
|
if ($pid == 0) {
|
|
|
|
open(STDOUT, '>', '/dev/null')
|
|
|
|
or error "cannot open /dev/null for writing: $!";
|
|
|
|
open(STDERR, '>', '/dev/null')
|
|
|
|
or error "cannot open /dev/null for writing: $!";
|
|
|
|
exec { $testcmd[0] } @testcmd
|
|
|
|
or error("cannot exec " . (join " ", @testcmd) . ": $!");
|
|
|
|
}
|
|
|
|
waitpid $pid, 0;
|
|
|
|
if ($? != 0) {
|
2020-01-08 16:41:46 +00:00
|
|
|
warning "Download is performed unsandboxed as root as file"
|
|
|
|
. " $options->{root}$partial couldn't be accessed by user _apt";
|
2020-01-08 16:44:07 +00:00
|
|
|
open my $fh, '>>', $tmpfile
|
|
|
|
or error "cannot open $tmpfile for appending: $!";
|
2020-01-08 14:41:49 +00:00
|
|
|
print $fh "APT::Sandbox::User \"root\";\n";
|
|
|
|
close $fh;
|
|
|
|
}
|
2019-02-28 10:54:03 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 21:07:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub run_update() {
|
|
|
|
my $options = shift;
|
2019-02-20 12:32:49 +00:00
|
|
|
|
2021-05-31 09:17:39 +00:00
|
|
|
my $aptopts = {
|
2021-10-06 19:19:00 +00:00
|
|
|
ARGV => ['apt-get', 'update', '--error-on=any'],
|
2021-05-31 09:17:39 +00:00
|
|
|
CHDIR => $options->{root},
|
|
|
|
};
|
|
|
|
|
2023-01-16 06:39:15 +00:00
|
|
|
# Maybe "apt-get update" was already run in the setup hook? If yes, skip
|
|
|
|
# running it here. We are overly strict on purpose because better to run it
|
|
|
|
# twice on accident than not at all.
|
|
|
|
if ( !-d "$options->{root}/var/lib/apt/lists/auxfiles"
|
|
|
|
|| !-d "$options->{root}/var/lib/apt/lists/partial"
|
|
|
|
|| !-e "$options->{root}/var/lib/apt/lists/lock"
|
|
|
|
|| !-e "$options->{root}/var/cache/apt/pkgcache.bin"
|
|
|
|
|| !-e "$options->{root}/var/cache/apt/srcpkgcache.bin") {
|
|
|
|
info "running apt-get update...";
|
|
|
|
run_apt_progress($aptopts);
|
|
|
|
} else {
|
|
|
|
info "skipping apt-get update because it was already run";
|
|
|
|
}
|
2018-09-21 06:04:40 +00:00
|
|
|
|
|
|
|
# check if anything was downloaded at all
|
|
|
|
{
|
2020-01-08 16:44:07 +00:00
|
|
|
open my $fh, '-|', 'apt-get',
|
|
|
|
'indextargets' // error "failed to fork(): $!";
|
|
|
|
chomp(
|
|
|
|
my $indextargets = do { local $/; <$fh> }
|
|
|
|
);
|
2020-01-08 14:41:49 +00:00
|
|
|
close $fh;
|
|
|
|
if ($indextargets eq '') {
|
2023-01-16 06:54:27 +00:00
|
|
|
warning("apt-get indextargets output is empty");
|
2023-01-16 14:13:39 +00:00
|
|
|
if (scalar @{ $options->{sourceslists} } == 0) {
|
|
|
|
warning "no known apt sources.list entry";
|
|
|
|
}
|
2023-01-16 06:54:27 +00:00
|
|
|
for my $list (@{ $options->{sourceslists} }) {
|
|
|
|
if (defined $list->{fname}) {
|
|
|
|
info("Filename: $list->{fname}");
|
|
|
|
}
|
|
|
|
info("Type: $list->{type}");
|
|
|
|
info("Content:");
|
|
|
|
for my $line (split "\n", $list->{content}) {
|
|
|
|
info(" $line");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
open(my $fh, '-|', 'apt-cache', 'policy')
|
|
|
|
// error "failed to fork(): $!";
|
|
|
|
while (my $line = <$fh>) {
|
|
|
|
chomp $line;
|
|
|
|
info $line;
|
|
|
|
}
|
|
|
|
close $fh;
|
|
|
|
my $msg
|
|
|
|
= "apt-get update did not find any indices "
|
|
|
|
. "for architecture '$options->{nativearch}' in ";
|
|
|
|
if (length $options->{suite}) {
|
|
|
|
$msg .= "suite '$options->{suite}'";
|
|
|
|
} else {
|
|
|
|
$msg .= "the configured apt sources";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2023-01-16 06:54:27 +00:00
|
|
|
error $msg;
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2018-09-21 06:04:40 +00:00
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
|
2020-04-09 21:07:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub run_download() {
|
|
|
|
my $options = shift;
|
|
|
|
|
2021-08-25 03:20:46 +00:00
|
|
|
# In the future we want to replace downloading packages with "apt-get
|
2022-05-24 09:47:16 +00:00
|
|
|
# install" and installing them with dpkg by just installing the essential
|
|
|
|
# packages with apt from the outside with DPkg::Chroot-Directory.
|
|
|
|
# We are not doing that because then the preinst script of base-passwd will
|
|
|
|
# not be called early enough and packages will fail to install because they
|
|
|
|
# are missing /etc/passwd.
|
2020-11-13 18:02:41 +00:00
|
|
|
my @cached_debs = ();
|
|
|
|
my @dl_debs = ();
|
|
|
|
if (
|
|
|
|
!$options->{dryrun}
|
|
|
|
&& ((none { $_ eq $options->{variant} } ('extract', 'custom'))
|
2021-11-09 06:31:56 +00:00
|
|
|
|| scalar @{ $options->{include} } != 0)
|
2020-11-13 18:02:41 +00:00
|
|
|
&& -d "$options->{root}/var/cache/apt/archives/"
|
|
|
|
) {
|
|
|
|
my $apt_archives = "/var/cache/apt/archives/";
|
|
|
|
opendir my $dh, "$options->{root}/$apt_archives"
|
|
|
|
or error "cannot read $apt_archives";
|
|
|
|
while (my $deb = readdir $dh) {
|
|
|
|
if ($deb !~ /\.deb$/) {
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
if (!-f "$options->{root}/$apt_archives/$deb") {
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
push @cached_debs, $deb;
|
|
|
|
}
|
|
|
|
closedir $dh;
|
|
|
|
}
|
|
|
|
|
2018-09-18 09:20:24 +00:00
|
|
|
# To figure out the right package set for the apt variant we can use:
|
|
|
|
# $ apt-get dist-upgrade -o dir::state::status=/dev/null
|
|
|
|
# This is because that variants only contain essential packages and
|
|
|
|
# apt and libapt treats apt as essential. If we want to install less
|
|
|
|
# (essential variant) then we have to compute the package set ourselves.
|
|
|
|
# Same if we want to install priority based variants.
|
2018-10-22 15:05:56 +00:00
|
|
|
if (any { $_ eq $options->{variant} } ('extract', 'custom')) {
|
2021-11-09 06:31:56 +00:00
|
|
|
if (scalar @{ $options->{include} } == 0) {
|
2020-05-03 13:06:24 +00:00
|
|
|
info "nothing to download -- skipping...";
|
2022-05-23 21:30:29 +00:00
|
|
|
return ([], \@cached_debs);
|
2020-05-03 13:06:24 +00:00
|
|
|
}
|
2023-01-16 11:13:21 +00:00
|
|
|
my @apt_argv = ('install', @{ $options->{include} });
|
2020-05-03 13:06:24 +00:00
|
|
|
|
2022-05-24 09:47:16 +00:00
|
|
|
@dl_debs = run_apt_download_progress({
|
|
|
|
APT_ARGV => [@apt_argv],
|
|
|
|
dryrun => $options->{dryrun},
|
|
|
|
},
|
|
|
|
);
|
2022-11-14 13:34:15 +00:00
|
|
|
} elsif (any { $_ eq $options->{variant} }
|
2024-06-03 05:59:51 +00:00
|
|
|
('essential', 'apt', 'standard', 'important', 'required', 'buildd')) {
|
2021-08-17 08:29:56 +00:00
|
|
|
# 2021-06-07, #debian-apt on OFTC, times in UTC+2
|
|
|
|
# 17:27 < DonKult> (?essential includes 'apt' through)
|
|
|
|
# 17:30 < josch> DonKult: no, because pkgCacheGen::ForceEssential ",";
|
|
|
|
# 17:32 < DonKult> touché
|
2022-05-24 09:47:16 +00:00
|
|
|
@dl_debs = run_apt_download_progress({
|
|
|
|
APT_ARGV => [
|
2021-08-17 08:29:56 +00:00
|
|
|
'install',
|
|
|
|
'?narrow('
|
|
|
|
. (
|
2021-11-09 06:31:56 +00:00
|
|
|
length($options->{suite})
|
2022-01-07 11:46:35 +00:00
|
|
|
? '?or(?archive(^'
|
|
|
|
. $options->{suite}
|
|
|
|
. '$),?codename(^'
|
|
|
|
. $options->{suite} . '$)),'
|
2021-08-17 08:29:56 +00:00
|
|
|
: ''
|
|
|
|
)
|
|
|
|
. '?architecture('
|
|
|
|
. $options->{nativearch}
|
|
|
|
. '),?essential)'
|
|
|
|
],
|
2022-05-24 09:47:16 +00:00
|
|
|
dryrun => $options->{dryrun},
|
|
|
|
},
|
|
|
|
);
|
2018-10-22 12:44:45 +00:00
|
|
|
} else {
|
2020-01-08 14:41:49 +00:00
|
|
|
error "unknown variant: $options->{variant}";
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2018-09-21 18:32:07 +00:00
|
|
|
my @essential_pkgs;
|
2022-05-24 09:47:16 +00:00
|
|
|
# strip the chroot directory from the filenames
|
|
|
|
foreach my $deb (@dl_debs) {
|
|
|
|
# if filename does not start with chroot directory then the user
|
|
|
|
# might've used a file:// mirror and we check whether the path is
|
|
|
|
# accessible inside the chroot
|
|
|
|
if (rindex $deb, $options->{root}, 0) {
|
|
|
|
if (!-e "$options->{root}/$deb") {
|
|
|
|
error "package file $deb not accessible from chroot directory"
|
2022-05-24 11:16:24 +00:00
|
|
|
. " -- use copy:// instead of file:// or a bind-mount. You"
|
|
|
|
. " can also try using --hook-dir=/usr/share/mmdebstrap/"
|
|
|
|
. "hooks/file-mirror-automount to automatically create"
|
2022-07-26 16:43:18 +00:00
|
|
|
. " bind-mounts or copy the files as necessary.";
|
2022-05-24 09:47:16 +00:00
|
|
|
}
|
|
|
|
push @essential_pkgs, $deb;
|
|
|
|
next;
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2022-05-24 09:47:16 +00:00
|
|
|
# filename starts with chroot directory, strip it off
|
|
|
|
# this is the normal case
|
|
|
|
if (!-e $deb) {
|
|
|
|
error "cannot find package file $deb";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2022-05-24 09:47:16 +00:00
|
|
|
push @essential_pkgs, substr($deb, length($options->{root}));
|
2018-09-21 18:32:07 +00:00
|
|
|
}
|
|
|
|
|
2021-11-09 06:31:56 +00:00
|
|
|
return (\@essential_pkgs, \@cached_debs);
|
2020-04-09 21:07:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub run_extract() {
|
|
|
|
my $options = shift;
|
|
|
|
my $essential_pkgs = shift;
|
|
|
|
|
|
|
|
if ($options->{dryrun}) {
|
2020-01-10 10:44:15 +00:00
|
|
|
info "skip extracting packages because of --dry-run";
|
2020-04-09 21:07:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-03 13:06:24 +00:00
|
|
|
if (scalar @{$essential_pkgs} == 0) {
|
|
|
|
info "nothing to extract -- skipping...";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-09 21:07:02 +00:00
|
|
|
info "extracting archives...";
|
|
|
|
print_progress 0.0;
|
|
|
|
my $counter = 0;
|
|
|
|
my $total = scalar @{$essential_pkgs};
|
|
|
|
foreach my $deb (@{$essential_pkgs}) {
|
|
|
|
$counter += 1;
|
2020-08-25 11:02:33 +00:00
|
|
|
|
|
|
|
my $tarfilter;
|
|
|
|
my @tarfilterargs;
|
|
|
|
# if the path-excluded option was added to the dpkg config,
|
|
|
|
# insert the tarfilter between dpkg-deb and tar
|
|
|
|
if (-e "$options->{root}/etc/dpkg/dpkg.cfg.d/99mmdebstrap") {
|
|
|
|
open(my $fh, '<',
|
|
|
|
"$options->{root}/etc/dpkg/dpkg.cfg.d/99mmdebstrap")
|
|
|
|
or error "cannot open /etc/dpkg/dpkg.cfg.d/99mmdebstrap: $!";
|
|
|
|
my @matches = grep { /^path-(?:exclude|include)=/ } <$fh>;
|
|
|
|
close $fh;
|
|
|
|
chop @matches; # remove trailing newline
|
|
|
|
@tarfilterargs = map { "--" . $_ } @matches;
|
|
|
|
}
|
|
|
|
if (scalar @tarfilterargs > 0) {
|
|
|
|
if (-x "./tarfilter") {
|
|
|
|
$tarfilter = "./tarfilter";
|
|
|
|
} else {
|
|
|
|
$tarfilter = "mmtarfilter";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
my $dpkg_writer;
|
|
|
|
my $tar_reader;
|
|
|
|
my $filter_reader;
|
|
|
|
my $filter_writer;
|
|
|
|
if (scalar @tarfilterargs > 0) {
|
|
|
|
pipe $filter_reader, $dpkg_writer or error "pipe failed: $!";
|
|
|
|
pipe $tar_reader, $filter_writer or error "pipe failed: $!";
|
|
|
|
} else {
|
|
|
|
pipe $tar_reader, $dpkg_writer or error "pipe failed: $!";
|
|
|
|
}
|
2020-04-09 21:07:02 +00:00
|
|
|
# not using dpkg-deb --extract as that would replace the
|
|
|
|
# merged-usr symlinks with plain directories
|
2023-10-23 09:48:32 +00:00
|
|
|
# even after switching from pre-merging to post-merging, dpkg-deb
|
|
|
|
# will ignore filter rules from dpkg.cfg.d
|
2021-08-25 03:20:46 +00:00
|
|
|
# https://bugs.debian.org/989602
|
2020-08-25 11:02:33 +00:00
|
|
|
# not using dpkg --unpack because that would try running preinst
|
|
|
|
# maintainer scripts
|
2020-04-09 21:07:02 +00:00
|
|
|
my $pid1 = fork() // error "fork() failed: $!";
|
|
|
|
if ($pid1 == 0) {
|
2020-08-25 11:02:33 +00:00
|
|
|
open(STDOUT, '>&', $dpkg_writer) or error "cannot open STDOUT: $!";
|
|
|
|
close($tar_reader) or error "cannot close tar_reader: $!";
|
|
|
|
if (scalar @tarfilterargs > 0) {
|
|
|
|
close($filter_reader)
|
|
|
|
or error "cannot close filter_reader: $!";
|
|
|
|
close($filter_writer)
|
|
|
|
or error "cannot close filter_writer: $!";
|
|
|
|
}
|
2020-04-09 21:07:02 +00:00
|
|
|
debug("running dpkg-deb --fsys-tarfile $options->{root}/$deb");
|
|
|
|
eval { Devel::Cover::set_coverage("none") } if $is_covering;
|
|
|
|
exec 'dpkg-deb', '--fsys-tarfile', "$options->{root}/$deb";
|
|
|
|
}
|
2020-08-25 11:02:33 +00:00
|
|
|
my $pid2;
|
|
|
|
if (scalar @tarfilterargs > 0) {
|
|
|
|
$pid2 = fork() // error "fork() failed: $!";
|
|
|
|
if ($pid2 == 0) {
|
|
|
|
open(STDIN, '<&', $filter_reader)
|
|
|
|
or error "cannot open STDIN: $!";
|
|
|
|
open(STDOUT, '>&', $filter_writer)
|
|
|
|
or error "cannot open STDOUT: $!";
|
|
|
|
close($dpkg_writer) or error "cannot close dpkg_writer: $!";
|
|
|
|
close($tar_reader) or error "cannot close tar_reader: $!";
|
|
|
|
debug("running $tarfilter " . (join " ", @tarfilterargs));
|
|
|
|
eval { Devel::Cover::set_coverage("none") } if $is_covering;
|
|
|
|
exec $tarfilter, @tarfilterargs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
my $pid3 = fork() // error "fork() failed: $!";
|
|
|
|
if ($pid3 == 0) {
|
|
|
|
open(STDIN, '<&', $tar_reader) or error "cannot open STDIN: $!";
|
|
|
|
close($dpkg_writer) or error "cannot close dpkg_writer: $!";
|
|
|
|
if (scalar @tarfilterargs > 0) {
|
|
|
|
close($filter_reader)
|
|
|
|
or error "cannot close filter_reader: $!";
|
|
|
|
close($filter_writer)
|
|
|
|
or error "cannot close filter_writer: $!";
|
|
|
|
}
|
2020-04-09 21:07:02 +00:00
|
|
|
debug( "running tar -C $options->{root}"
|
|
|
|
. " --keep-directory-symlink --extract --file -");
|
|
|
|
eval { Devel::Cover::set_coverage("none") } if $is_covering;
|
|
|
|
exec 'tar', '-C', $options->{root},
|
|
|
|
'--keep-directory-symlink', '--extract', '--file', '-';
|
|
|
|
}
|
2020-08-25 11:02:33 +00:00
|
|
|
close($dpkg_writer) or error "cannot close dpkg_writer: $!";
|
|
|
|
close($tar_reader) or error "cannot close tar_reader: $!";
|
|
|
|
if (scalar @tarfilterargs > 0) {
|
|
|
|
close($filter_reader) or error "cannot close filter_reader: $!";
|
|
|
|
close($filter_writer) or error "cannot close filter_writer: $!";
|
|
|
|
}
|
2020-04-09 21:07:02 +00:00
|
|
|
waitpid($pid1, 0);
|
|
|
|
$? == 0 or error "dpkg-deb --fsys-tarfile failed: $?";
|
2020-08-25 11:02:33 +00:00
|
|
|
if (scalar @tarfilterargs > 0) {
|
|
|
|
waitpid($pid2, 0);
|
|
|
|
$? == 0 or error "tarfilter failed: $?";
|
|
|
|
}
|
|
|
|
waitpid($pid3, 0);
|
2020-04-09 21:07:02 +00:00
|
|
|
$? == 0 or error "tar --extract failed: $?";
|
2022-10-16 20:03:06 +00:00
|
|
|
print_progress($counter / $total * 100, "extracting");
|
2020-04-09 21:07:02 +00:00
|
|
|
}
|
|
|
|
print_progress "done";
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub run_prepare {
|
|
|
|
my $options = shift;
|
|
|
|
|
|
|
|
if ($options->{mode} eq 'fakechroot') {
|
|
|
|
# this borrows from and extends
|
|
|
|
# /etc/fakechroot/debootstrap.env and
|
|
|
|
# /etc/fakechroot/chroot.env
|
|
|
|
{
|
2022-05-29 05:50:10 +00:00
|
|
|
my %subst = (
|
|
|
|
chroot => "/usr/sbin/chroot.fakechroot",
|
|
|
|
mkfifo => "/bin/true",
|
|
|
|
ldconfig => (getcwd() . '/ldconfig.fakechroot'),
|
|
|
|
ldd => "/usr/bin/ldd.fakechroot",
|
|
|
|
ischroot => "/bin/true"
|
|
|
|
);
|
|
|
|
if (!-x $subst{ldconfig}) {
|
|
|
|
$subst{ldconfig}
|
|
|
|
= '/usr/libexec/mmdebstrap/ldconfig.fakechroot';
|
2021-09-16 14:23:46 +00:00
|
|
|
}
|
2023-01-23 15:35:35 +00:00
|
|
|
my %mergedusrmap = (
|
|
|
|
"/bin" => "/usr/bin",
|
|
|
|
"/sbin" => "/usr/sbin",
|
|
|
|
"/usr/bin/" => "/bin",
|
|
|
|
"/usr/sbin" => "/sbin"
|
|
|
|
);
|
2023-01-23 14:01:21 +00:00
|
|
|
my %fakechrootsubst;
|
2022-05-29 05:50:10 +00:00
|
|
|
foreach my $d (split ':', $ENV{PATH}) {
|
2023-01-23 14:01:21 +00:00
|
|
|
foreach my $k (sort %subst) {
|
2023-01-23 15:35:35 +00:00
|
|
|
my $mapped_path = $mergedusrmap{$d} // $d;
|
|
|
|
next if !-e "$d/$k" && !-e "$mapped_path/$k";
|
|
|
|
$fakechrootsubst{"$d/$k=$subst{$k}"} = 1;
|
|
|
|
$fakechrootsubst{"$mapped_path/$k=$subst{$k}"} = 1;
|
2022-05-29 05:50:10 +00:00
|
|
|
}
|
2020-04-09 21:07:02 +00:00
|
|
|
}
|
|
|
|
if (defined $ENV{FAKECHROOT_CMD_SUBST}
|
|
|
|
&& $ENV{FAKECHROOT_CMD_SUBST} ne "") {
|
2023-01-23 14:01:21 +00:00
|
|
|
foreach my $e (split /:/, $ENV{FAKECHROOT_CMD_SUBST}) {
|
|
|
|
$fakechrootsubst{$e} = 1;
|
|
|
|
}
|
2020-04-09 21:07:02 +00:00
|
|
|
}
|
|
|
|
## no critic (Variables::RequireLocalizedPunctuationVars)
|
2023-01-23 14:01:21 +00:00
|
|
|
$ENV{FAKECHROOT_CMD_SUBST} = join ':',
|
|
|
|
(sort keys %fakechrootsubst);
|
2020-04-09 21:07:02 +00:00
|
|
|
}
|
|
|
|
if (defined $ENV{FAKECHROOT_EXCLUDE_PATH}
|
|
|
|
&& $ENV{FAKECHROOT_EXCLUDE_PATH} ne "") {
|
|
|
|
## no critic (Variables::RequireLocalizedPunctuationVars)
|
|
|
|
$ENV{FAKECHROOT_EXCLUDE_PATH}
|
|
|
|
= "$ENV{FAKECHROOT_EXCLUDE_PATH}:/dev:/proc:/sys";
|
|
|
|
} else {
|
|
|
|
## no critic (Variables::RequireLocalizedPunctuationVars)
|
|
|
|
$ENV{FAKECHROOT_EXCLUDE_PATH} = '/dev:/proc:/sys';
|
|
|
|
}
|
|
|
|
# workaround for long unix socket path if FAKECHROOT_BASE
|
|
|
|
# exceeds the limit of 108 bytes
|
|
|
|
{
|
|
|
|
## no critic (Variables::RequireLocalizedPunctuationVars)
|
|
|
|
$ENV{FAKECHROOT_AF_UNIX_PATH} = "/tmp";
|
|
|
|
}
|
|
|
|
{
|
|
|
|
my @ldlibpath = ();
|
|
|
|
if (defined $ENV{LD_LIBRARY_PATH}
|
|
|
|
&& $ENV{LD_LIBRARY_PATH} ne "") {
|
|
|
|
push @ldlibpath, (split /:/, $ENV{LD_LIBRARY_PATH});
|
|
|
|
}
|
|
|
|
# FIXME: workaround allowing installation of systemd should
|
|
|
|
# live in fakechroot, see #917920
|
2021-09-21 12:17:27 +00:00
|
|
|
push @ldlibpath, "$options->{root}/lib/systemd";
|
|
|
|
my $parse_ld_so_conf;
|
|
|
|
$parse_ld_so_conf = sub {
|
|
|
|
foreach my $conf (@_) {
|
|
|
|
next if !-r $conf;
|
|
|
|
open my $fh, '<', "$conf" or error "can't read $conf: $!";
|
|
|
|
while (my $line = <$fh>) {
|
|
|
|
chomp $line;
|
|
|
|
if ($line eq "") {
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
if ($line =~ /^#/) {
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
if ($line =~ /include (.*)/) {
|
|
|
|
$parse_ld_so_conf->(glob("$options->{root}/$1"));
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
if (!-d "$options->{root}/$line") {
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
push @ldlibpath, "$options->{root}/$line";
|
|
|
|
}
|
|
|
|
close $fh;
|
2020-04-09 21:07:02 +00:00
|
|
|
}
|
2021-09-21 12:17:27 +00:00
|
|
|
};
|
|
|
|
if (-e "$options->{root}/etc/ld.so.conf") {
|
|
|
|
$parse_ld_so_conf->("$options->{root}/etc/ld.so.conf");
|
2020-04-09 21:07:02 +00:00
|
|
|
}
|
|
|
|
## no critic (Variables::RequireLocalizedPunctuationVars)
|
|
|
|
$ENV{LD_LIBRARY_PATH} = join ':', @ldlibpath;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# make sure that APT_CONFIG and TMPDIR are not set when executing
|
|
|
|
# anything inside the chroot
|
|
|
|
my @chrootcmd = ('env', '--unset=APT_CONFIG', '--unset=TMPDIR');
|
2022-09-05 03:50:50 +00:00
|
|
|
if (any { $_ eq $options->{mode} } ('root', 'unshare', 'fakechroot')) {
|
2022-05-24 18:36:01 +00:00
|
|
|
push @chrootcmd, ('chroot', $options->{root});
|
2018-11-20 23:13:10 +00:00
|
|
|
} else {
|
2020-04-09 21:07:02 +00:00
|
|
|
error "unknown mode: $options->{mode}";
|
|
|
|
}
|
|
|
|
|
2023-09-27 12:02:00 +00:00
|
|
|
# foreign architecture setup for fakechroot mode
|
|
|
|
if (defined $options->{qemu} && $options->{mode} eq 'fakechroot') {
|
|
|
|
# Make sure that the fakeroot and fakechroot shared libraries exist for
|
|
|
|
# the right architecture
|
|
|
|
open my $fh, '-|', 'dpkg-architecture', '-a',
|
|
|
|
$options->{nativearch},
|
|
|
|
'-qDEB_HOST_MULTIARCH' // error "failed to fork(): $!";
|
|
|
|
chomp(
|
|
|
|
my $deb_host_multiarch = do { local $/; <$fh> }
|
|
|
|
);
|
|
|
|
close $fh;
|
|
|
|
if (($? != 0) or (!$deb_host_multiarch)) {
|
|
|
|
error "dpkg-architecture failed: $?";
|
|
|
|
}
|
|
|
|
my $fakechrootdir = "/usr/lib/$deb_host_multiarch/fakechroot";
|
|
|
|
if (!-e "$fakechrootdir/libfakechroot.so") {
|
|
|
|
error "$fakechrootdir/libfakechroot.so doesn't exist."
|
|
|
|
. " Install libfakechroot:$options->{nativearch}"
|
|
|
|
. " outside the chroot";
|
|
|
|
}
|
|
|
|
my $fakerootdir = "/usr/lib/$deb_host_multiarch/libfakeroot";
|
|
|
|
if (!-e "$fakerootdir/libfakeroot-sysv.so") {
|
|
|
|
error "$fakerootdir/libfakeroot-sysv.so doesn't exist."
|
|
|
|
. " Install libfakeroot:$options->{nativearch}"
|
|
|
|
. " outside the chroot";
|
|
|
|
}
|
|
|
|
|
|
|
|
# The rest of this block sets environment variables, so we have to add
|
|
|
|
# the "no critic" statement to stop perlcritic from complaining about
|
|
|
|
# setting global variables
|
|
|
|
## no critic (Variables::RequireLocalizedPunctuationVars)
|
|
|
|
# fakechroot only fills LD_LIBRARY_PATH with the directories of the
|
|
|
|
# host's architecture. We append the directories of the chroot
|
|
|
|
# architecture.
|
|
|
|
$ENV{LD_LIBRARY_PATH}
|
|
|
|
= "$ENV{LD_LIBRARY_PATH}:$fakechrootdir:$fakerootdir";
|
|
|
|
# The binfmt support on the outside is used, so qemu needs to know
|
|
|
|
# where it has to look for shared libraries
|
|
|
|
if (defined $ENV{QEMU_LD_PREFIX}
|
|
|
|
&& $ENV{QEMU_LD_PREFIX} ne "") {
|
|
|
|
$ENV{QEMU_LD_PREFIX} = "$ENV{QEMU_LD_PREFIX}:$options->{root}";
|
2020-04-09 21:07:02 +00:00
|
|
|
} else {
|
2023-09-27 12:02:00 +00:00
|
|
|
$ENV{QEMU_LD_PREFIX} = $options->{root};
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2018-11-20 23:13:10 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 21:07:02 +00:00
|
|
|
# some versions of coreutils use the renameat2 system call in mv.
|
2022-09-05 03:50:50 +00:00
|
|
|
# This breaks certain versions of fakechroot. Here we do
|
2020-04-09 21:07:02 +00:00
|
|
|
# a sanity check and warn the user in case things might break.
|
2022-09-05 03:50:50 +00:00
|
|
|
if ($options->{mode} eq 'fakechroot'
|
|
|
|
and -e "$options->{root}/bin/mv") {
|
2020-04-09 21:07:02 +00:00
|
|
|
mkdir "$options->{root}/000-move-me"
|
|
|
|
or error "cannot create directory: $!";
|
|
|
|
my $ret = system @chrootcmd, '/bin/mv', '/000-move-me',
|
|
|
|
'/001-delete-me';
|
|
|
|
if ($ret != 0) {
|
2022-09-05 03:50:50 +00:00
|
|
|
info "the /bin/mv binary inside the chroot doesn't"
|
|
|
|
. " work under fakechroot";
|
|
|
|
info "with certain versions of coreutils and glibc,"
|
|
|
|
. " this is due to missing support for renameat2 in"
|
|
|
|
. " fakechroot";
|
|
|
|
info "see https://github.com/dex4er/fakechroot/issues/60";
|
2020-04-09 21:07:02 +00:00
|
|
|
info "expect package post installation scripts not to work";
|
|
|
|
rmdir "$options->{root}/000-move-me"
|
|
|
|
or error "cannot rmdir: $!";
|
|
|
|
} else {
|
|
|
|
rmdir "$options->{root}/001-delete-me"
|
|
|
|
or error "cannot rmdir: $!";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return \@chrootcmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub run_essential() {
|
|
|
|
my $options = shift;
|
|
|
|
my $essential_pkgs = shift;
|
|
|
|
my $chrootcmd = shift;
|
2020-11-13 18:02:41 +00:00
|
|
|
my $cached_debs = shift;
|
2020-03-22 13:08:21 +00:00
|
|
|
|
2020-05-03 13:06:24 +00:00
|
|
|
if (scalar @{$essential_pkgs} == 0) {
|
|
|
|
info "no essential packages -- skipping...";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-20 23:13:10 +00:00
|
|
|
if ($options->{mode} eq 'chrootless') {
|
2020-01-10 10:44:15 +00:00
|
|
|
if ($options->{dryrun}) {
|
2020-11-27 23:45:32 +00:00
|
|
|
info "simulate installing essential packages...";
|
2020-01-10 10:44:15 +00:00
|
|
|
} else {
|
2020-11-27 23:45:32 +00:00
|
|
|
info "installing essential packages...";
|
2020-01-10 10:44:15 +00:00
|
|
|
}
|
2020-01-08 14:41:49 +00:00
|
|
|
# FIXME: the dpkg config from the host is parsed before the command
|
|
|
|
# line arguments are parsed and might break this mode
|
|
|
|
# Example: if the host has --path-exclude set, then this will also
|
2021-08-25 03:15:44 +00:00
|
|
|
# affect the chroot. See #808203
|
2020-01-08 14:41:49 +00:00
|
|
|
my @chrootless_opts = (
|
2023-03-22 08:27:11 +00:00
|
|
|
'-oDPkg::Chroot-Directory=',
|
2020-01-08 14:41:49 +00:00
|
|
|
'-oDPkg::Options::=--force-not-root',
|
|
|
|
'-oDPkg::Options::=--force-script-chrootless',
|
|
|
|
'-oDPkg::Options::=--root=' . $options->{root},
|
2020-01-10 10:44:15 +00:00
|
|
|
'-oDPkg::Options::=--log=' . "$options->{root}/var/log/dpkg.log",
|
|
|
|
$options->{dryrun} ? '-oAPT::Get::Simulate=true' : (),
|
2020-01-08 16:44:07 +00:00
|
|
|
);
|
2020-01-08 14:41:49 +00:00
|
|
|
if (defined $options->{qemu}) {
|
|
|
|
# The binfmt support on the outside is used, so qemu needs to know
|
|
|
|
# where it has to look for shared libraries
|
|
|
|
if (defined $ENV{QEMU_LD_PREFIX}
|
|
|
|
&& $ENV{QEMU_LD_PREFIX} ne "") {
|
2020-01-09 07:39:40 +00:00
|
|
|
## no critic (Variables::RequireLocalizedPunctuationVars)
|
2020-01-08 14:41:49 +00:00
|
|
|
$ENV{QEMU_LD_PREFIX} = "$ENV{QEMU_LD_PREFIX}:$options->{root}";
|
|
|
|
} else {
|
2020-01-09 07:39:40 +00:00
|
|
|
## no critic (Variables::RequireLocalizedPunctuationVars)
|
2020-01-08 14:41:49 +00:00
|
|
|
$ENV{QEMU_LD_PREFIX} = $options->{root};
|
|
|
|
}
|
|
|
|
}
|
2021-08-17 21:39:20 +00:00
|
|
|
# we don't use apt because that will not run the base-passwd preinst
|
|
|
|
# early enough
|
|
|
|
#run_apt_progress({
|
|
|
|
# ARGV => ['apt-get', '--yes', @chrootless_opts, 'install'],
|
|
|
|
# PKGS => [map { "$options->{root}/$_" } @{$essential_pkgs}],
|
|
|
|
#});
|
|
|
|
run_dpkg_progress({
|
|
|
|
ARGV => [
|
|
|
|
'dpkg',
|
|
|
|
'--force-not-root',
|
|
|
|
'--force-script-chrootless',
|
|
|
|
"--root=$options->{root}",
|
|
|
|
"--log=$options->{root}/var/log/dpkg.log",
|
|
|
|
'--install',
|
|
|
|
'--force-depends'
|
|
|
|
],
|
|
|
|
PKGS => [map { "$options->{root}/$_" } @{$essential_pkgs}] });
|
2022-09-05 03:50:50 +00:00
|
|
|
} elsif (any { $_ eq $options->{mode} } ('root', 'unshare', 'fakechroot'))
|
|
|
|
{
|
2020-04-09 21:07:02 +00:00
|
|
|
# install the extracted packages properly
|
|
|
|
# we need --force-depends because dpkg does not take Pre-Depends
|
|
|
|
# into account and thus doesn't install them in the right order
|
|
|
|
# And the --predep-package option is broken: #539133
|
2021-08-16 11:32:20 +00:00
|
|
|
#
|
|
|
|
# We could use apt from outside the chroot using DPkg::Chroot-Directory
|
|
|
|
# but then the preinst script of base-passwd will not be called early
|
|
|
|
# enough and packages will fail to install because they are missing
|
|
|
|
# /etc/passwd. Also, with plain dpkg the essential variant can finish
|
|
|
|
# within 9 seconds. If we use apt instead, it becomes 12 seconds. We
|
|
|
|
# prefer speed here.
|
2020-04-09 21:07:02 +00:00
|
|
|
if ($options->{dryrun}) {
|
2020-11-27 23:45:32 +00:00
|
|
|
info "simulate installing essential packages...";
|
2020-04-09 21:07:02 +00:00
|
|
|
} else {
|
2020-11-27 23:45:32 +00:00
|
|
|
info "installing essential packages...";
|
2022-11-10 13:53:36 +00:00
|
|
|
run_dpkg_progress({
|
|
|
|
ARGV =>
|
|
|
|
[@{$chrootcmd}, 'dpkg', '--install', '--force-depends'],
|
|
|
|
PKGS => $essential_pkgs,
|
|
|
|
});
|
2020-04-09 21:07:02 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error "unknown mode: $options->{mode}";
|
|
|
|
}
|
2020-01-08 14:41:49 +00:00
|
|
|
|
2020-11-13 18:02:41 +00:00
|
|
|
if (any { $_ eq 'essential/unlink' } @{ $options->{skip} }) {
|
|
|
|
info "skipping essential/unlink as requested";
|
|
|
|
} else {
|
|
|
|
foreach my $deb (@{$essential_pkgs}) {
|
|
|
|
# do not unlink those packages that were in /var/cache/apt/archive
|
|
|
|
# before the download phase
|
|
|
|
next
|
|
|
|
if any { "/var/cache/apt/archives/$_" eq $deb } @{$cached_debs};
|
2022-05-24 09:47:16 +00:00
|
|
|
# do not unlink those packages that were not in
|
|
|
|
# /var/cache/apt/archive (for example because they were provided by
|
|
|
|
# a file:// mirror)
|
|
|
|
next if $deb !~ /\/var\/cache\/apt\/archives\//;
|
2020-11-13 18:02:41 +00:00
|
|
|
unlink "$options->{root}/$deb"
|
|
|
|
or error "cannot unlink $deb: $!";
|
|
|
|
}
|
2020-04-09 21:07:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub run_install() {
|
2022-11-10 13:53:36 +00:00
|
|
|
my $options = shift;
|
2021-11-09 06:31:56 +00:00
|
|
|
|
2023-01-16 11:13:21 +00:00
|
|
|
my @pkgs_to_install = (@{ $options->{include} });
|
2024-06-03 05:59:51 +00:00
|
|
|
if ($options->{variant} eq 'extract') {
|
|
|
|
error "must not be called with variant extract";
|
|
|
|
}
|
|
|
|
if (none { $_ eq $options->{variant} } ('custom', 'essential')) {
|
|
|
|
push @pkgs_to_install, 'apt';
|
|
|
|
}
|
2021-11-09 06:31:56 +00:00
|
|
|
if ($options->{variant} eq 'buildd') {
|
2024-06-03 05:59:51 +00:00
|
|
|
push @pkgs_to_install, 'build-essential';
|
2021-11-09 06:31:56 +00:00
|
|
|
}
|
2022-11-14 13:34:15 +00:00
|
|
|
if (any { $_ eq $options->{variant} }
|
2023-10-23 08:38:10 +00:00
|
|
|
('required', 'important', 'standard')) {
|
2022-02-11 22:01:08 +00:00
|
|
|
# Many of the priority:required packages are also essential:yes. We
|
|
|
|
# make sure not to select those here to avoid useless "xxx is already
|
|
|
|
# the newest version" messages.
|
2021-11-09 06:31:56 +00:00
|
|
|
my $priority;
|
2023-10-23 08:38:10 +00:00
|
|
|
if (any { $_ eq $options->{variant} } ('required')) {
|
2022-02-11 22:01:08 +00:00
|
|
|
$priority = '?and(?priority(required),?not(?essential))';
|
2021-11-09 06:31:56 +00:00
|
|
|
} elsif ($options->{variant} eq 'important') {
|
2022-02-11 22:01:08 +00:00
|
|
|
$priority = '?and(?or(?priority(required),?priority(important)),'
|
|
|
|
. '?not(?essential))';
|
2021-11-09 06:31:56 +00:00
|
|
|
} elsif ($options->{variant} eq 'standard') {
|
2022-02-11 22:01:08 +00:00
|
|
|
$priority = '?and(?or(~prequired,~pimportant,~pstandard),'
|
|
|
|
. '?not(?essential))';
|
2021-11-09 06:31:56 +00:00
|
|
|
}
|
2023-01-16 11:13:21 +00:00
|
|
|
push @pkgs_to_install,
|
|
|
|
(
|
2021-11-09 06:31:56 +00:00
|
|
|
"?narrow("
|
|
|
|
. (
|
|
|
|
length($options->{suite})
|
2022-01-07 11:46:35 +00:00
|
|
|
? '?or(?archive(^'
|
|
|
|
. $options->{suite}
|
|
|
|
. '$),?codename(^'
|
|
|
|
. $options->{suite} . '$)),'
|
2021-11-09 06:31:56 +00:00
|
|
|
: ''
|
|
|
|
)
|
|
|
|
. "?architecture($options->{nativearch}),"
|
|
|
|
. "$priority)"
|
2023-01-16 11:13:21 +00:00
|
|
|
);
|
2021-11-09 06:31:56 +00:00
|
|
|
}
|
2020-04-09 21:07:02 +00:00
|
|
|
|
|
|
|
if ($options->{mode} eq 'chrootless') {
|
2021-11-09 06:31:56 +00:00
|
|
|
if (scalar @pkgs_to_install > 0) {
|
2020-04-09 21:07:02 +00:00
|
|
|
my @chrootless_opts = (
|
2023-03-22 08:27:11 +00:00
|
|
|
'-oDPkg::Chroot-Directory=',
|
2020-04-09 21:07:02 +00:00
|
|
|
'-oDPkg::Options::=--force-not-root',
|
|
|
|
'-oDPkg::Options::=--force-script-chrootless',
|
|
|
|
'-oDPkg::Options::=--root=' . $options->{root},
|
|
|
|
'-oDPkg::Options::=--log='
|
|
|
|
. "$options->{root}/var/log/dpkg.log",
|
|
|
|
$options->{dryrun} ? '-oAPT::Get::Simulate=true' : (),
|
|
|
|
);
|
|
|
|
run_apt_progress({
|
|
|
|
ARGV => ['apt-get', '--yes', @chrootless_opts, 'install'],
|
2021-11-09 06:31:56 +00:00
|
|
|
PKGS => [@pkgs_to_install],
|
2020-04-09 21:07:02 +00:00
|
|
|
});
|
|
|
|
}
|
2022-09-05 03:50:50 +00:00
|
|
|
} elsif (any { $_ eq $options->{mode} } ('root', 'unshare', 'fakechroot'))
|
|
|
|
{
|
2020-04-09 21:07:02 +00:00
|
|
|
if ($options->{variant} ne 'custom'
|
2021-11-09 06:31:56 +00:00
|
|
|
and scalar @pkgs_to_install > 0) {
|
2021-08-16 11:32:20 +00:00
|
|
|
# Advantage of running apt on the outside instead of inside the
|
|
|
|
# chroot:
|
2020-04-09 21:07:02 +00:00
|
|
|
#
|
2021-08-16 11:32:20 +00:00
|
|
|
# - we can build chroots without apt (for example from buildinfo
|
|
|
|
# files)
|
|
|
|
#
|
|
|
|
# - we do not need to install additional packages like
|
|
|
|
# apt-transport-* or ca-certificates inside the chroot
|
|
|
|
#
|
|
|
|
# - we do not not need additional key material inside the chroot
|
|
|
|
#
|
|
|
|
# - we can make use of file:// and copy://
|
|
|
|
#
|
2022-02-11 22:01:36 +00:00
|
|
|
# - we can use EDSP solvers without installing apt-utils or other
|
|
|
|
# solvers inside the chroot
|
|
|
|
#
|
2021-08-16 11:32:20 +00:00
|
|
|
# The DPkg::Install::Recursive::force=true workaround can be
|
|
|
|
# dropped after this issue is fixed:
|
2021-09-19 17:38:47 +00:00
|
|
|
# https://salsa.debian.org/apt-team/apt/-/merge_requests/189
|
2021-08-16 11:32:20 +00:00
|
|
|
#
|
|
|
|
# We could also move the dpkg call to the outside and run dpkg with
|
|
|
|
# --root but this would only make sense in situations where there
|
|
|
|
# is no dpkg inside the chroot.
|
2020-04-09 21:07:02 +00:00
|
|
|
if (!$options->{dryrun}) {
|
2022-11-10 13:53:36 +00:00
|
|
|
info "installing remaining packages inside the chroot...";
|
|
|
|
run_apt_progress({
|
|
|
|
ARGV => [
|
|
|
|
'apt-get',
|
|
|
|
'-o',
|
|
|
|
'Dir::Bin::dpkg=env',
|
|
|
|
'-o',
|
|
|
|
'DPkg::Options::=--unset=TMPDIR',
|
|
|
|
'-o',
|
|
|
|
'DPkg::Options::=dpkg',
|
|
|
|
$options->{mode} eq 'fakechroot'
|
|
|
|
? ('-o', 'DPkg::Install::Recursive::force=true')
|
|
|
|
: (),
|
|
|
|
'--yes',
|
|
|
|
'install'
|
|
|
|
],
|
|
|
|
PKGS => [@pkgs_to_install],
|
|
|
|
});
|
2020-04-09 21:07:02 +00:00
|
|
|
} else {
|
|
|
|
info "simulate installing remaining packages inside the"
|
|
|
|
. " chroot...";
|
|
|
|
run_apt_progress({
|
|
|
|
ARGV => [
|
|
|
|
'apt-get', '--yes',
|
|
|
|
'-oAPT::Get::Simulate=true', 'install'
|
|
|
|
],
|
2021-11-09 06:31:56 +00:00
|
|
|
PKGS => [@pkgs_to_install],
|
2020-04-09 21:07:02 +00:00
|
|
|
});
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-22 15:05:56 +00:00
|
|
|
} else {
|
2020-01-08 14:41:49 +00:00
|
|
|
error "unknown mode: $options->{mode}";
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 21:07:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub run_cleanup() {
|
|
|
|
my $options = shift;
|
2019-01-08 10:28:27 +00:00
|
|
|
|
2020-04-09 22:00:36 +00:00
|
|
|
if (any { $_ eq 'cleanup/apt' } @{ $options->{skip} }) {
|
|
|
|
info "skipping cleanup/apt as requested";
|
|
|
|
} else {
|
2021-05-09 18:44:02 +00:00
|
|
|
if ( none { $_ eq 'cleanup/apt/lists' } @{ $options->{skip} }
|
|
|
|
and none { $_ eq 'cleanup/apt/cache' } @{ $options->{skip} }) {
|
|
|
|
info "cleaning package lists and apt cache...";
|
|
|
|
}
|
|
|
|
if (any { $_ eq 'cleanup/apt/lists' } @{ $options->{skip} }) {
|
|
|
|
info "skipping cleanup/apt/lists as requested";
|
|
|
|
} else {
|
|
|
|
if (any { $_ eq 'cleanup/apt/cache' } @{ $options->{skip} }) {
|
|
|
|
info "cleaning package lists...";
|
|
|
|
}
|
|
|
|
run_apt_progress({
|
|
|
|
ARGV => [
|
|
|
|
'apt-get', '--option',
|
|
|
|
'Dir::Etc::SourceList=/dev/null', '--option',
|
|
|
|
'Dir::Etc::SourceParts=/dev/null', 'update'
|
|
|
|
],
|
|
|
|
CHDIR => $options->{root},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (any { $_ eq 'cleanup/apt/cache' } @{ $options->{skip} }) {
|
|
|
|
info "skipping cleanup/apt/cache as requested";
|
|
|
|
} else {
|
|
|
|
if (any { $_ eq 'cleanup/apt/lists' } @{ $options->{skip} }) {
|
|
|
|
info "cleaning apt cache...";
|
|
|
|
}
|
|
|
|
run_apt_progress(
|
|
|
|
{ ARGV => ['apt-get', 'clean'], CHDIR => $options->{root} });
|
|
|
|
}
|
2018-09-18 09:20:24 +00:00
|
|
|
|
2020-04-09 22:00:36 +00:00
|
|
|
# apt since 1.6 creates the auxfiles directory. If apt inside the
|
|
|
|
# chroot is older than that, then it will not know how to clean it.
|
|
|
|
if (-e "$options->{root}/var/lib/apt/lists/auxfiles") {
|
2021-10-06 19:20:41 +00:00
|
|
|
0 == system(
|
|
|
|
'rm',
|
|
|
|
'--interactive=never',
|
|
|
|
'--recursive',
|
|
|
|
'--preserve-root',
|
|
|
|
'--one-file-system',
|
|
|
|
"$options->{root}/var/lib/apt/lists/auxfiles"
|
|
|
|
) or error "rm failed: $?";
|
2020-04-09 22:00:36 +00:00
|
|
|
}
|
2019-04-23 11:28:55 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 22:00:36 +00:00
|
|
|
if (any { $_ eq 'cleanup/mmdebstrap' } @{ $options->{skip} }) {
|
|
|
|
info "skipping cleanup/mmdebstrap as requested";
|
|
|
|
} else {
|
|
|
|
# clean up temporary configuration file
|
|
|
|
unlink "$options->{root}/etc/apt/apt.conf.d/00mmdebstrap"
|
2024-01-23 06:48:12 +00:00
|
|
|
or warning "failed to unlink /etc/apt/apt.conf.d/00mmdebstrap: $!";
|
2020-04-09 22:00:36 +00:00
|
|
|
|
|
|
|
if (defined $ENV{APT_CONFIG} && -e $ENV{APT_CONFIG}) {
|
|
|
|
unlink $ENV{APT_CONFIG}
|
|
|
|
or error "failed to unlink $ENV{APT_CONFIG}: $!";
|
|
|
|
}
|
2018-09-18 15:11:02 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 22:00:36 +00:00
|
|
|
if (any { $_ eq 'cleanup/reproducible' } @{ $options->{skip} }) {
|
|
|
|
info "skipping cleanup/reproducible as requested";
|
|
|
|
} else {
|
|
|
|
# clean up certain files to make output reproducible
|
|
|
|
foreach my $fname (
|
|
|
|
'/var/log/dpkg.log', '/var/log/apt/history.log',
|
|
|
|
'/var/log/apt/term.log', '/var/log/alternatives.log',
|
2022-02-11 22:01:56 +00:00
|
|
|
'/var/cache/ldconfig/aux-cache', '/var/log/apt/eipp.log.xz',
|
|
|
|
'/var/lib/dbus/machine-id'
|
2020-04-09 22:00:36 +00:00
|
|
|
) {
|
|
|
|
my $path = "$options->{root}$fname";
|
|
|
|
if (!-e $path) {
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
unlink $path or error "cannot unlink $path: $!";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (-e "$options->{root}/etc/machine-id") {
|
|
|
|
# from machine-id(5):
|
|
|
|
# For operating system images which are created once and used on
|
|
|
|
# multiple machines, for example for containers or in the cloud,
|
|
|
|
# /etc/machine-id should be an empty file in the generic file
|
|
|
|
# system image. An ID will be generated during boot and saved to
|
|
|
|
# this file if possible. Having an empty file in place is useful
|
|
|
|
# because it allows a temporary file to be bind-mounted over the
|
|
|
|
# real file, in case the image is used read-only.
|
2024-09-12 23:17:52 +00:00
|
|
|
if (any { $_ eq 'cleanup/reproducible/machine-id' }
|
|
|
|
@{ $options->{skip} }) {
|
|
|
|
info "skipping cleanup/reproducible/machine-id as requested";
|
|
|
|
} else {
|
|
|
|
unlink "$options->{root}/etc/machine-id"
|
|
|
|
or error "cannot unlink /etc/machine-id: $!";
|
|
|
|
open my $fh, '>', "$options->{root}/etc/machine-id"
|
|
|
|
or error "failed to open(): $!";
|
|
|
|
close $fh;
|
|
|
|
}
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2020-01-21 12:13:58 +00:00
|
|
|
}
|
|
|
|
|
2022-09-02 21:29:52 +00:00
|
|
|
if (any { $_ eq 'cleanup/run' } @{ $options->{skip} }) {
|
|
|
|
info "skipping cleanup/run as requested";
|
|
|
|
} else {
|
|
|
|
# remove any possible leftovers in /run
|
|
|
|
if (-d "$options->{root}/run") {
|
|
|
|
opendir(my $dh, "$options->{root}/run")
|
|
|
|
or error "Can't opendir($options->{root}/run): $!";
|
|
|
|
while (my $entry = readdir $dh) {
|
|
|
|
# skip the "." and ".." entries
|
|
|
|
next if $entry eq ".";
|
|
|
|
next if $entry eq "..";
|
2022-09-06 14:58:20 +00:00
|
|
|
# skip deleting /run/lock as /var/lock is a symlink to it
|
|
|
|
# according to Debian policy §9.1.4
|
|
|
|
next if $entry eq "lock";
|
2022-09-02 21:29:52 +00:00
|
|
|
debug "deleting files in /run: $entry";
|
|
|
|
0 == system(
|
|
|
|
'rm', '--interactive=never',
|
|
|
|
'--recursive', '--preserve-root',
|
|
|
|
'--one-file-system', "$options->{root}/run/$entry"
|
|
|
|
) or error "rm failed: $?";
|
|
|
|
}
|
|
|
|
closedir($dh);
|
|
|
|
}
|
|
|
|
}
|
2020-04-09 22:00:36 +00:00
|
|
|
if (any { $_ eq 'cleanup/tmp' } @{ $options->{skip} }) {
|
|
|
|
info "skipping cleanup/tmp as requested";
|
|
|
|
} else {
|
2022-09-02 21:29:52 +00:00
|
|
|
# remove any possible leftovers in /tmp
|
2020-04-09 22:00:36 +00:00
|
|
|
if (-d "$options->{root}/tmp") {
|
|
|
|
opendir(my $dh, "$options->{root}/tmp")
|
|
|
|
or error "Can't opendir($options->{root}/tmp): $!";
|
|
|
|
while (my $entry = readdir $dh) {
|
|
|
|
# skip the "." and ".." entries
|
|
|
|
next if $entry eq ".";
|
|
|
|
next if $entry eq "..";
|
2022-09-02 21:29:52 +00:00
|
|
|
debug "deleting files in /tmp: $entry";
|
2021-10-06 19:20:41 +00:00
|
|
|
0 == system(
|
|
|
|
'rm', '--interactive=never',
|
|
|
|
'--recursive', '--preserve-root',
|
|
|
|
'--one-file-system', "$options->{root}/tmp/$entry"
|
|
|
|
) or error "rm failed: $?";
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2020-04-09 22:00:36 +00:00
|
|
|
closedir($dh);
|
2020-01-08 14:41:49 +00:00
|
|
|
}
|
2020-01-06 11:44:44 +00:00
|
|
|
}
|
2023-09-27 11:52:20 +00:00
|
|
|
|
|
|
|
if (any { $_ eq 'cleanup/dev' } @{ $options->{skip} }) {
|
|
|
|
info "skipping cleanup/dev as requested";
|
|
|
|
} else {
|
|
|
|
|
|
|
|
# By default, tar is run with --exclude=./dev because we create the
|
|
|
|
# ./dev entries ourselves using @devfiles. But if --skip=output/dev is
|
|
|
|
# used, --exclude=./dev is not passed so that the chroot includes ./dev
|
|
|
|
# as created by base-files. But if mknod was available (for example
|
|
|
|
# when running as root) then ./dev will also include the @devfiles
|
|
|
|
# entries created by run_setup() and thus the resulting tarball will
|
|
|
|
# include things inside ./dev despite the user having supplied
|
|
|
|
# --skip=output/dev. So if --skip=output/dev was passed and if a
|
|
|
|
# tarball is to be created, we need to make sure to clean up the
|
|
|
|
# ./dev entries that were created in run_setup(). This is not done
|
|
|
|
# when creating a directory because in that case we want to do the
|
|
|
|
# same as debootstrap and create a directory including device nodes.
|
|
|
|
if ($options->{format} ne 'directory' && any { $_ eq 'output/dev' }
|
|
|
|
@{ $options->{skip} }) {
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
foreach my $file (@linuxdevfiles) {
|
|
|
|
my ($fname, $mode, $type, $linkname, $devmajor, $devminor,
|
|
|
|
undef)
|
2023-09-27 11:52:20 +00:00
|
|
|
= @{$file};
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
if (!-e "$options->{root}/$fname") {
|
2023-09-27 11:52:20 +00:00
|
|
|
next;
|
|
|
|
}
|
|
|
|
# do not remove ./dev itself
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
if ($fname eq "./dev/") {
|
2023-09-27 11:52:20 +00:00
|
|
|
next;
|
|
|
|
}
|
|
|
|
if ($type == 0) { # normal file
|
|
|
|
error "type 0 not implemented";
|
|
|
|
} elsif ($type == 1) { # hardlink
|
|
|
|
error "type 1 not implemented";
|
|
|
|
} elsif (any { $_ eq $type } (2, 3, 4))
|
|
|
|
{ # symlink, char, block
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
unlink "$options->{root}/$fname"
|
|
|
|
or error "failed to unlink $fname: $!";
|
2023-09-27 11:52:20 +00:00
|
|
|
} elsif ($type == 5) { # directory
|
support chrootless hurd-i386
$ mmdebstrap --variant=apt --include=passwd,debian-ports-archive-keyring,mmdebstrap,sysvinit-core,sysv-rc \
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless --arch=hurd-i386 --include=sysvinit-core,sysv-rc,debian-ports-archive-keyring,gnumach-image-1-486 --customize-hook="passwd --root=\"\$1\" --delete root" --variant=apt unstable /tmp/chroot.tar "deb http://ftp.ports.debian.org/debian-ports/ unstable main" "deb http://ftp.ports.debian.org/debian-ports/ unreleased main"' \
--customize-hook='copy-out /tmp/chroot.tar .' unstable /dev/null
$ /sbin/mkfs.ext2 -q -F -o hurd -I 128 -b 4096 -d chroot.tar hurd.ext2 204800
$ qemu-system-i386 -nographic -net user,hostfwd=tcp:127.0.0.1:2222-:22 \
-net nic,model=e1000 -m 1G -kernel gnumach-1.8-486-up \
-append 'root=device:hd0 console=com0' --initrd './ext2fs.static --multiboot-command-line=${kernel-command-line} --host-priv-port=${host-port} --device-master-port=${device-port} --exec-server-task=${exec-task} -T typed ${root} $(task-create) $(task-resume),./exec.static $(exec-task=task-create)' \
-drive file=hurd.ext2,format=raw
2024-08-26 23:04:54 +00:00
|
|
|
rmdir "$options->{root}/$fname"
|
|
|
|
or error "failed to unlink $fname: $!";
|
2023-09-27 11:52:20 +00:00
|
|
|
} else {
|
|
|
|
error "unsupported type: $type";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2018-09-18 09:20:24 +00:00
|
|
|
}
|
|
|
|
|
2019-12-09 09:40:51 +00:00
|
|
|
# messages from process inside unshared namespace to the outside
|
|
|
|
# openw -- open file for writing
|
|
|
|
# untar -- extract tar into directory
|
|
|
|
# write -- write data to last opened file or tar process
|
|
|
|
# close -- finish file writing or tar extraction
|
|
|
|
# adios -- last message and tear-down
|
|
|
|
# messages from process outside unshared namespace to the inside
|
|
|
|
# okthx -- success
|
|
|
|
sub checkokthx {
|
2020-01-08 16:44:07 +00:00
|
|
|
my $fh = shift;
|
|
|
|
my $ret = read($fh, my $buf, 2 + 5) // error "cannot read from socket: $!";
|
2019-12-09 09:40:51 +00:00
|
|
|
if ($ret == 0) { error "received eof on socket"; }
|
|
|
|
my ($len, $msg) = unpack("nA5", $buf);
|
|
|
|
if ($msg ne "okthx") { error "expected okthx but got: $msg"; }
|
2020-01-08 16:44:07 +00:00
|
|
|
if ($len != 0) { error "expected no payload but got $len bytes"; }
|
2020-01-09 07:39:40 +00:00
|
|
|
return;
|
2019-12-09 09:40:51 +00:00
|
|
|
}
|
|
|
|
|
2020-08-15 16:29:17 +00:00
|
|
|
# resolve a path inside a chroot
|
|
|
|
sub chrooted_realpath {
|
|
|
|
my $root = shift;
|
|
|
|
my $src = shift;
|
|
|
|
my $result = $root;
|
|
|
|
my $prefix;
|
|
|
|
|
|
|
|
# relative paths are relative to the root of the chroot
|
|
|
|
# remove prefixed slashes
|
|
|
|
$src =~ s{^/+}{};
|
|
|
|
my $loop = 0;
|
|
|
|
while (length $src) {
|
|
|
|
if ($loop > 25) {
|
|
|
|
error "too many levels of symbolic links";
|
|
|
|
}
|
|
|
|
# Get the first directory component.
|
|
|
|
($prefix, $src) = split m{/+}, $src, 2;
|
|
|
|
# Resolve the first directory component.
|
|
|
|
if ($prefix eq ".") {
|
|
|
|
# Ignore, stay at the same directory.
|
|
|
|
} elsif ($prefix eq "..") {
|
|
|
|
# Go up one directory.
|
|
|
|
$result =~ s{(.*)/[^/]*}{$1};
|
|
|
|
# but not further than the root
|
|
|
|
if ($result !~ m/^\Q$root\E/) {
|
|
|
|
$result = $root;
|
|
|
|
}
|
|
|
|
} elsif (-l "$result/$prefix") {
|
|
|
|
my $dst = readlink "$result/$prefix";
|
|
|
|
if ($dst =~ s{^/+}{}) {
|
|
|
|
# Absolute pathname, reset result back to $root.
|
|
|
|
$result = $root;
|
|
|
|
}
|
|
|
|
$src = length $src ? "$dst/$src" : $dst;
|
|
|
|
$loop++;
|
|
|
|
} else {
|
|
|
|
# Otherwise append the prefix.
|
|
|
|
$result = "$result/$prefix";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2022-11-14 08:59:59 +00:00
|
|
|
sub pivot_root {
|
|
|
|
my $root = shift;
|
|
|
|
my $target = "/mnt";
|
|
|
|
my $put_old = "tmp";
|
|
|
|
0 == syscall &SYS_mount, $root, $target, 0, $MS_REC | $MS_BIND, 0
|
|
|
|
or error "mount failed: $!";
|
|
|
|
chdir "/mnt" or error "failed chdir() to /mnt: $!";
|
|
|
|
0 == syscall &SYS_pivot_root, my $new_root = ".", $put_old
|
|
|
|
or error "pivot_root failed: $!";
|
|
|
|
chroot "." or error "failed to chroot() to .: $!";
|
|
|
|
0 == syscall &SYS_umount2, $put_old, $MNT_DETACH
|
|
|
|
or error "umount2 failed: $!";
|
|
|
|
0 == syscall &SYS_umount2, my $sys = "sys", $MNT_DETACH
|
|
|
|
or error "umount2 failed: $!";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-16 11:02:11 +00:00
|
|
|
sub hookhelper {
|
2023-10-23 08:41:46 +00:00
|
|
|
my ($root, $mode, $hook, $skipopt, $verbosity, $command, @args) = @_;
|
2022-11-08 12:02:47 +00:00
|
|
|
$verbosity_level = $verbosity;
|
2023-10-23 08:41:46 +00:00
|
|
|
my @skipopts = ();
|
|
|
|
if (length $skipopt) {
|
|
|
|
for my $skip (split /[,\s]+/, $skipopt) {
|
|
|
|
# strip leading and trailing whitespace
|
|
|
|
$skip =~ s/^\s+|\s+$//g;
|
|
|
|
# skip if the remainder is an empty string
|
|
|
|
if ($skip eq '') {
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
push @skipopts, $skip;
|
|
|
|
}
|
|
|
|
}
|
2020-01-16 11:02:11 +00:00
|
|
|
# we put everything in an eval block because that way we can easily handle
|
|
|
|
# errors without goto labels or much code duplication: the error handler
|
|
|
|
# has to send an "error" message to the other side
|
|
|
|
eval {
|
2020-01-08 14:41:49 +00:00
|
|
|
|
|
|
|
my @cmdprefix = ();
|
2020-01-21 12:24:49 +00:00
|
|
|
my @tarcmd = (
|
|
|
|
'tar', '--numeric-owner', '--xattrs', '--format=pax',
|
|
|
|
'--pax-option=exthdr.name=%d/PaxHeaders/%f,'
|
|
|
|
. 'delete=atime,delete=ctime'
|
|
|
|
);
|
2020-01-08 14:41:49 +00:00
|
|
|
if ($hook eq 'setup') {
|
2020-03-22 13:08:21 +00:00
|
|
|
} elsif (any { $_ eq $hook } ('extract', 'essential', 'customize')) {
|
2020-01-08 14:41:49 +00:00
|
|
|
if ($mode eq 'fakechroot') {
|
|
|
|
# Fakechroot requires tar to run inside the chroot or
|
|
|
|
# otherwise absolute symlinks will include the path to the
|
|
|
|
# root directory
|
2022-05-24 18:36:01 +00:00
|
|
|
push @cmdprefix, 'chroot', $root;
|
2020-01-08 14:41:49 +00:00
|
|
|
} elsif (any { $_ eq $mode } ('root', 'chrootless', 'unshare')) {
|
2020-08-15 16:29:17 +00:00
|
|
|