| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Sys::Export::Linux; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# ABSTRACT: Export subsets of a Linux system |
|
4
|
|
|
|
|
|
|
our $VERSION = '0.005'; # VERSION |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
2
|
|
|
2
|
|
423179
|
use v5.26; |
|
|
2
|
|
|
|
|
8
|
|
|
8
|
2
|
|
|
2
|
|
9
|
use warnings; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
106
|
|
|
9
|
2
|
|
|
2
|
|
8
|
use experimental qw( signatures ); |
|
|
2
|
|
|
|
|
2
|
|
|
|
2
|
|
|
|
|
10
|
|
|
10
|
2
|
|
|
2
|
|
192
|
use parent 'Sys::Export::Unix'; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
12
|
|
|
11
|
2
|
|
|
2
|
|
100
|
use Cwd 'abs_path'; |
|
|
2
|
|
|
|
|
2
|
|
|
|
2
|
|
|
|
|
77
|
|
|
12
|
2
|
|
|
2
|
|
6
|
use Carp; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
2644
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub _build__trace_deps { |
|
15
|
1
|
|
|
1
|
|
2
|
my $self= shift; |
|
16
|
1
|
50
|
|
|
|
4
|
if ($self->_can_run_in_src) { |
|
17
|
|
|
|
|
|
|
# Are we going to attempt chrooting? |
|
18
|
1
|
50
|
|
|
|
3
|
if ($self->src_abs ne '/') { |
|
19
|
0
|
|
0
|
|
|
0
|
$self->{cmd_path_chroot} //= do { |
|
20
|
0
|
|
|
|
|
0
|
chomp(my $chroot= `which chroot`); |
|
21
|
0
|
0
|
|
|
|
0
|
-x $chroot or croak "chroot command not available or not executable"; |
|
22
|
0
|
0
|
|
|
|
0
|
$self->{_log_trace}->("chroot binary at $chroot") if $self->{_log_trace}; |
|
23
|
0
|
|
|
|
|
0
|
$chroot; |
|
24
|
|
|
|
|
|
|
}; |
|
25
|
|
|
|
|
|
|
} |
|
26
|
1
|
|
33
|
|
|
16
|
$self->{cmd_path_strace} //= do { |
|
27
|
1
|
|
|
|
|
5653
|
chomp(my $strace= `which strace`); |
|
28
|
1
|
50
|
|
|
|
496
|
-x $strace or croak "strace command not available or not executable"; |
|
29
|
0
|
0
|
|
|
|
0
|
$self->{_log_trace}->("strace binary at $strace") if $self->{_log_trace}; |
|
30
|
0
|
|
|
|
|
0
|
$strace; |
|
31
|
|
|
|
|
|
|
}; |
|
32
|
0
|
|
|
|
|
0
|
return $self->can('_trace_deps_linux_strace'); |
|
33
|
|
|
|
|
|
|
} |
|
34
|
0
|
|
|
|
|
0
|
$self->next::method(@_); |
|
35
|
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
|
|
37
|
0
|
|
|
0
|
|
0
|
sub _trace_deps_linux_strace($self, @argv) { |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
38
|
|
|
|
|
|
|
# Are we going to attempt chrooting? |
|
39
|
0
|
0
|
|
|
|
0
|
unshift @argv, $self->{cmd_path_chroot}, $self->src_abs |
|
40
|
|
|
|
|
|
|
unless $self->src_abs eq '/'; |
|
41
|
|
|
|
|
|
|
# Tell strace to write to a pipe, while redirecting command output to /dev/null |
|
42
|
0
|
0
|
|
|
|
0
|
open my $devnull, '+<', '/dev/null' or croak "open(/dev/null): $!"; |
|
43
|
0
|
|
0
|
|
|
0
|
pipe(my $r, my $w) // croak "pipe: $!"; |
|
44
|
0
|
|
0
|
|
|
0
|
pipe(my $err_r, my $err_w) // croak "pipe: $!"; |
|
45
|
0
|
|
0
|
|
|
0
|
my $pid= fork // croak "fork: $!"; |
|
46
|
0
|
0
|
|
|
|
0
|
if (!$pid) { |
|
47
|
0
|
|
|
|
|
0
|
close $r; |
|
48
|
0
|
|
|
|
|
0
|
close $err_r; |
|
49
|
0
|
|
|
|
|
0
|
eval { |
|
50
|
0
|
0
|
|
|
|
0
|
chdir $self->src_abs or die "chdir: $!"; |
|
51
|
0
|
0
|
|
|
|
0
|
POSIX::dup2(fileno $devnull, 0) or die "dup2(->0): $!"; |
|
52
|
0
|
0
|
|
|
|
0
|
POSIX::dup2(fileno $devnull, 1) or die "dup2(->1): $!"; |
|
53
|
0
|
0
|
|
|
|
0
|
POSIX::dup2(fileno $devnull, 2) or die "dup2(->2): $!"; |
|
54
|
0
|
0
|
|
|
|
0
|
POSIX::dup2(fileno $w, 3) or die "dup2(->3): $!"; |
|
55
|
0
|
|
|
|
|
0
|
$^F= 3; |
|
56
|
0
|
|
|
|
|
0
|
unshift @argv, $self->{cmd_path_strace}, -o => "/proc/self/fd/3", -e => 'trace=open,openat'; |
|
57
|
0
|
0
|
|
|
|
0
|
exec @argv |
|
58
|
|
|
|
|
|
|
or die "exec(@argv): $!"; |
|
59
|
|
|
|
|
|
|
}; |
|
60
|
0
|
|
|
|
|
0
|
$err_w->print($@); |
|
61
|
0
|
|
|
|
|
0
|
$err_w->close; |
|
62
|
0
|
|
|
|
|
0
|
POSIX::_exit(2); # forcibly exit rather than bubble up the stack |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
else { |
|
65
|
0
|
|
|
|
|
0
|
close $w; |
|
66
|
0
|
|
|
|
|
0
|
close $err_w; |
|
67
|
0
|
|
|
|
|
0
|
my %deps; |
|
68
|
0
|
|
|
|
|
0
|
my $err= do { local $/; <$err_r> }; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
69
|
0
|
0
|
|
|
|
0
|
if (length $err) { |
|
70
|
0
|
|
|
|
|
0
|
waitpid($pid, 0); |
|
71
|
0
|
|
|
|
|
0
|
die $err; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
0
|
0
|
|
|
|
0
|
$self->{_log_trace}->("Reading strace output") if $self->{_log_trace}; |
|
74
|
0
|
|
|
|
|
0
|
while (<$r>) { |
|
75
|
0
|
0
|
|
|
|
0
|
$self->{_log_trace}->($_) if $self->{_log_trace}; |
|
76
|
0
|
0
|
|
|
|
0
|
$deps{$1}= 1 if /^open(?:at)?\(.*?"(.*?)",.*?= [0-9]/; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
0
|
0
|
|
|
|
0
|
$self->{_log_trace}->("Done reading strace") if $self->{_log_trace}; |
|
79
|
0
|
|
|
|
|
0
|
waitpid($pid,0); |
|
80
|
0
|
|
|
|
|
0
|
my $wstat= $?; |
|
81
|
0
|
0
|
|
|
|
0
|
$self->{_log_trace}->("Command exited with $wstat") if $self->{_log_trace}; |
|
82
|
0
|
0
|
|
|
|
0
|
croak "straced command failed: wstat = $wstat" |
|
83
|
|
|
|
|
|
|
if $wstat; |
|
84
|
0
|
|
|
|
|
0
|
return \%deps; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
|
89
|
1
|
|
|
1
|
1
|
7
|
sub add_passwd($self, %options) { |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
1
|
|
|
90
|
|
|
|
|
|
|
# If the dst_userdb hasn't been created, create it by filtering the src_userdb by which |
|
91
|
|
|
|
|
|
|
# group and user ids have been seen during the export. |
|
92
|
|
|
|
|
|
|
my $db= $self->dst_userdb // Sys::Export::Unix::UserDB->new( |
|
93
|
1
|
|
0
|
|
|
6
|
auto_import => ($self->{src_userdb} //= $self->_build_src_userdb), |
|
|
|
|
33
|
|
|
|
|
|
94
|
|
|
|
|
|
|
); |
|
95
|
1
|
|
|
|
|
4
|
$db->group($_) for keys $self->dst_gid_used->%*; |
|
96
|
1
|
|
|
|
|
5
|
$db->user($_) for keys $self->dst_uid_used->%*; |
|
97
|
1
|
|
|
|
|
4
|
$db->save(\my %contents); |
|
98
|
1
|
|
50
|
|
|
4
|
my $etc_path= $options{etc_path} // 'etc'; |
|
99
|
1
|
|
|
|
|
13
|
$self->add([ dir755 => "$etc_path", { uid => 0, gid => 0 }]); |
|
100
|
1
|
|
|
|
|
7
|
$self->add([ file644 => "$etc_path/passwd", $contents{passwd}, { uid => 0, gid => 0 }]); |
|
101
|
1
|
|
|
|
|
10
|
$self->add([ file600 => "$etc_path/shadow", $contents{shadow}, { uid => 0, gid => 0 }]); |
|
102
|
1
|
|
|
|
|
6
|
$self->add([ file644 => "$etc_path/group", $contents{group}, { uid => 0, gid => 0 }]); |
|
103
|
1
|
|
|
|
|
3
|
$self; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
|
|
107
|
0
|
|
|
0
|
1
|
|
sub add_localtime($self, $tz_name) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
108
|
0
|
0
|
0
|
|
|
|
if (exists $self->{dst_path_set}{"usr/share/zoneinfo/$tz_name"} |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
|| ($self->_dst->can('dst_abs') && -f $self->_dst->dst_abs . $tz_name) |
|
110
|
|
|
|
|
|
|
) { |
|
111
|
|
|
|
|
|
|
# zoneinfo is exported, and includes this timezone, so symlink to it |
|
112
|
0
|
|
|
|
|
|
$self->add([ sym => "etc/localtime" => "../usr/share/zoneinfo/$tz_name" ]); |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
elsif (defined (my $src_path= $self->_src_abs_path("usr/share/zoneinfo/$tz_name"))) { |
|
115
|
0
|
|
|
|
|
|
$self->add([ file644 => 'etc/localtime', { data_path => $self->src_abs . $src_path } ]); |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
elsif (defined (my $path= abs_path("/usr/share/zoneinfo/$tz_name"))) { |
|
118
|
0
|
|
|
|
|
|
$self->add([ file644 => 'etc/localtime', { data_path => $path } ]); |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
else { |
|
121
|
0
|
|
|
|
|
|
croak "Can't find 'usr/share/zoneinfo/$tz_name' in destination, source, or host filesystem"; |
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
} |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# Avoiding dependency on namespace::clean |
|
126
|
|
|
|
|
|
|
delete @{Sys::Export::Linux::}{qw( croak carp confess abs_path )}; |
|
127
|
|
|
|
|
|
|
1; |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
__END__ |