/
OS.pm
504 lines (346 loc) · 11.6 KB
/
OS.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
package Slim::Utils::OS;
# $Id: Base.pm 21790 2008-07-15 20:18:07Z andy $
# Logitech Media Server Copyright 2001-2011 Logitech.
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License,
# version 2.
# Base class for OS specific code
use strict;
use Config;
use File::Path;
use File::Spec::Functions qw(:ALL);
use FindBin qw($Bin);
use constant MAX_LOGSIZE => 1024 * 1024 * 100;
sub new {
my $class = shift;
my $self = {
osDetails => {},
};
return bless $self, $class;
}
sub initDetails {
return shift->{osDetails};
}
sub getMACAddress {
my $class = shift;
if (!main::SCANNER && !defined $class->{osDetails}->{mac}) {
require Slim::Utils::Network;
# fall back to empty string to prevent repeated attempts (if needed)
$class->{osDetails}->{mac} = Slim::Utils::Network::serverMACAddress() || '';
}
return $class->{osDetails}->{mac};
}
sub details {
return shift->{osDetails};
}
sub initPrefs {}
sub postInitPrefs {}
=head2 migratePrefsFolder()
Use this sub to migrate complete prefs files before they are read.
To be used during product migrations like eg. SqueezeCenter -> Squeezebox Server
Windows & OSX handle this in the installer
=cut
sub migratePrefsFolder {}
sub sqlHelperClass {
if ( $main::dbtype ) {
return "Slim::Utils::${main::dbtype}Helper";
}
return 'Slim::Utils::SQLiteHelper';
}
# Skip obsolete plugins, they should be deleted by installers
sub skipPlugins {return (qw(Picks ShoutcastBrowser Webcasters Health));}
=head2 initSearchPath( [$baseDir] )
Initialises the binary seach path used by Slim::Utils::Misc::findbin to OS specific locations.
Optionally a base directory can be defined, eg. used to add plugin specific folders.
=cut
sub initSearchPath {
my $class = shift;
my $baseDir = shift || $class->dirsFor('Bin');
# Initialise search path for findbin - called later in initialisation than init above
# Reduce all the x86 architectures down to i386, including x86_64, so we only need one directory per *nix OS.
my $binArch = $class->{osDetails}->{'binArch'} = $Config::Config{'archname'};
$class->{osDetails}->{'binArch'} =~ s/^(?:i[3456]86|x86_64)-([^-]+).*/i386-$1/;
# Reduce ARM to arm(hf)-linux
if ( $class->{osDetails}->{'binArch'} =~ /^arm.*linux.*gnueabihf/ ||
($class->{osDetails}->{'binArch'} =~ /arm/ && (
$Config::Config{'lddlflags'} =~ /\-mfloat\-abi=hard/ ||
$Config::Config{'config_args'} =~ /\-mfloat\-abi=hard/
))
) {
$class->{osDetails}->{'binArch'} = 'armhf-linux';
}
elsif ( $class->{osDetails}->{'binArch'} =~ /^arm.*linux/ ) {
$class->{osDetails}->{'binArch'} = 'arm-linux';
}
elsif ( $class->{osDetails}->{'binArch'} =~ /^aarch64-linux/ ) {
$class->{osDetails}->{'binArch'} = 'aarch64-linux';
}
# Reduce PPC to powerpc-linux
elsif ( $class->{osDetails}->{'binArch'} =~ /^(?:ppc|powerpc).*linux/ ) {
$class->{osDetails}->{'binArch'} = 'powerpc-linux';
}
my @paths = ( catdir($baseDir, $class->{osDetails}->{'binArch'}), catdir($baseDir, $^O), $baseDir );
# Linux x86_64 should check its native folder first
if ( $binArch =~ s/^x86_64-([^-]+).*/x86_64-$1/ ) {
unshift @paths, catdir($baseDir, $binArch);
}
elsif ( $class->{osDetails}->{'binArch'} eq 'armhf-linux' ) {
push @paths, catdir($baseDir, 'arm-linux');
}
elsif ( $class->{osDetails}->{'binArch'} =~ /darwin/i && $class->{osDetails}->{osArch} =~ /x86_64/ ) {
unshift @paths, catdir($baseDir, $class->{osDetails}->{'binArch'} . '-x86_64'), catdir($baseDir, $^O . '-x86_64');
}
Slim::Utils::Misc::addFindBinPaths(@paths);
# add path to Extension installer loaded plugins to @INC, NB this can only be done here as it requires Prefs to be loaded
# and the cachedir pref to be set before we can do it. Prefs requires OSDetect so we can't do it at init time of OSDetect.
if ( my $cache = Slim::Utils::Prefs::preferences('server')->get('cachedir') ) {
unshift @INC, catdir($cache, 'InstalledPlugins');
}
}
=head2 initMySQL( )
Provide a hook to do system specific MySQL initialization. This allows to eg. use a locally installed
MySQL server instead of the instance installed with SC
=cut
sub initMySQL {
my ($class, $dbclass) = @_;
require File::Which;
# try to figure out whether we have a locally running MySQL
# which we can connect to using a socket file
my $mysql_config = File::Which::which('mysql_config');
# The user might have a socket file in a non-standard
# location. See bug 3443
if ($mysql_config && -x $mysql_config) {
my $socket = `$mysql_config --socket`;
chomp($socket);
if ($socket && -S $socket) {
$dbclass->socketFile($socket);
}
}
}
=head2 dirsFor( $dir )
Return OS Specific directories.
Argument $dir is a string to indicate which of the Logitech Media Server directories we
need information for.
=cut
sub dirsFor {
my $class = shift;
my $dir = shift;
my @dirs = ();
if ($dir eq "Plugins") {
push @dirs, catdir($Bin, 'Slim', 'Plugin');
# add on path to plugins installed by Extension installer, NB this can only be called after Prefs is loaded
push @dirs, catdir( Slim::Utils::Prefs::preferences('server')->get('cachedir'), 'InstalledPlugins', 'Plugins' );
}
elsif ($dir eq 'updates') {
my $updateDir;
eval {
$updateDir = catdir( Slim::Utils::Prefs::preferences('server')->get('cachedir'), $dir );
};
if ($@) {
eval {
$updateDir = catdir( Slim::Utils::Light::getPref('cachedir'), $dir );
};
}
return unless $updateDir;
mkdir $updateDir unless -d $updateDir;
push @dirs, $updateDir;
}
return wantarray() ? @dirs : $dirs[0];
}
=head2 logRotate( $dir )
Simple log rotation for systems which don't do this automatically (OSX/Windows).
=cut
sub logRotate {
my $class = shift;
my $dir = shift || Slim::Utils::OSDetect::dirsFor('log');
my $maxSize = shift || MAX_LOGSIZE;
require File::Copy;
opendir(DIR, $dir) or return;
while ( defined (my $file = readdir(DIR)) ) {
next if $file !~ /\.log$/i;
$file = catdir($dir, $file);
# max. log size (default: 100MB)
if (-s $file > $maxSize) {
# keep one old copy
my $oldfile = "$file.0";
unlink $oldfile if -e $oldfile;
File::Copy::move($file, $oldfile);
}
}
closedir(DIR);
}
=head2 decodeExternalHelperPath( $filename )
When calling calling external helper apps (transcoding, MySQL etc.)
we might need to encode the path to correctly handle non-latin characters.
=cut
sub decodeExternalHelperPath {
my $path = $_[1];
# Bug 8118, only decode if filename can't be found
# No. We need to set the UFT8 flag if we have non-ASCII contents
$path = Slim::Utils::Unicode::utf8decode_locale($path);
return $path;
}
sub scanner {
return "$Bin/scanner.pl";
}
sub gdresize {
return "$Bin/gdresize.pl";
}
sub gdresized {
return "$Bin/gdresized.pl";
}
sub dontSetUserAndGroup { 0 }
=head2 getProxy( )
Try to read the system's proxy setting by evaluating environment variables,
registry and browser settings
=cut
sub getProxy {
my $proxy = '';
$proxy = $ENV{'http_proxy'};
my $proxy_port = $ENV{'http_proxy_port'};
# remove any leading "http://"
if($proxy) {
$proxy =~ s/http:\/\///i;
$proxy = $proxy . ":" .$proxy_port if($proxy_port);
}
return $proxy;
}
=head2 getDefaultGateway()
Get the network's default gateway address
=cut
sub getDefaultGateway { '' }
sub ignoredItems {
return (
# Items we should ignore on a linux volume
'lost+found' => 1,
);
}
=head2 localeDetails()
Get details about the locale, system language etc.
=cut
sub localeDetails {
require POSIX;
my $lc_time = POSIX::setlocale(POSIX::LC_TIME()) || 'C';
my $lc_ctype = POSIX::setlocale(POSIX::LC_CTYPE()) || 'C';
# If the locale is C or POSIX, that's ASCII - we'll set to iso-8859-1
# Otherwise, normalize the codeset part of the locale.
if ($lc_ctype eq 'C' || $lc_ctype eq 'POSIX') {
warn "Your locale was detected as $lc_ctype, you may have problems with non-Latin filenames. Consider changing your LANG variable to the correct locale, i.e. en_US.utf8\n";
$lc_ctype = 'iso-8859-1';
} else {
$lc_ctype = lc((split(/\./, $lc_ctype))[1]);
}
# Locale can end up with nothing, if it's invalid, such as "en_US"
if (!defined $lc_ctype || $lc_ctype =~ /^\s*$/) {
$lc_ctype = 'iso-8859-1';
}
# Sometimes underscores can be aliases - Solaris
$lc_ctype =~ s/_/-/g;
# ISO encodings with 4 or more digits use a hyphen after "ISO"
$lc_ctype =~ s/^iso(\d{4})/iso-$1/;
# Special case ISO 2022 and 8859 to be nice
$lc_ctype =~ s/^iso-(2022|8859)([^-])/iso-$1-$2/;
$lc_ctype =~ s/utf-8/utf8/gi;
# CJK Locales
$lc_ctype =~ s/eucjp/euc-jp/i;
$lc_ctype =~ s/ujis/euc-jp/i;
$lc_ctype =~ s/sjis/shiftjis/i;
$lc_ctype =~ s/euckr/euc-kr/i;
$lc_ctype =~ s/big5/big5-eten/i;
$lc_ctype =~ s/gb2312/euc-cn/i;
return ($lc_ctype, $lc_time);
}
=head2 getSystemLanguage()
Return the system's language or 'EN' as default value
=cut
sub getSystemLanguage {
require POSIX;
my $class = shift;
$class->_parseLanguage(POSIX::setlocale(POSIX::LC_CTYPE()));
}
sub _parseLanguage {
my ($class, $language) = @_;
$language = uc($language);
$language =~ s/\.UTF.*$//;
$language =~ s/(?:_|-|\.)\w+$//;
return 'EN' if $language && $language eq 'C';
return $language || 'EN';
}
=head2 get( 'key' [, 'key2', 'key...'] )
Get a list of values from the osDetails list
=cut
sub get {
my $class = shift;
if ( wantarray ) {
return map { $class->{osDetails}->{$_} }
grep { $class->{osDetails}->{$_} } @_;
}
else {
return $class->{osDetails}->{+shift};
}
}
=head2 setPriority( $priority )
Set the priority for the server. $priority should be -20 to 20
=cut
sub setPriority {
my $class = shift;
my $priority = shift;
return unless defined $priority && $priority =~ /^-?\d+$/;
# For *nix, including OSX, set whatever priority the user gives us.
Slim::Utils::Log::logger('server')->info("Logitech Media Server changing process priority to $priority");
eval { setpriority (0, 0, $priority); };
if ($@) {
Slim::Utils::Log->logError("Couldn't set priority to $priority [$@]");
}
}
=head2 getPriority( )
Get the current priority of the server.
=cut
sub getPriority {
my $priority = eval { getpriority (0, 0) };
if ($@) {
Slim::Utils::Log->logError("Can't get priority [$@]");
}
return $priority;
}
=head2 initUpdate( )
Initialize download of a potential updated Logitech Media Server version.
Not needed on Linux distributions which do manage the update through their repositories.
=cut
sub initUpdate {};
sub getUpdateParams { 0 };
sub canAutoUpdate { 0 };
sub installerExtension { '' };
sub installerOS { '' };
# XXX - disable AutoRescan for all but SqueezeOS for now
sub canAutoRescan { 0 }
# can we use more memory to improve DB performance?
sub canDBHighMem { 0 }
# some systems support checking ACLs in addition to simpler file tests
my $filetest;
sub aclFiletest {
my ($class, $cb) = @_;
$filetest = $cb if $cb;
return $filetest;
}
=head2 directFirmwareDownload( )
Return true if you don't want the server to download and cache firmware
upgrades for your players. It will then tell the player to download them directly
from SqueezeNetwork.
Use this if you are running the server on low spec hardware or flash with limited capacity.
=cut
sub directFirmwareDownload { 0 };
=head2 restartServer( ) and canRestartServer
The server can initiate a restart on some systems.
These methods must only be called from main::restartServer and
main::canRestartServer which supervise other cleanup operations.
The implementations of the methods are redefined in each of the
OS implementations that can support the restart feature.
=cut
sub restartServer { 0 }
sub canRestartServer { 0 }
sub progressJSON { }
sub runningFromSource {
$::REVISION =~ /^\s*\d+\s*$/ ? 0 : 1;
}
1;