line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MDK::Common::System; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
MDK::Common::System - system-related useful functions |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use MDK::Common::System qw(:all); |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 EXPORTS |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=over |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=item %compat_arch |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
architecture compatibility mapping (eg: k6 => i586, k7 => k6 ...) |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=item %printable_chars |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
7 bit ascii characters |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=item $sizeof_int |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sizeof(int) |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=item $bitof_int |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
$sizeof_int * 8 |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=item arch() |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
return the architecture (eg: i686, ppc, ia64, k7...) |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=item typeFromMagic(FILENAME, LIST) |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
find the first corresponding magic in FILENAME. eg of LIST: |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
[ 'empty', 0, "\0\0\0\0" ], |
40
|
|
|
|
|
|
|
[ 'grub', 0, "\xEBG", 0x17d, "stage1 \0" ], |
41
|
|
|
|
|
|
|
[ 'lilo', 0x2, "LILO" ], |
42
|
|
|
|
|
|
|
sub { my ($F) = @_; |
43
|
|
|
|
|
|
|
#- standard grub has no good magic (Mageia's grub is patched to have "GRUB" at offset 6) |
44
|
|
|
|
|
|
|
#- so scanning a range of possible places where grub can have its string |
45
|
|
|
|
|
|
|
my ($min, $max, $magic) = (0x176, 0x181, "GRUB \0"); |
46
|
|
|
|
|
|
|
my $tmp; |
47
|
|
|
|
|
|
|
sysseek($F, 0, 0) && sysread($F, $tmp, $max + length($magic)) or return; |
48
|
|
|
|
|
|
|
substr($tmp, 0, 2) eq "\xEBH" or return; |
49
|
|
|
|
|
|
|
index($tmp, $magic, $min) >= 0 && "grub"; |
50
|
|
|
|
|
|
|
}, |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
where each entry is [ magic_name, offset, string, offset, string, ... ]. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=item list_passwd() |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
return the list of users as given by C (see perlfunc) |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=item is_real_user() |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
checks whether or not the user is a system user or a real user |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=item is_real_group() |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
checks whether or not the group is a system group or a real group |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=item list_home() |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
return the list of home (eg: /home/foo, /home/pixel, ...) |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=item list_skels() |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
return the directories where we can find dot files: homes, /root and /etc/skel |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=item list_users() |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
return the list of unprivilegied users (uses the is_real_user function to filter |
77
|
|
|
|
|
|
|
out system users from the full list) |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=item syscall_(NAME, PARA) |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
calls the syscall NAME |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=item psizeof(STRING) |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
useful to know the length of a C format string. |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
psizeof("I I I C C S") = 4 + 4 + 4 + 1 + 1 + 2 = 16 |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=item availableMemory() |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
size of swap + memory |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=item availableRamMB() |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
size of RAM as reported by the BIOS (it is a round number that can be |
96
|
|
|
|
|
|
|
displayed or given as "mem=128M" to the kernel) |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=item gettimeofday() |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
returns the epoch in microseconds |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=item unix2dos(STRING) |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
takes care of CR/LF translation |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=item whereis_binary(STRING) |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
return the first absolute file in $PATH (similar to which(1) and whereis(1)) |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=item getVarsFromSh(FILENAME) |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
returns a hash associating shell variables to their value. useful for config |
113
|
|
|
|
|
|
|
files such as /etc/sysconfig files |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=item setVarsInSh(FILENAME, HASH REF) |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
write file in shell format association a shell variable + value for each |
118
|
|
|
|
|
|
|
key/value |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=item setVarsInSh(FILENAME, HASH REF, LIST) |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
restrict the fields that will be printed to LIST |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=item setVarsInShMode(FILENAME, INT, HASH REF, LIST) |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
like setVarsInSh with INT being the chmod value for the config file |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=item addVarsInSh(FILENAME, HASH REF) |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
like setVarsInSh but keeping the entries in the file |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=item addVarsInSh(FILENAME, HASH REF, LIST) |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
like setVarsInSh but keeping the entries in the file |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=item addVarsInShMode(FILENAME, INT, HASH REF, LIST) |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
like addVarsInShMode but keeping the entries in the file |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=item setExportedVarsInCsh(FILENAME, HASH REF, LIST) |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
same as C for csh format |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=item template2file(FILENAME_IN, FILENAME_OUT, HASH) |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
read in a template file, replace keys @@@key@@@ with value, save it in out |
147
|
|
|
|
|
|
|
file |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=item template2userfile(PREFIX, FILENAME_IN, FILENAME_OUT, BOOL, HASH) |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
read in a template file, replace keys @@@key@@@ with value, save it in every homes. |
152
|
|
|
|
|
|
|
If BOOL is true, overwrite existing files. FILENAME_OUT must be a relative filename |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=item read_gnomekderc(FILENAME, STRING) |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
reads GNOME-like and KDE-like config files (aka windows-like). |
157
|
|
|
|
|
|
|
You must give a category. eg: |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
read_gnomekderc("/etc/skels/.kderc", 'KDE') |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=item update_gnomekderc(FILENAME, STRING, HASH) |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
modifies GNOME-like and KDE-like config files (aka windows-like). |
164
|
|
|
|
|
|
|
If the category doesn't exist, it creates it. eg: |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
update_gnomekderc("/etc/skels/.kderc", 'KDE', |
167
|
|
|
|
|
|
|
kfmIconStyle => "Large") |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=item fuzzy_pidofs(REGEXP) |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
return the list of process ids matching the regexp |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=back |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head1 OTHER |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=over |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=item better_arch(ARCH1, ARCH2) |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
is ARCH1 compatible with ARCH2? |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
better_arch('i386', 'ia64') and better_arch('ia64', 'i386') are false |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
better_arch('k7', 'k6') is true and better_arch('k6', 'k7') is false |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=item compat_arch(STRING) |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
test the architecture compatibility. eg: |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
compat_arch('i386') is false on a ia64 |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
compat_arch('k6') is true on a k6 and k7 but false on a i386 and i686 |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=back |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=head1 SEE ALSO |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
L |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=cut |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
|
204
|
1
|
|
|
1
|
|
10
|
use MDK::Common::Math; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
59
|
|
205
|
1
|
|
|
1
|
|
9
|
use MDK::Common::File; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
48
|
|
206
|
1
|
|
|
1
|
|
9
|
use MDK::Common::DataStructure; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
50
|
|
207
|
|
|
|
|
|
|
|
208
|
1
|
|
|
1
|
|
9
|
use Exporter; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
4820
|
|
209
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
210
|
|
|
|
|
|
|
our @EXPORT_OK = qw(%compat_arch $printable_chars $sizeof_int $bitof_int arch distrib typeFromMagic list_passwd is_real_user is_real_group list_home list_skels list_users syscall_ psizeof availableMemory availableRamMB gettimeofday unix2dos whereis_binary getVarsFromSh setVarsInSh setVarsInShMode addVarsInSh addVarsInShMode setExportedVarsInSh setExportedVarsInCsh template2file template2userfile read_gnomekderc update_gnomekderc fuzzy_pidofs); #); |
211
|
|
|
|
|
|
|
our %EXPORT_TAGS = (all => [ @EXPORT_OK ]); |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
our %compat_arch = ( #- compatibilty arch mapping. |
215
|
|
|
|
|
|
|
'noarch' => undef, |
216
|
|
|
|
|
|
|
'ia32' => 'noarch', |
217
|
|
|
|
|
|
|
'i386' => 'ia32', |
218
|
|
|
|
|
|
|
'i486' => 'i386', |
219
|
|
|
|
|
|
|
'i586' => 'i486', |
220
|
|
|
|
|
|
|
'i686' => 'i586', |
221
|
|
|
|
|
|
|
'i786' => 'i686', |
222
|
|
|
|
|
|
|
'k6' => 'i586', |
223
|
|
|
|
|
|
|
'k7' => 'k6', |
224
|
|
|
|
|
|
|
'k8' => 'k7', |
225
|
|
|
|
|
|
|
'x86_64' => 'i686', |
226
|
|
|
|
|
|
|
'amd64' => 'x86_64', |
227
|
|
|
|
|
|
|
'ia64' => 'noarch', |
228
|
|
|
|
|
|
|
'ppc' => 'noarch', |
229
|
|
|
|
|
|
|
'alpha' => 'noarch', |
230
|
|
|
|
|
|
|
'sparc' => 'noarch', |
231
|
|
|
|
|
|
|
'sparc32' => 'sparc', |
232
|
|
|
|
|
|
|
'sparc64' => 'sparc32', |
233
|
|
|
|
|
|
|
'ia64' => 'noarch', |
234
|
|
|
|
|
|
|
); |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
our $printable_chars = "\x20-\x7E"; |
237
|
|
|
|
|
|
|
our $sizeof_int = psizeof("i"); |
238
|
|
|
|
|
|
|
our $bitof_int = $sizeof_int * 8; |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
sub arch() { |
242
|
0
|
|
|
0
|
1
|
0
|
my $SYS_NMLN = 65; |
243
|
0
|
|
|
|
|
0
|
my $format = "Z$SYS_NMLN" x 6; |
244
|
0
|
|
|
|
|
0
|
my $t = pack $format; |
245
|
0
|
|
|
|
|
0
|
syscall_('uname', $t); |
246
|
0
|
|
|
|
|
0
|
(unpack($format, $t))[4]; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
sub better_arch { |
249
|
0
|
|
|
0
|
1
|
0
|
my ($new, $old) = @_; |
250
|
0
|
|
0
|
|
|
0
|
while ($new && $new ne $old) { $new = $compat_arch{$new} } |
|
0
|
|
|
|
|
0
|
|
251
|
0
|
|
|
|
|
0
|
$new; |
252
|
|
|
|
|
|
|
} |
253
|
0
|
|
|
0
|
1
|
0
|
sub compat_arch { better_arch(arch(), $_[0]) } |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub distrib() { |
256
|
0
|
|
|
0
|
0
|
0
|
my $release = MDK::Common::File::cat_('/etc/release'); |
257
|
0
|
|
|
|
|
0
|
my ($real_system, $real_product) = $release =~ /(.*) release ([\d.]+)/; |
258
|
0
|
|
|
|
|
0
|
my $oem_config = '/etc/sysconfig/oem'; |
259
|
0
|
|
0
|
|
|
0
|
my %oem = -f $oem_config && getVarsFromSh($oem_config); |
260
|
|
|
|
|
|
|
#- (blino) FIXME: merge with release functions from /usr/lib/libDrakX/common.pm (including product.id parsing) |
261
|
0
|
|
|
|
|
0
|
my ($default_company) = split(' ', $real_system); |
262
|
0
|
|
0
|
|
|
0
|
my $company = $oem{COMPANY} || $default_company || 'Unknown vendor'; |
263
|
0
|
|
0
|
|
|
0
|
my $system = $oem{SYSTEM} || $real_system; |
264
|
0
|
|
0
|
|
|
0
|
my $product = $oem{PRODUCT} || $real_product; |
265
|
0
|
|
|
|
|
0
|
(company => $company, system => $system, product => $product, real_system => $real_system, real_product => $real_product); |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
sub typeFromMagic { |
269
|
0
|
|
|
0
|
1
|
0
|
my $f = shift; |
270
|
0
|
0
|
|
|
|
0
|
sysopen(my $F, $f, 0) or return; |
271
|
|
|
|
|
|
|
|
272
|
0
|
|
|
|
|
0
|
my $tmp; |
273
|
0
|
|
|
|
|
0
|
M: foreach (@_) { |
274
|
0
|
0
|
|
|
|
0
|
if (ref($_) eq 'CODE') { |
275
|
0
|
0
|
|
|
|
0
|
my $name = $_->($F) or next M; |
276
|
0
|
|
|
|
|
0
|
return $name; |
277
|
|
|
|
|
|
|
} else { |
278
|
0
|
|
|
|
|
0
|
my ($name, @l) = @$_; |
279
|
0
|
|
|
|
|
0
|
while (@l) { |
280
|
0
|
|
|
|
|
0
|
my ($offset, $signature) = splice(@l, 0, 2); |
281
|
0
|
0
|
|
|
|
0
|
sysseek($F, $offset, 0) or next M; |
282
|
0
|
|
|
|
|
0
|
sysread($F, $tmp, length $signature); |
283
|
0
|
0
|
|
|
|
0
|
$tmp eq $signature or next M; |
284
|
|
|
|
|
|
|
} |
285
|
0
|
|
|
|
|
0
|
return $name; |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
} |
288
|
0
|
|
|
|
|
0
|
undef; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
sub list_passwd() { |
293
|
0
|
|
|
0
|
1
|
0
|
my (@l, @e); |
294
|
0
|
|
|
|
|
0
|
setpwent(); |
295
|
0
|
|
|
|
|
0
|
while (@e = getpwent()) { push @l, [ @e ] } |
|
0
|
|
|
|
|
0
|
|
296
|
0
|
|
|
|
|
0
|
endpwent(); |
297
|
0
|
|
|
|
|
0
|
@l; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
sub is_real_user { |
300
|
0
|
|
|
0
|
1
|
0
|
my ($username) = @_; |
301
|
|
|
|
|
|
|
|
302
|
0
|
0
|
|
|
|
0
|
return 0 if $username eq "nobody"; |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
# We consider real users to be those users who: |
305
|
|
|
|
|
|
|
# Have a UID >= 1000 |
306
|
|
|
|
|
|
|
# or |
307
|
|
|
|
|
|
|
# Have a UID >= 500 |
308
|
|
|
|
|
|
|
# and have a homedir that is not / or does not start with /var or /run |
309
|
|
|
|
|
|
|
# and have a shell that does not end in "nologin" or "false" |
310
|
|
|
|
|
|
|
|
311
|
0
|
|
|
|
|
0
|
my (undef, undef, $uid, undef, undef, undef, undef, $homedir, $shell) = getpwnam($username); |
312
|
0
|
0
|
0
|
|
|
0
|
($uid >= 1000 || ($uid >= 500 && $homedir !~ m!^/($|var/|run/)! && $shell !~ /(nologin|false)$/)); |
|
|
|
0
|
|
|
|
|
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
sub is_real_group { |
315
|
0
|
|
|
0
|
1
|
0
|
my ($groupname) = @_; |
316
|
|
|
|
|
|
|
|
317
|
0
|
0
|
|
|
|
0
|
return 0 if $groupname eq "nogroup"; |
318
|
|
|
|
|
|
|
|
319
|
0
|
|
|
|
|
0
|
my (undef, undef, $gid, $members) = getgrnam($groupname); |
320
|
0
|
0
|
|
|
|
0
|
return 0 if $gid < 500; |
321
|
0
|
0
|
|
|
|
0
|
return 1 if $gid >= 1000; |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# We are in the range 500-1000, so we need some heuristic. |
324
|
|
|
|
|
|
|
# We consider ourselves a "real" group if this is the primary group of a user |
325
|
|
|
|
|
|
|
# with the same name, or we have any member users who are "real" |
326
|
|
|
|
|
|
|
|
327
|
0
|
|
|
|
|
0
|
my (undef, undef, undef, $ugid) = getpwnam($groupname); |
328
|
0
|
0
|
0
|
|
|
0
|
return 1 if $ugid == $gid && is_real_user($groupname); |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# OK we're not a primary group, but perhaps we have some real members? |
331
|
0
|
|
|
|
|
0
|
foreach (split(' ', $members)) { |
332
|
0
|
0
|
|
|
|
0
|
return 1 if is_real_user($_); |
333
|
|
|
|
|
|
|
} |
334
|
0
|
|
|
|
|
0
|
return 0; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
sub list_home() { |
337
|
0
|
|
|
0
|
1
|
0
|
MDK::Common::DataStructure::uniq(map { $_->[7] } grep { is_real_user($_->[0]) } list_passwd()); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
sub list_skels { |
340
|
0
|
|
|
0
|
1
|
0
|
my ($prefix, $suffix) = @_; |
341
|
0
|
0
|
|
|
|
0
|
grep { -d $_ && -w $_ } map { "$prefix$_/$suffix" } '/etc/skel', '/root', list_home(); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub list_users() { |
345
|
0
|
0
|
|
0
|
1
|
0
|
MDK::Common::DataStructure::uniq(map { is_real_user($_->[0]) ? $_->[0] : () } list_passwd()); |
|
0
|
|
|
|
|
0
|
|
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
sub syscall_ { |
351
|
0
|
|
|
0
|
1
|
0
|
my $f = shift; |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
#- load syscall.ph in package "main". If every use of syscall.ph do the same, all will be nice |
354
|
|
|
|
|
|
|
package main; |
355
|
0
|
|
|
|
|
0
|
require 'syscall.ph'; |
356
|
|
|
|
|
|
|
|
357
|
0
|
|
|
|
|
0
|
syscall(&{"main::SYS_$f"}, @_) == 0; |
|
0
|
|
|
|
|
0
|
|
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
#- return the size of the partition and its free space in KiB |
362
|
|
|
|
|
|
|
sub df { |
363
|
0
|
|
|
0
|
0
|
0
|
my ($mntpoint) = @_; |
364
|
0
|
|
|
|
|
0
|
require Filesys::Df; |
365
|
0
|
|
|
|
|
0
|
my $df = Filesys::Df::df($mntpoint, 1024); # ask 1kb values |
366
|
0
|
|
|
|
|
0
|
@$df{qw(blocks bfree)}; |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
0
|
|
|
0
|
0
|
0
|
sub sync() { syscall_('sync') } |
370
|
1
|
|
|
1
|
1
|
8
|
sub psizeof { length pack $_[0] } |
371
|
0
|
|
|
0
|
1
|
|
sub availableMemory() { MDK::Common::Math::sum(map { /(\d+)/ } grep { /^(MemTotal|SwapTotal):/ } MDK::Common::File::cat_("/proc/meminfo")) } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
372
|
0
|
|
|
0
|
1
|
|
sub availableRamMB() { 4 * MDK::Common::Math::round((-s '/proc/kcore') / 1024 / 1024 / 4) } |
373
|
0
|
0
|
|
0
|
1
|
|
sub gettimeofday() { my $t = pack "LL"; syscall_('gettimeofday', $t, 0) or die "gettimeofday failed: $!\n"; unpack("LL", $t) } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
374
|
0
|
|
|
0
|
1
|
|
sub unix2dos { local $_ = $_[0]; s/\015$//mg; s/$/\015/mg; $_ } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub expandLinkInChroot { |
377
|
0
|
|
|
0
|
0
|
|
my ($file, $prefix) = @_; |
378
|
0
|
|
|
|
|
|
my $l = readlink "$prefix$file"; |
379
|
0
|
0
|
|
|
|
|
return unless $l; |
380
|
0
|
0
|
|
|
|
|
return $l if $l =~ m!^/!; |
381
|
0
|
|
|
|
|
|
my $path = $file; |
382
|
0
|
|
|
|
|
|
$path =~ s!/[^/]*$!!; |
383
|
0
|
|
|
|
|
|
$path .= "/$l"; |
384
|
0
|
|
|
|
|
|
return $path; |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
sub whereis_binary { |
388
|
0
|
|
|
0
|
1
|
|
my ($prog, $o_prefix) = @_; |
389
|
0
|
0
|
|
|
|
|
if ($prog =~ m!/!) { |
390
|
0
|
|
|
|
|
|
require MDK::Common::Various; |
391
|
0
|
|
|
|
|
|
warn qq(don't call whereis_binary with a name containing a "/" (the culprit is: $prog)\n) . MDK::Common::Various::backtrace(); |
392
|
0
|
|
|
|
|
|
return; |
393
|
|
|
|
|
|
|
} |
394
|
0
|
|
|
|
|
|
foreach (split(':', $ENV{PATH})) { |
395
|
0
|
|
|
|
|
|
my $f = "$_/$prog"; |
396
|
0
|
|
|
|
|
|
my $links = 0; |
397
|
0
|
|
|
|
|
|
my $l = $f; |
398
|
0
|
|
|
|
|
|
while (-l "$o_prefix$l") { |
399
|
0
|
|
|
|
|
|
$l = expandLinkInChroot($l, $o_prefix); |
400
|
0
|
0
|
|
|
|
|
if ($links++ > 16) { |
401
|
0
|
|
|
|
|
|
warn qq(symlink recursion too deep in whereis_binary\n); |
402
|
0
|
|
|
|
|
|
return; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
} |
405
|
0
|
0
|
|
|
|
|
-x "$o_prefix$l" and return $f; |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub getVarsFromSh { |
410
|
0
|
|
|
0
|
1
|
|
my %l; |
411
|
0
|
0
|
|
|
|
|
open(my $F, $_[0]) or return; |
412
|
0
|
|
|
|
|
|
local $_; |
413
|
0
|
|
|
|
|
|
while (<$F>) { |
414
|
0
|
|
|
|
|
|
s/^\s*#.*//; # remove comment-only lines |
415
|
0
|
|
|
|
|
|
s/^\s*//; # leading space |
416
|
0
|
0
|
|
|
|
|
my ($v, $val) = /^(\w+)=(.*)/ or next; |
417
|
0
|
0
|
|
|
|
|
if ($val =~ /^"(.*)"(\s+#.*)?$/) { |
|
|
0
|
|
|
|
|
|
418
|
0
|
|
|
|
|
|
$val = $1; |
419
|
|
|
|
|
|
|
} elsif ($val =~ /^'(.*)'(\s+#.*)?$/) { |
420
|
0
|
|
|
|
|
|
$val = $1; |
421
|
0
|
|
|
|
|
|
$val =~ s/(^|[^'])'\\''/$1'/g; |
422
|
|
|
|
|
|
|
} |
423
|
0
|
|
|
|
|
|
$l{$v} = $val; |
424
|
|
|
|
|
|
|
} |
425
|
0
|
|
|
|
|
|
%l; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
sub addVarsInSh { |
429
|
0
|
|
|
0
|
1
|
|
my ($file, $l, @fields) = @_; |
430
|
0
|
|
|
|
|
|
addVarsInShMode($file, 0777 ^ umask(), $l, @fields); |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
sub addVarsInShMode { |
434
|
0
|
|
|
0
|
1
|
|
my ($file, $mod, $l, @fields) = @_; |
435
|
0
|
0
|
|
|
|
|
my %l = @fields ? map { $_ => $l->{$_} } @fields : %$l; |
|
0
|
|
|
|
|
|
|
436
|
0
|
|
|
|
|
|
my %l2 = getVarsFromSh($file); |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
# below is add2hash_(\%l, \%l2); |
439
|
0
|
|
0
|
|
|
|
exists $l{$_} or $l{$_} = $l2{$_} foreach keys %l2; |
440
|
|
|
|
|
|
|
|
441
|
0
|
|
|
|
|
|
setVarsInShMode($file, $mod, \%l); |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
sub setVarsInSh { |
445
|
0
|
|
|
0
|
1
|
|
my ($file, $l, @fields) = @_; |
446
|
0
|
|
|
|
|
|
setVarsInShMode($file, 0777 ^ umask(), $l, @fields); |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
sub quoteForSh { |
450
|
0
|
|
|
0
|
0
|
|
my ($val) = @_; |
451
|
0
|
0
|
|
|
|
|
if ($val =~ /["`\$]/) { |
|
|
0
|
|
|
|
|
|
452
|
0
|
|
|
|
|
|
$val =~ s/(')/$1\\$1$1/g; |
453
|
0
|
|
|
|
|
|
$val = qq('$val'); |
454
|
|
|
|
|
|
|
} elsif ($val =~ /[\(\)'|\s\\;<>\[\]~{}*?]/) { |
455
|
0
|
|
|
|
|
|
$val = qq("$val"); |
456
|
|
|
|
|
|
|
} |
457
|
0
|
|
|
|
|
|
$val; |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
sub setVarsInShMode { |
461
|
0
|
|
|
0
|
1
|
|
my ($file, $mod, $l, @fields) = @_; |
462
|
0
|
0
|
|
|
|
|
@fields = sort keys %$l unless @fields; |
463
|
|
|
|
|
|
|
my $string = join('', |
464
|
0
|
|
|
|
|
|
map { "$_=" . quoteForSh($l->{$_}) . "\n" } grep { $l->{$_} } @fields |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
); |
466
|
0
|
0
|
|
|
|
|
if ($file =~ m!^/home/!) { |
467
|
0
|
|
|
|
|
|
MDK::Common::File::secured_output($file, $string); |
468
|
|
|
|
|
|
|
} else { |
469
|
0
|
|
|
|
|
|
MDK::Common::File::output($file, $string); |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
|
472
|
0
|
|
|
|
|
|
chmod $mod, $file; |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
sub setExportedVarsInSh { |
476
|
0
|
|
|
0
|
0
|
|
my ($file, $l, @fields) = @_; |
477
|
0
|
0
|
|
|
|
|
@fields = keys %$l unless @fields; |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
MDK::Common::File::output($file, |
480
|
0
|
0
|
|
|
|
|
(map { $l->{$_} ? "$_=" . quoteForSh($l->{$_}) . "\n" : () } @fields), |
|
0
|
0
|
|
|
|
|
|
481
|
|
|
|
|
|
|
@fields ? "export " . join(" ", @fields) . "\n" : (), |
482
|
|
|
|
|
|
|
); |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
sub setExportedVarsInCsh { |
486
|
0
|
|
|
0
|
1
|
|
my ($file, $l, @fields) = @_; |
487
|
0
|
0
|
|
|
|
|
@fields = keys %$l unless @fields; |
488
|
|
|
|
|
|
|
|
489
|
0
|
0
|
|
|
|
|
MDK::Common::File::output($file, map { $l->{$_} ? "setenv $_ " . quoteForSh($l->{$_}) . "\n" : () } @fields); |
|
0
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
} |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
sub template2file { |
493
|
0
|
|
|
0
|
1
|
|
my ($in, $out, %toreplace) = @_; |
494
|
0
|
|
|
|
|
|
MDK::Common::File::output($out, map { s/@@@(.*?)@@@/$toreplace{$1}/g; $_ } MDK::Common::File::cat_($in)); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
sub template2userfile { |
497
|
0
|
|
|
0
|
1
|
|
my ($prefix, $in, $out_rel, $force, %toreplace) = @_; |
498
|
|
|
|
|
|
|
|
499
|
0
|
|
|
|
|
|
foreach (list_skels($prefix, $out_rel)) { |
500
|
0
|
0
|
0
|
|
|
|
-d MDK::Common::File::dirname($_) or !-e $_ or $force or next; |
|
|
|
0
|
|
|
|
|
501
|
|
|
|
|
|
|
|
502
|
0
|
|
|
|
|
|
template2file($in, $_, %toreplace); |
503
|
0
|
0
|
|
|
|
|
m|/home/(.+?)/| and chown(getpwnam($1), getgrnam($1), $_); |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
sub read_gnomekderc { |
508
|
0
|
|
|
0
|
1
|
|
my ($file, $category) = @_; |
509
|
0
|
|
|
|
|
|
my %h; |
510
|
0
|
|
|
|
|
|
foreach (MDK::Common::File::cat_($file), "[NOCATEGORY]\n") { |
511
|
0
|
0
|
|
|
|
|
if (/^\s*\[\Q$category\E\]/i ... /^\[/) { |
512
|
0
|
0
|
|
|
|
|
$h{$1} = $2 if /^\s*([^=]*?)=(.*)/; |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
} |
515
|
0
|
|
|
|
|
|
%h; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
sub update_gnomekderc { |
519
|
0
|
|
|
0
|
1
|
|
my ($file, $category, %subst_) = @_; |
520
|
|
|
|
|
|
|
|
521
|
0
|
|
|
|
|
|
my %subst = map { lc($_) => [ $_, $subst_{$_} ] } keys %subst_; |
|
0
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
|
523
|
0
|
|
|
|
|
|
my $s; |
524
|
0
|
0
|
|
|
|
|
defined($category) or $category = "DEFAULTCATEGORY"; |
525
|
0
|
|
|
|
|
|
foreach ("[DEFAULTCATEGORY]\n", MDK::Common::File::cat_($file), "[NOCATEGORY]\n") { |
526
|
0
|
0
|
|
|
|
|
if (my $i = /^\s*\[\Q$category\E\]/i ... /^\[/) { |
527
|
0
|
0
|
|
|
|
|
if ($i =~ /E/) { #- for last line of category |
|
|
0
|
|
|
|
|
|
528
|
0
|
|
|
|
|
|
chomp $s; $s .= "\n"; |
|
0
|
|
|
|
|
|
|
529
|
0
|
|
|
|
|
|
$s .= "$_->[0]=$_->[1]\n" foreach values %subst; |
530
|
0
|
|
|
|
|
|
%subst = (); |
531
|
|
|
|
|
|
|
} elsif (/^\s*([^=]*?)=/) { |
532
|
0
|
0
|
|
|
|
|
if (my $e = delete $subst{lc($1)}) { |
533
|
0
|
|
|
|
|
|
$_ = "$1=$e->[1]\n"; |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
} |
537
|
0
|
0
|
|
|
|
|
$s .= $_ if !/^\[(NO|DEFAULT)CATEGORY\]/; |
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
#- if category has not been found above (DEFAULTCATEGORY is always found). |
541
|
0
|
0
|
|
|
|
|
if (keys %subst) { |
542
|
0
|
|
|
|
|
|
chomp $s; |
543
|
0
|
|
|
|
|
|
$s .= "\n[$category]\n"; |
544
|
0
|
|
|
|
|
|
$s .= "$_->[0]=$_->[1]\n" foreach values %subst; |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
|
547
|
0
|
|
|
|
|
|
MDK::Common::File::output_p($file, $s); |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
sub fuzzy_pidofs { |
552
|
0
|
|
|
0
|
1
|
|
my ($regexp) = @_; |
553
|
|
|
|
|
|
|
grep { |
554
|
0
|
0
|
|
|
|
|
if (/^(\d+)$/) { |
|
0
|
|
|
|
|
|
|
555
|
0
|
|
0
|
|
|
|
my $s = MDK::Common::File::cat_("/proc/$_/cmdline") || |
556
|
|
|
|
|
|
|
readlink("/proc/$_/exe") || |
557
|
|
|
|
|
|
|
MDK::Common::File::cat_("/proc/$_/stat") =~ /\s(\S+)/ && $1 || |
558
|
|
|
|
|
|
|
''; |
559
|
0
|
|
|
|
|
|
$s =~ /$regexp/; |
560
|
|
|
|
|
|
|
} else { |
561
|
0
|
|
|
|
|
|
0; |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
} MDK::Common::File::all('/proc'); |
564
|
|
|
|
|
|
|
} |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
1; |