forked from josch/mmdebstrap
Rework /dev, /sys, /proc mounting
- assume all entries in @devfiles to be in /dev - allow for /dev, /sys and /proc not to exist in the target and print warning - allow for /dev entries as well as /sys and /proc not to exist on the outside - simplify umount by storing special options in @umountopts - remove superfluous checks for root and unshare mode - make sure /dev entries are less than 100 chars in size for tar
This commit is contained in:
parent
d52eaa4814
commit
5a3d1ab5c4
2 changed files with 201 additions and 102 deletions
47
coverage.sh
47
coverage.sh
|
@ -120,7 +120,7 @@ if [ ! -e shared/hooks/eatmydata/customize.sh ] || [ hooks/eatmydata/customize.s
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
starttime=
|
starttime=
|
||||||
total=191
|
total=193
|
||||||
skipped=0
|
skipped=0
|
||||||
runtests=0
|
runtests=0
|
||||||
i=1
|
i=1
|
||||||
|
@ -937,6 +937,51 @@ else
|
||||||
runtests=$((runtests+1))
|
runtests=$((runtests+1))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
print_header "mode=unshare,variant=apt: missing device nodes outside the chroot"
|
||||||
|
cat << END > shared/test.sh
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
export LC_ALL=C.UTF-8
|
||||||
|
if [ ! -e /mmdebstrap-testenv ]; then
|
||||||
|
echo "this test modifies the system and should only be run inside a container" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
rm /dev/console
|
||||||
|
adduser --gecos user --disabled-password user
|
||||||
|
sysctl -w kernel.unprivileged_userns_clone=1
|
||||||
|
runuser -u user -- $CMD --mode=unshare --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar $mirror
|
||||||
|
tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt -
|
||||||
|
rm /tmp/debian-chroot.tar
|
||||||
|
END
|
||||||
|
if [ "$HAVE_QEMU" = "yes" ]; then
|
||||||
|
./run_qemu.sh
|
||||||
|
runtests=$((runtests+1))
|
||||||
|
else
|
||||||
|
echo "HAVE_QEMU != yes -- Skipping test..." >&2
|
||||||
|
skipped=$((skipped+1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_header "mode=unshare,variant=custom: missing /dev, /sys, /proc inside the chroot"
|
||||||
|
cat << END > shared/test.sh
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
export LC_ALL=C.UTF-8
|
||||||
|
if [ ! -e /mmdebstrap-testenv ]; then
|
||||||
|
echo "this test modifies the system and should only be run inside a container" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
adduser --gecos user --disabled-password user
|
||||||
|
sysctl -w kernel.unprivileged_userns_clone=1
|
||||||
|
runuser -u user -- $CMD --mode=unshare --variant=custom --include=dpkg,dash,diffutils,coreutils,libc-bin,sed $DEFAULT_DIST /dev/null $mirror
|
||||||
|
END
|
||||||
|
if [ "$HAVE_QEMU" = "yes" ]; then
|
||||||
|
./run_qemu.sh
|
||||||
|
runtests=$((runtests+1))
|
||||||
|
else
|
||||||
|
echo "HAVE_QEMU != yes -- Skipping test..." >&2
|
||||||
|
skipped=$((skipped+1))
|
||||||
|
fi
|
||||||
|
|
||||||
print_header "mode=root,variant=apt: chroot directory not accessible by _apt user"
|
print_header "mode=root,variant=apt: chroot directory not accessible by _apt user"
|
||||||
cat << END > shared/test.sh
|
cat << END > shared/test.sh
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
250
mmdebstrap
250
mmdebstrap
|
@ -61,6 +61,7 @@ our ($CLONE_NEWNS, $CLONE_NEWUTS, $CLONE_NEWIPC,
|
||||||
$CLONE_NEWUSER, $CLONE_NEWPID, $CLONE_NEWNET,
|
$CLONE_NEWUSER, $CLONE_NEWPID, $CLONE_NEWNET,
|
||||||
$_LINUX_CAPABILITY_VERSION_3, $CAP_SYS_ADMIN);
|
$_LINUX_CAPABILITY_VERSION_3, $CAP_SYS_ADMIN);
|
||||||
|
|
||||||
|
#<<<
|
||||||
# type codes:
|
# type codes:
|
||||||
# 0 -> normal file
|
# 0 -> normal file
|
||||||
# 1 -> hardlink
|
# 1 -> hardlink
|
||||||
|
@ -70,22 +71,23 @@ our ($CLONE_NEWNS, $CLONE_NEWUTS, $CLONE_NEWIPC,
|
||||||
# 5 -> directory
|
# 5 -> directory
|
||||||
my @devfiles = (
|
my @devfiles = (
|
||||||
# filename mode type link target major minor
|
# filename mode type link target major minor
|
||||||
["./dev/", oct(755), 5, '', undef, undef],
|
["", oct(755), 5, '', undef, undef],
|
||||||
["./dev/console", oct(666), 3, '', 5, 1],
|
["console", oct(666), 3, '', 5, 1],
|
||||||
["./dev/fd", oct(777), 2, '/proc/self/fd', undef, undef],
|
["fd", oct(777), 2, '/proc/self/fd', undef, undef],
|
||||||
["./dev/full", oct(666), 3, '', 1, 7],
|
["full", oct(666), 3, '', 1, 7],
|
||||||
["./dev/null", oct(666), 3, '', 1, 3],
|
["null", oct(666), 3, '', 1, 3],
|
||||||
["./dev/ptmx", oct(666), 3, '', 5, 2],
|
["ptmx", oct(666), 3, '', 5, 2],
|
||||||
["./dev/pts/", oct(755), 5, '', undef, undef],
|
["pts/", oct(755), 5, '', undef, undef],
|
||||||
["./dev/random", oct(666), 3, '', 1, 8],
|
["random", oct(666), 3, '', 1, 8],
|
||||||
["./dev/shm/", oct(755), 5, '', undef, undef],
|
["shm/", oct(755), 5, '', undef, undef],
|
||||||
["./dev/stderr", oct(777), 2, '/proc/self/fd/2', undef, undef],
|
["stderr", oct(777), 2, '/proc/self/fd/2', undef, undef],
|
||||||
["./dev/stdin", oct(777), 2, '/proc/self/fd/0', undef, undef],
|
["stdin", oct(777), 2, '/proc/self/fd/0', undef, undef],
|
||||||
["./dev/stdout", oct(777), 2, '/proc/self/fd/1', undef, undef],
|
["stdout", oct(777), 2, '/proc/self/fd/1', undef, undef],
|
||||||
["./dev/tty", oct(666), 3, '', 5, 0],
|
["tty", oct(666), 3, '', 5, 0],
|
||||||
["./dev/urandom", oct(666), 3, '', 1, 9],
|
["urandom", oct(666), 3, '', 1, 9],
|
||||||
["./dev/zero", oct(666), 3, '', 1, 5],
|
["zero", oct(666), 3, '', 1, 5],
|
||||||
);
|
);
|
||||||
|
#>>>
|
||||||
|
|
||||||
# verbosity levels:
|
# verbosity levels:
|
||||||
# 0 -> print nothing
|
# 0 -> print nothing
|
||||||
|
@ -918,84 +920,111 @@ sub run_chroot {
|
||||||
foreach my $file (@devfiles) {
|
foreach my $file (@devfiles) {
|
||||||
my ($fname, $mode, $type, $linkname, $devmajor, $devminor)
|
my ($fname, $mode, $type, $linkname, $devmajor, $devminor)
|
||||||
= @{$file};
|
= @{$file};
|
||||||
next if $fname eq './dev/';
|
next if $fname eq '';
|
||||||
if ($type == 0) { # normal file
|
if ($type == 0) { # normal file
|
||||||
error "type 0 not implemented";
|
error "type 0 not implemented";
|
||||||
} elsif ($type == 1) { # hardlink
|
} elsif ($type == 1) { # hardlink
|
||||||
error "type 1 not implemented";
|
error "type 1 not implemented";
|
||||||
} elsif ($type == 2) { # symlink
|
} elsif ($type == 2) { # symlink
|
||||||
if (!$options->{havemknod}) {
|
if (!$options->{havemknod}) {
|
||||||
if ( $options->{mode} eq 'fakechroot'
|
# If we had mknod, then the symlink was already created
|
||||||
and $linkname =~ /^\/proc/) {
|
# in the run_setup function.
|
||||||
# there is no /proc in fakechroot mode
|
if (!-d "$options->{root}/dev") {
|
||||||
|
warning(
|
||||||
|
"skipping creation of ./dev/$fname because the"
|
||||||
|
. " /dev directory is missing in the target"
|
||||||
|
);
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
any { $_ eq $options->{mode} }
|
|
||||||
('root', 'unshare')
|
|
||||||
) {
|
|
||||||
push @cleanup_tasks, sub {
|
push @cleanup_tasks, sub {
|
||||||
unlink "$options->{root}/$fname"
|
unlink "$options->{root}/dev/$fname"
|
||||||
or warn "cannot unlink $fname: $!";
|
or warn "cannot unlink ./dev/$fname: $!";
|
||||||
}
|
};
|
||||||
}
|
symlink $linkname, "$options->{root}/dev/$fname"
|
||||||
symlink $linkname, "$options->{root}/$fname"
|
or error
|
||||||
or error "cannot create symlink $fname";
|
"cannot create symlink ./dev/$fname -> $linkname";
|
||||||
}
|
}
|
||||||
} elsif ($type == 3 or $type == 4) {
|
} elsif ($type == 3 or $type == 4) {
|
||||||
# character/block special
|
# character/block special
|
||||||
if ($options->{mode} eq 'root' && !$options->{canmount}) {
|
if ($options->{mode} eq 'root' && !$options->{canmount}) {
|
||||||
warning "skipping bind-mounting $fname";
|
warning "skipping bind-mounting ./dev/$fname";
|
||||||
} elsif (!$options->{havemknod}) {
|
} elsif (!$options->{havemknod}) {
|
||||||
open my $fh, '>', "$options->{root}/$fname"
|
if (!-d "$options->{root}/dev") {
|
||||||
or error "cannot open $options->{root}/$fname: $!";
|
warning(
|
||||||
close $fh;
|
"skipping creation of ./dev/$fname because the"
|
||||||
if ($options->{mode} eq 'unshare') {
|
. " /dev directory is missing in the target"
|
||||||
push @cleanup_tasks, sub {
|
);
|
||||||
0 == system('umount', '--no-mtab',
|
next;
|
||||||
"$options->{root}/$fname")
|
|
||||||
or warn "umount $fname failed: $?";
|
|
||||||
unlink "$options->{root}/$fname"
|
|
||||||
or warn "cannot unlink $fname: $!";
|
|
||||||
};
|
|
||||||
} elsif ($options->{mode} eq 'root') {
|
|
||||||
push @cleanup_tasks, sub {
|
|
||||||
0 == system('umount',
|
|
||||||
"$options->{root}/$fname")
|
|
||||||
or warn "umount failed: $?";
|
|
||||||
unlink "$options->{root}/$fname"
|
|
||||||
or warn "cannot unlink $fname: $!";
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
error "unknown mode: $options->{mode}";
|
|
||||||
}
|
}
|
||||||
0 == system('mount', '-o', 'bind', "/$fname",
|
if (!-e "/dev/$fname") {
|
||||||
"$options->{root}/$fname")
|
warning("skipping creation of ./dev/$fname because"
|
||||||
or error "mount $fname failed: $?";
|
. " /dev/$fname does not exist"
|
||||||
|
. " on the outside");
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if (!-c "/dev/$fname") {
|
||||||
|
warning("skipping creation of ./dev/$fname because"
|
||||||
|
. " /dev/$fname on the outside is not a"
|
||||||
|
. " character special file");
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
open my $fh, '>', "$options->{root}/dev/$fname"
|
||||||
|
or error
|
||||||
|
"cannot open $options->{root}/dev/$fname: $!";
|
||||||
|
close $fh;
|
||||||
|
my @umountopts = ();
|
||||||
|
if ($options->{mode} eq 'unshare') {
|
||||||
|
push @umountopts, '--no-mtab';
|
||||||
|
}
|
||||||
|
push @cleanup_tasks, sub {
|
||||||
|
0 == system('umount', @umountopts,
|
||||||
|
"$options->{root}/dev/$fname")
|
||||||
|
or warn "umount ./dev/$fname failed: $?";
|
||||||
|
unlink "$options->{root}/dev/$fname"
|
||||||
|
or warn "cannot unlink ./dev/$fname: $!";
|
||||||
|
};
|
||||||
|
0 == system('mount', '-o', 'bind', "/dev/$fname",
|
||||||
|
"$options->{root}/dev/$fname")
|
||||||
|
or error "mount ./dev/$fname failed: $?";
|
||||||
}
|
}
|
||||||
} elsif ($type == 5
|
} elsif ($type == 5
|
||||||
&& $options->{mode} eq 'root'
|
&& $options->{mode} eq 'root'
|
||||||
&& !$options->{canmount}) {
|
&& !$options->{canmount}) {
|
||||||
warning "skipping bind-mounting $fname";
|
warning "skipping bind-mounting ./dev/$fname";
|
||||||
} elsif ($type == 5) { # directory
|
} elsif ($type == 5) { # directory
|
||||||
|
if (!-d "$options->{root}/dev") {
|
||||||
|
warning(
|
||||||
|
"skipping creation of ./dev/$fname because the"
|
||||||
|
. " /dev directory is missing in the target");
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if (!-e "/dev/$fname") {
|
||||||
|
warning("skipping creation of ./dev/$fname because"
|
||||||
|
. " /dev/$fname does not exist"
|
||||||
|
. " on the outside");
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if (!-d "/dev/$fname") {
|
||||||
|
warning("skipping creation of ./dev/$fname because"
|
||||||
|
. " /dev/$fname on the outside is not a"
|
||||||
|
. " directory");
|
||||||
|
next;
|
||||||
|
}
|
||||||
if (!$options->{havemknod}) {
|
if (!$options->{havemknod}) {
|
||||||
if (
|
# If had mknod, then the directory to bind-mount into
|
||||||
any { $_ eq $options->{mode} }
|
# was already created in the run_setup function.
|
||||||
('root', 'unshare')
|
|
||||||
) {
|
|
||||||
push @cleanup_tasks, sub {
|
push @cleanup_tasks, sub {
|
||||||
rmdir "$options->{root}/$fname"
|
rmdir "$options->{root}/dev/$fname"
|
||||||
or warn "cannot rmdir $fname: $!";
|
or warn "cannot rmdir ./dev/$fname: $!";
|
||||||
}
|
};
|
||||||
}
|
if (-e "$options->{root}/dev/$fname") {
|
||||||
if (-e "$options->{root}/$fname") {
|
if (!-d "$options->{root}/dev/$fname") {
|
||||||
if (!-d "$options->{root}/$fname") {
|
error "./dev/$fname already exists but is not"
|
||||||
error "$fname already exists but is not a"
|
. " a directory";
|
||||||
. " directory";
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
my $num_created
|
my $num_created
|
||||||
= make_path "$options->{root}/$fname",
|
= make_path "$options->{root}/dev/$fname",
|
||||||
{ error => \my $err };
|
{ error => \my $err };
|
||||||
if ($err && @$err) {
|
if ($err && @$err) {
|
||||||
error(
|
error(
|
||||||
|
@ -1007,29 +1036,25 @@ sub run_chroot {
|
||||||
} @$err
|
} @$err
|
||||||
));
|
));
|
||||||
} elsif ($num_created == 0) {
|
} elsif ($num_created == 0) {
|
||||||
error "cannot create $options->{root}/$fname";
|
error
|
||||||
|
"cannot create $options->{root}/dev/$fname";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chmod $mode, "$options->{root}/$fname"
|
chmod $mode, "$options->{root}/dev/$fname"
|
||||||
or error "cannot chmod $fname: $!";
|
or error "cannot chmod ./dev/$fname: $!";
|
||||||
}
|
}
|
||||||
|
my @umountopts = ();
|
||||||
if ($options->{mode} eq 'unshare') {
|
if ($options->{mode} eq 'unshare') {
|
||||||
push @cleanup_tasks, sub {
|
push @umountopts, '--no-mtab';
|
||||||
0 == system('umount', '--no-mtab',
|
|
||||||
"$options->{root}/$fname")
|
|
||||||
or warn "umount $fname failed: $?";
|
|
||||||
};
|
|
||||||
} elsif ($options->{mode} eq 'root') {
|
|
||||||
push @cleanup_tasks, sub {
|
|
||||||
0 == system('umount', "$options->{root}/$fname")
|
|
||||||
or warn "umount $fname failed: $?";
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
error "unknown mode: $options->{mode}";
|
|
||||||
}
|
}
|
||||||
0 == system('mount', '-o', 'bind', "/$fname",
|
push @cleanup_tasks, sub {
|
||||||
"$options->{root}/$fname")
|
0 == system('umount', @umountopts,
|
||||||
or error "mount $fname failed: $?";
|
"$options->{root}/dev/$fname")
|
||||||
|
or warn "umount ./dev/$fname failed: $?";
|
||||||
|
};
|
||||||
|
0 == system('mount', '-o', 'bind', "/dev/$fname",
|
||||||
|
"$options->{root}/dev/$fname")
|
||||||
|
or error "mount ./dev/$fname failed: $?";
|
||||||
} else {
|
} else {
|
||||||
error "unsupported type: $type";
|
error "unsupported type: $type";
|
||||||
}
|
}
|
||||||
|
@ -1049,6 +1074,9 @@ sub run_chroot {
|
||||||
# to extract those
|
# to extract those
|
||||||
if ($options->{mode} eq 'root' && !$options->{canmount}) {
|
if ($options->{mode} eq 'root' && !$options->{canmount}) {
|
||||||
warning "skipping mount sysfs";
|
warning "skipping mount sysfs";
|
||||||
|
} elsif ($options->{mode} eq 'root' && !-d "$options->{root}/sys") {
|
||||||
|
warning("skipping mounting of sysfs because the"
|
||||||
|
. " /sys directory is missing in the target");
|
||||||
} elsif ($options->{mode} eq 'root') {
|
} elsif ($options->{mode} eq 'root') {
|
||||||
push @cleanup_tasks, sub {
|
push @cleanup_tasks, sub {
|
||||||
0 == system('umount', "$options->{root}/sys")
|
0 == system('umount', "$options->{root}/sys")
|
||||||
|
@ -1059,6 +1087,15 @@ sub run_chroot {
|
||||||
'-o', 'ro,nosuid,nodev,noexec', 'sys',
|
'-o', 'ro,nosuid,nodev,noexec', 'sys',
|
||||||
"$options->{root}/sys"
|
"$options->{root}/sys"
|
||||||
) or error "mount /sys failed: $?";
|
) or error "mount /sys failed: $?";
|
||||||
|
} elsif ($options->{mode} eq 'unshare' && !-d "$options->{root}/sys") {
|
||||||
|
warning("skipping bind-mounting /sys because the"
|
||||||
|
. " /sys directory is missing in the target");
|
||||||
|
} elsif ($options->{mode} eq 'unshare' && !-e "/sys") {
|
||||||
|
warning("skipping bind-mounting /sys because"
|
||||||
|
. " /sys does not exist on the outside");
|
||||||
|
} elsif ($options->{mode} eq 'unshare' && !-d "/sys") {
|
||||||
|
warning("skipping bind-mounting /sys because"
|
||||||
|
. " /sys on the outside is not a directory");
|
||||||
} elsif ($options->{mode} eq 'unshare') {
|
} elsif ($options->{mode} eq 'unshare') {
|
||||||
# naturally we have to clean up after ourselves in sudo mode where
|
# 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
|
# we do a real mount. But we also need to unmount in unshare mode
|
||||||
|
@ -1091,6 +1128,9 @@ sub run_chroot {
|
||||||
}
|
}
|
||||||
if ($options->{mode} eq 'root' && !$options->{canmount}) {
|
if ($options->{mode} eq 'root' && !$options->{canmount}) {
|
||||||
warning "skipping mount proc";
|
warning "skipping mount proc";
|
||||||
|
} elsif ($options->{mode} eq 'root' && !-d "$options->{root}/proc") {
|
||||||
|
warning("skipping mounting of proc because the"
|
||||||
|
. " /proc directory is missing in the target");
|
||||||
} elsif ($options->{mode} eq 'root') {
|
} elsif ($options->{mode} eq 'root') {
|
||||||
push @cleanup_tasks, sub {
|
push @cleanup_tasks, sub {
|
||||||
# some maintainer scripts mount additional stuff into /proc
|
# some maintainer scripts mount additional stuff into /proc
|
||||||
|
@ -1110,6 +1150,16 @@ sub run_chroot {
|
||||||
0 == system('mount', '-t', 'proc', '-o', 'ro', 'proc',
|
0 == system('mount', '-t', 'proc', '-o', 'ro', 'proc',
|
||||||
"$options->{root}/proc")
|
"$options->{root}/proc")
|
||||||
or error "mount /proc failed: $?";
|
or error "mount /proc failed: $?";
|
||||||
|
} elsif ($options->{mode} eq 'unshare' && !-d "$options->{root}/proc")
|
||||||
|
{
|
||||||
|
warning("skipping bind-mounting /proc because the"
|
||||||
|
. " /proc directory is missing in the target");
|
||||||
|
} elsif ($options->{mode} eq 'unshare' && !-e "/proc") {
|
||||||
|
warning("skipping bind-mounting /proc because"
|
||||||
|
. " /proc does not exist on the outside");
|
||||||
|
} elsif ($options->{mode} eq 'unshare' && !-d "/proc") {
|
||||||
|
warning("skipping bind-mounting /proc because"
|
||||||
|
. " /proc on the outside is not a directory");
|
||||||
} elsif ($options->{mode} eq 'unshare') {
|
} elsif ($options->{mode} eq 'unshare') {
|
||||||
# naturally we have to clean up after ourselves in sudo mode where
|
# 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
|
# we do a real mount. But we also need to unmount in unshare mode
|
||||||
|
@ -1781,24 +1831,25 @@ sub run_setup() {
|
||||||
# there is no /proc in fakechroot mode
|
# there is no /proc in fakechroot mode
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
symlink $linkname, "$options->{root}/$fname"
|
symlink $linkname, "$options->{root}/dev/$fname"
|
||||||
or error "cannot create symlink $fname";
|
or error "cannot create symlink ./dev/$fname";
|
||||||
next; # chmod cannot work on symlinks
|
next; # chmod cannot work on symlinks
|
||||||
} elsif ($type == 3) { # character special
|
} elsif ($type == 3) { # character special
|
||||||
0 == system('mknod', "$options->{root}/$fname", 'c',
|
0 == system('mknod', "$options->{root}/dev/$fname", 'c',
|
||||||
$devmajor, $devminor)
|
$devmajor, $devminor)
|
||||||
or error "mknod failed: $?";
|
or error "mknod failed: $?";
|
||||||
} elsif ($type == 4) { # block special
|
} elsif ($type == 4) { # block special
|
||||||
0 == system('mknod', "$options->{root}/$fname", 'b',
|
0 == system('mknod', "$options->{root}/dev/$fname", 'b',
|
||||||
$devmajor, $devminor)
|
$devmajor, $devminor)
|
||||||
or error "mknod failed: $?";
|
or error "mknod failed: $?";
|
||||||
} elsif ($type == 5) { # directory
|
} elsif ($type == 5) { # directory
|
||||||
if (-e "$options->{root}/$fname") {
|
if (-e "$options->{root}/dev/$fname") {
|
||||||
if (!-d "$options->{root}/$fname") {
|
if (!-d "$options->{root}/dev/$fname") {
|
||||||
error "$fname already exists but is not a directory";
|
error
|
||||||
|
"./dev/$fname already exists but is not a directory";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
my $num_created = make_path "$options->{root}/$fname",
|
my $num_created = make_path "$options->{root}/dev/$fname",
|
||||||
{ error => \my $err };
|
{ error => \my $err };
|
||||||
if ($err && @$err) {
|
if ($err && @$err) {
|
||||||
error(
|
error(
|
||||||
|
@ -1808,14 +1859,14 @@ sub run_setup() {
|
||||||
@$err
|
@$err
|
||||||
));
|
));
|
||||||
} elsif ($num_created == 0) {
|
} elsif ($num_created == 0) {
|
||||||
error "cannot create $options->{root}/$fname";
|
error "cannot create $options->{root}/dev/$fname";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error "unsupported type: $type";
|
error "unsupported type: $type";
|
||||||
}
|
}
|
||||||
chmod $mode, "$options->{root}/$fname"
|
chmod $mode, "$options->{root}/dev/$fname"
|
||||||
or error "cannot chmod $fname: $!";
|
or error "cannot chmod ./dev/$fname: $!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5314,9 +5365,12 @@ sub main() {
|
||||||
foreach my $file (@devfiles) {
|
foreach my $file (@devfiles) {
|
||||||
my ($fname, $mode, $type, $linkname, $devmajor, $devminor)
|
my ($fname, $mode, $type, $linkname, $devmajor, $devminor)
|
||||||
= @{$file};
|
= @{$file};
|
||||||
|
if (length "./dev/$fname" > 100) {
|
||||||
|
error "tar entry cannot exceed 100 characters";
|
||||||
|
}
|
||||||
my $entry = pack(
|
my $entry = pack(
|
||||||
'a100 a8 a8 a8 a12 a12 A8 a1 a100 a8 a32 a32 a8 a8 a155 x12',
|
'a100 a8 a8 a8 a12 a12 A8 a1 a100 a8 a32 a32 a8 a8 a155 x12',
|
||||||
$fname,
|
"./dev/$fname",
|
||||||
sprintf('%07o', $mode),
|
sprintf('%07o', $mode),
|
||||||
sprintf('%07o', 0), # uid
|
sprintf('%07o', 0), # uid
|
||||||
sprintf('%07o', 0), # gid
|
sprintf('%07o', 0), # gid
|
||||||
|
|
Loading…
Reference in a new issue