line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mail::Toaster::FreeBSD; |
2
|
1
|
|
|
1
|
|
609
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
71
|
|
3
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
35
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
our $VERSION = '5.50'; |
6
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
4
|
use Carp; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
38
|
|
8
|
1
|
|
|
1
|
|
3
|
use File::Copy; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
38
|
|
9
|
1
|
|
|
1
|
|
4
|
use Params::Validate qw( :all ); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
114
|
|
10
|
1
|
|
|
1
|
|
4
|
use POSIX; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
7
|
|
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
1395
|
use lib 'lib'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
5
|
|
13
|
1
|
|
|
1
|
|
68
|
use parent 'Mail::Toaster::Base'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
5
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub drive_spin_down { |
16
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
17
|
0
|
|
|
|
|
|
my %p = validate( @_, { 'drive' => SCALAR, $self->get_std_opts } ); |
18
|
0
|
|
|
|
|
|
my %args = $self->toaster->get_std_args( %p ); |
19
|
|
|
|
|
|
|
|
20
|
0
|
|
|
|
|
|
my $drive = $p{'drive'}; |
21
|
|
|
|
|
|
|
|
22
|
0
|
0
|
|
|
|
|
return $p{'test_ok'} if defined $p{'test_ok'}; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
#TODO: see if the drive exists! |
25
|
|
|
|
|
|
|
|
26
|
0
|
0
|
|
|
|
|
my $camcontrol = $self->util->find_bin( "camcontrol", %args) |
27
|
|
|
|
|
|
|
or return $self->error( "couldn't find camcontrol", %args ); |
28
|
|
|
|
|
|
|
|
29
|
0
|
|
|
|
|
|
print "spinning down backup drive $drive..."; |
30
|
0
|
|
|
|
|
|
$self->util->syscmd( "$camcontrol stop $drive", %args ); |
31
|
0
|
|
|
|
|
|
print "done.\n"; |
32
|
0
|
|
|
|
|
|
return 1; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub get_defines { |
36
|
0
|
|
|
0
|
0
|
|
my ($self, $flags) = @_; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# flags are the "make -DWITH_OPTION" flags |
39
|
0
|
0
|
|
|
|
|
return '' if ! $flags; |
40
|
|
|
|
|
|
|
|
41
|
0
|
|
|
|
|
|
my $make_defines; |
42
|
0
|
|
|
|
|
|
foreach my $def ( split( /,/, $flags ) ) { |
43
|
0
|
0
|
|
|
|
|
if ( $def =~ /=/ ) { # DEFINE=VALUE format, use as is |
44
|
0
|
|
|
|
|
|
$make_defines .= " $def "; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
else { |
47
|
0
|
|
|
|
|
|
$make_defines .= " -D$def "; # otherwise, prepend the -D flag |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
} |
50
|
0
|
|
|
|
|
|
return $make_defines; |
51
|
|
|
|
|
|
|
}; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub get_port_category { |
54
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
55
|
0
|
0
|
|
|
|
|
my $port = shift or die "missing port in request\n"; |
56
|
|
|
|
|
|
|
|
57
|
0
|
|
|
|
|
|
my ($path) = glob("/usr/ports/*/$port/distinfo"); |
58
|
0
|
0
|
|
|
|
|
if ( ! $path ) { |
59
|
0
|
|
|
|
|
|
($path) = glob("/usr/ports/*/$port/Makefile"); |
60
|
|
|
|
|
|
|
}; |
61
|
0
|
0
|
|
|
|
|
return if ! $path; |
62
|
0
|
|
|
|
|
|
return (split '/', $path)[3]; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub get_version { |
66
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
67
|
|
|
|
|
|
|
|
68
|
0
|
|
|
|
|
|
my (undef, undef, $version) = POSIX::uname; |
69
|
0
|
|
|
|
|
|
$self->audit( "version is $version" ); |
70
|
|
|
|
|
|
|
|
71
|
0
|
|
|
|
|
|
return $version; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub install_port { |
75
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
76
|
0
|
0
|
|
|
|
|
my $portname = shift or return $self->error("missing port/package name" ); |
77
|
0
|
|
|
|
|
|
my %p = validate( @_, |
78
|
|
|
|
|
|
|
{ dir => { type => SCALAR, optional => 1 }, |
79
|
|
|
|
|
|
|
category => { type => SCALAR, optional => 1 }, |
80
|
|
|
|
|
|
|
check => { type => SCALAR, optional => 1 }, |
81
|
|
|
|
|
|
|
flags => { type => SCALAR, optional => 1 }, |
82
|
|
|
|
|
|
|
options => { type => SCALAR, optional => 1 }, |
83
|
|
|
|
|
|
|
$self->get_std_opts, |
84
|
|
|
|
|
|
|
}, |
85
|
|
|
|
|
|
|
); |
86
|
|
|
|
|
|
|
|
87
|
0
|
|
|
|
|
|
my $options = $p{options}; |
88
|
0
|
|
|
|
|
|
my %args = $self->get_std_args( %p ); |
89
|
|
|
|
|
|
|
|
90
|
0
|
0
|
|
|
|
|
return $p{test_ok} if defined $p{test_ok}; |
91
|
|
|
|
|
|
|
|
92
|
0
|
|
0
|
|
|
|
my $check = $p{check} || $portname; |
93
|
0
|
0
|
|
|
|
|
return 1 if $self->is_port_installed( $check, verbose=>1); |
94
|
|
|
|
|
|
|
|
95
|
0
|
|
0
|
|
|
|
my $port_dir = $p{dir} || $portname; |
96
|
0
|
|
|
|
|
|
$port_dir =~ s/::/-/g; |
97
|
|
|
|
|
|
|
|
98
|
0
|
0
|
0
|
|
|
|
my $category = $p{category} || $self->get_port_category($portname) |
99
|
|
|
|
|
|
|
or die "unable to find port directory for port $portname\n"; |
100
|
|
|
|
|
|
|
|
101
|
0
|
|
|
|
|
|
my $path = "/usr/ports/$category/$port_dir"; |
102
|
0
|
0
|
|
|
|
|
-d $path or $self->error( "missing $path: $!\n" ); |
103
|
|
|
|
|
|
|
|
104
|
0
|
|
|
|
|
|
$self->util->audit("install_port: installing $portname"); |
105
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
my $make_defines = $self->get_defines($p{flags}); |
107
|
|
|
|
|
|
|
|
108
|
0
|
0
|
|
|
|
|
if ($options) { |
109
|
0
|
|
|
|
|
|
$self->port_options( port => $portname, cat => $category, opts => $options ); |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# reset our PATH, to make sure we use our system supplied tools |
113
|
0
|
|
|
|
|
|
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"; |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# the vast majority of ports work great this way |
116
|
0
|
|
|
|
|
|
$self->audit( "running: make -C $path $make_defines install clean"); |
117
|
0
|
|
|
|
|
|
system "make -C $path clean"; |
118
|
0
|
|
|
|
|
|
system "make -C $path $make_defines"; |
119
|
0
|
|
|
|
|
|
system "make -C $path $make_defines install"; |
120
|
0
|
0
|
|
|
|
|
if ( $portname eq "ezmlm-idx" ) { |
121
|
0
|
|
|
|
|
|
copy( "$path/work/ezmlm-0.53/ezmlmrc", "/usr/local/bin" ); |
122
|
|
|
|
|
|
|
} |
123
|
0
|
|
|
|
|
|
system "make -C $path clean"; |
124
|
|
|
|
|
|
|
|
125
|
0
|
0
|
|
|
|
|
return 1 if $self->is_port_installed( $check, verbose=>1 ); |
126
|
|
|
|
|
|
|
|
127
|
0
|
|
|
|
|
|
$self->util->audit( "install_port: $portname install, FAILED" ); |
128
|
|
|
|
|
|
|
|
129
|
0
|
0
|
|
|
|
|
if ( $portname =~ /\Ap5\-(.*)\z/ ) { |
130
|
0
|
|
|
|
|
|
my $p_name = $1; |
131
|
0
|
|
|
|
|
|
$p_name =~ s/\-/::/g; |
132
|
0
|
0
|
|
|
|
|
$self->util->install_module_cpan($p_name) and return 1; |
133
|
|
|
|
|
|
|
}; |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
$self->install_port_try_manual( $portname, $path ); |
136
|
0
|
|
|
|
|
|
return $self->error( "Install of $portname failed. Please fix and try again.", %args); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub is_port_installed { |
140
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
141
|
0
|
0
|
|
|
|
|
my $port = shift or return $self->error("missing port name", fatal=>0); |
142
|
0
|
|
|
|
|
|
my %p = validate( @_, |
143
|
|
|
|
|
|
|
{ 'alt' => { type => SCALAR | UNDEF, optional => 1 }, |
144
|
|
|
|
|
|
|
$self->get_std_opts, |
145
|
|
|
|
|
|
|
}, |
146
|
|
|
|
|
|
|
); |
147
|
|
|
|
|
|
|
|
148
|
0
|
|
0
|
|
|
|
my $alt = $p{alt} || $port; |
149
|
|
|
|
|
|
|
|
150
|
0
|
|
|
|
|
|
my ( $r, @args ); |
151
|
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
|
$self->util->audit( " checking for port $port", verbose=>0); |
153
|
|
|
|
|
|
|
|
154
|
0
|
0
|
|
|
|
|
return $p{test_ok} if defined $p{test_ok}; |
155
|
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
|
my @packages; |
157
|
0
|
0
|
|
|
|
|
if ( -x '/usr/sbin/pkg' ) { |
158
|
0
|
|
|
|
|
|
@packages = `/usr/sbin/pkg info`; chomp @packages; |
|
0
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
else { |
161
|
0
|
|
|
|
|
|
my $pkg_info = $self->util->find_bin( 'pkg_info', verbose => 0 ); |
162
|
0
|
|
|
|
|
|
@packages = `$pkg_info`; chomp @packages; |
|
0
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
0
|
|
|
|
|
|
my @matches = grep {/^$port\-/} @packages; |
|
0
|
|
|
|
|
|
|
166
|
0
|
0
|
|
|
|
|
if ( scalar @matches == 0 ) { @matches = grep {/^$port/} @packages; }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
167
|
0
|
0
|
|
|
|
|
if ( scalar @matches == 0 ) { @matches = grep {/^$alt\-/ } @packages; }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
168
|
0
|
0
|
|
|
|
|
if ( scalar @matches == 0 ) { @matches = grep {/^$alt/ } @packages; }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
169
|
0
|
0
|
|
|
|
|
return if scalar @matches == 0; # no matches |
170
|
0
|
0
|
|
|
|
|
$self->util->audit( "WARN: found multiple matches for port $port",verbose=>1) |
171
|
|
|
|
|
|
|
if scalar @matches > 1; |
172
|
|
|
|
|
|
|
|
173
|
0
|
|
|
|
|
|
my ($installed_as) = split(/\s/, $matches[0]); |
174
|
0
|
|
|
|
|
|
$self->util->audit( "found port $port installed as $installed_as" ); |
175
|
0
|
|
|
|
|
|
return $installed_as; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
sub install_portupgrade { |
179
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
180
|
0
|
|
|
|
|
|
my %p = validate( @_, { $self->get_std_opts } ); |
181
|
|
|
|
|
|
|
|
182
|
0
|
|
|
|
|
|
my %args = $self->toaster->get_std_args( %p ); |
183
|
|
|
|
|
|
|
|
184
|
0
|
|
0
|
|
|
|
my $package = $self->conf->{'package_install_method'} || "packages"; |
185
|
|
|
|
|
|
|
|
186
|
0
|
0
|
|
|
|
|
if ( defined $p{'test_ok'} ) { return $p{'test_ok'}; } |
|
0
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
# if we're running FreeBSD 6, try installing the package as it will do the |
189
|
|
|
|
|
|
|
# right thing. On older systems we want to install a (much newer) version |
190
|
|
|
|
|
|
|
# of portupgrade from ports |
191
|
|
|
|
|
|
|
|
192
|
0
|
0
|
|
|
|
|
if ( $self->get_version =~ m/\A6/ ) { |
193
|
0
|
|
|
|
|
|
$self->install_package( "portupgrade", %args ); |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
0
|
0
|
|
|
|
|
if ( $package eq "packages" ) { |
197
|
0
|
|
|
|
|
|
$self->install_package( "ruby18_static", |
198
|
|
|
|
|
|
|
alt => "ruby-1.8", |
199
|
|
|
|
|
|
|
%args, |
200
|
|
|
|
|
|
|
); |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
0
|
|
|
|
|
|
$self->install_port( port => "portupgrade", %args ); |
204
|
|
|
|
|
|
|
|
205
|
0
|
0
|
|
|
|
|
return 1 if $self->is_port_installed( "portupgrade" ); |
206
|
0
|
|
|
|
|
|
return; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
sub install_package { |
210
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
211
|
0
|
0
|
|
|
|
|
my $package = shift or die "missing package in request\n"; |
212
|
0
|
|
|
|
|
|
my %p = validate( |
213
|
|
|
|
|
|
|
@_, |
214
|
|
|
|
|
|
|
{ 'alt' => { type => SCALAR, optional => 1, }, |
215
|
|
|
|
|
|
|
'url' => { type => SCALAR, optional => 1, }, |
216
|
|
|
|
|
|
|
$self->get_std_opts, |
217
|
|
|
|
|
|
|
}, |
218
|
|
|
|
|
|
|
); |
219
|
|
|
|
|
|
|
|
220
|
0
|
|
|
|
|
|
my ( $alt, $pkg_url ) = ( $p{'alt'}, $p{'url'} ); |
221
|
0
|
|
|
|
|
|
my %args = $self->toaster->get_std_args( %p ); |
222
|
|
|
|
|
|
|
|
223
|
0
|
|
|
|
|
|
$self->util->audit("install_package: checking if $package is installed"); |
224
|
|
|
|
|
|
|
|
225
|
0
|
0
|
|
|
|
|
return $p{'test_ok'} if defined $p{'test_ok'}; |
226
|
|
|
|
|
|
|
|
227
|
0
|
0
|
|
|
|
|
return 1 if $self->is_port_installed( $package, alt => $alt, %args ); |
228
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
|
print "install_package: installing $package....\n"; |
230
|
0
|
0
|
|
|
|
|
$ENV{"PACKAGESITE"} = $pkg_url if $pkg_url; |
231
|
|
|
|
|
|
|
|
232
|
0
|
|
|
|
|
|
my ($pkg_add, $r2); |
233
|
0
|
0
|
|
|
|
|
if ( -x '/usr/sbin/pkg' ) { |
234
|
0
|
|
|
|
|
|
$pkg_add = '/usr/sbin/pkg'; |
235
|
0
|
|
|
|
|
|
$r2 = $self->util->syscmd( "$pkg_add install -y $package", verbose => 0 ); |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
0
|
0
|
|
|
|
|
if (! -x $pkg_add) { |
239
|
0
|
|
|
|
|
|
$pkg_add = $self->util->find_bin( "pkg_add", %args ); |
240
|
0
|
0
|
0
|
|
|
|
if ( !$pkg_add || !-x $pkg_add ) { |
241
|
0
|
|
|
|
|
|
return $self->error( "couldn't find pkg_add",fatal=>0) |
242
|
|
|
|
|
|
|
}; |
243
|
0
|
|
|
|
|
|
$r2 = $self->util->syscmd( "$pkg_add -r $package", verbose => 0 ); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
0
|
0
|
|
|
|
|
if ( !$r2 ) { print "\t $pkg_add failed\t "; } |
|
0
|
|
|
|
|
|
|
247
|
0
|
|
|
|
|
|
else { print "\t $pkg_add success\t " }; |
248
|
|
|
|
|
|
|
|
249
|
0
|
|
|
|
|
|
my $r = $self->is_port_installed( $package, alt => $alt, %args ); |
250
|
0
|
0
|
|
|
|
|
if ( ! $r ) { |
251
|
0
|
|
|
|
|
|
carp " : Sorry, I couldn't install $package!\n"; |
252
|
0
|
|
|
|
|
|
return; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
0
|
|
|
|
|
|
return $r; |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub install_port_try_manual { |
259
|
0
|
|
|
0
|
0
|
|
my ($self, $portname, $path ) = @_; |
260
|
0
|
|
|
|
|
|
print <<"EO_PORT_TRY_MANUAL"; |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Automatic installation of port $portname failed! You can try to install $portname manually |
263
|
|
|
|
|
|
|
using the following commands: |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
cd $path |
266
|
|
|
|
|
|
|
make |
267
|
|
|
|
|
|
|
make install clean |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
If that does not work, make sure your ports tree is up to date and |
270
|
|
|
|
|
|
|
try again. See also "Dealing With Broken Ports": |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/ports-broken.html |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
If manual installation fails, there may be something "unique" about your system |
275
|
|
|
|
|
|
|
or the port may be broken. You can: |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
a. Wait until the port is fixed |
278
|
|
|
|
|
|
|
b. Try fixing the port |
279
|
|
|
|
|
|
|
c. Get someone else to fix it |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
EO_PORT_TRY_MANUAL |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
sub port_options { |
285
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
286
|
0
|
|
|
|
|
|
my %p = validate( |
287
|
|
|
|
|
|
|
@_, |
288
|
|
|
|
|
|
|
{ port => SCALAR, |
289
|
|
|
|
|
|
|
opts => SCALAR, |
290
|
|
|
|
|
|
|
cat => SCALAR, |
291
|
|
|
|
|
|
|
$self->get_std_opts, |
292
|
|
|
|
|
|
|
}, |
293
|
|
|
|
|
|
|
); |
294
|
|
|
|
|
|
|
|
295
|
0
|
|
|
|
|
|
my ( $port, $cat, $opts ) = ( $p{port}, $p{cat}, $p{opts} ); |
296
|
0
|
|
|
|
|
|
my %args = $self->toaster->get_std_args( %p ); |
297
|
|
|
|
|
|
|
|
298
|
0
|
0
|
|
|
|
|
return $p{test_ok} if defined $p{test_ok}; |
299
|
|
|
|
|
|
|
|
300
|
0
|
|
|
|
|
|
my $opt_dir = "/var/db/ports/$cat".'_'.$port; |
301
|
0
|
0
|
|
|
|
|
if ( !-d $opt_dir ) { |
302
|
0
|
|
|
|
|
|
$self->util->mkdir_system( dir => $opt_dir, %args,); |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
0
|
|
|
|
|
|
my $prefix = '# This file installed by Mail::Toaster'; |
306
|
0
|
|
|
|
|
|
$self->util->file_write( "$opt_dir/options", lines => [$prefix,$opts], %args ); |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
sub update_ports { |
310
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
311
|
0
|
|
|
|
|
|
my %p = validate( @_, { $self->get_std_opts, } ); |
312
|
0
|
|
|
|
|
|
my %args = $self->toaster->get_std_args( %p ); |
313
|
|
|
|
|
|
|
|
314
|
0
|
0
|
|
|
|
|
return $p{test_ok} if defined $p{test_ok}; |
315
|
|
|
|
|
|
|
|
316
|
0
|
0
|
|
|
|
|
return $self->error( "you do not have write permission to /usr/ports.",%args) if ! $self->util->is_writable('/usr/ports', %args); |
317
|
|
|
|
|
|
|
|
318
|
0
|
|
0
|
|
|
|
my $supfile = $self->conf->{'cvsup_supfile_ports'} || "portsnap"; |
319
|
|
|
|
|
|
|
|
320
|
0
|
|
|
|
|
|
return $self->portsnap( %args); |
321
|
|
|
|
|
|
|
|
322
|
0
|
|
|
|
|
|
return 1; |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub portsnap { |
326
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
327
|
0
|
|
|
|
|
|
my %p = validate( @_, { $self->get_std_opts, },); |
328
|
|
|
|
|
|
|
|
329
|
0
|
|
|
|
|
|
my %args = $self->toaster->get_std_args( %p ); |
330
|
|
|
|
|
|
|
|
331
|
0
|
0
|
|
|
|
|
return $p{'test_ok'} if defined $p{'test_ok'}; |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# should be installed already on FreeBSD 5.5 and 6.x |
334
|
0
|
|
|
|
|
|
my $portsnap = $self->util->find_bin( "portsnap", fatal => 0 ); |
335
|
0
|
|
|
|
|
|
my $ps_conf = "/etc/portsnap.conf"; |
336
|
|
|
|
|
|
|
|
337
|
0
|
0
|
0
|
|
|
|
unless ( $portsnap && -x $portsnap ) { |
338
|
0
|
|
|
|
|
|
$self->install_port( "portsnap" ); |
339
|
|
|
|
|
|
|
|
340
|
0
|
|
|
|
|
|
$ps_conf = '/usr/local/etc/portsnap.conf'; |
341
|
0
|
0
|
|
|
|
|
if ( !-e $ps_conf ) { |
342
|
0
|
0
|
|
|
|
|
if ( -e "$ps_conf.sample" ) { |
343
|
0
|
|
|
|
|
|
copy( "$ps_conf.sample", $ps_conf ); |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
else { |
346
|
0
|
|
|
|
|
|
warn "WARNING: portsnap configuration file is missing!\n"; |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
0
|
|
|
|
|
|
$portsnap = $self->util->find_bin( "portsnap", fatal => 0 ); |
351
|
0
|
0
|
0
|
|
|
|
unless ( $portsnap && -x $portsnap ) { |
352
|
0
|
|
|
|
|
|
return $self->util->error( |
353
|
|
|
|
|
|
|
"portsnap is not installed (correctly). I cannot go on!"); |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
0
|
0
|
|
|
|
|
if ( !-e $ps_conf ) { |
358
|
0
|
|
|
|
|
|
$portsnap .= " -s portsnap.freebsd.org"; |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
# grabs the latest updates from the portsnap servers |
362
|
0
|
|
|
|
|
|
system $portsnap, 'fetch'; |
363
|
|
|
|
|
|
|
|
364
|
0
|
0
|
|
|
|
|
if ( !-e "/usr/ports/.portsnap.INDEX" ) { |
365
|
0
|
|
|
|
|
|
print "\a |
366
|
|
|
|
|
|
|
COFFEE BREAK TIME: this step will take a while, dependent on how fast your |
367
|
|
|
|
|
|
|
disks are. After this initial extract, portsnap updates are much quicker than |
368
|
|
|
|
|
|
|
doing a cvsup and require less bandwidth (good for you, and the FreeBSD |
369
|
|
|
|
|
|
|
servers). Please be patient.\n\n"; |
370
|
0
|
|
|
|
|
|
sleep 2; |
371
|
0
|
|
|
|
|
|
system $portsnap, "extract"; |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
else { |
374
|
0
|
|
|
|
|
|
system $portsnap, "update"; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
|
377
|
0
|
|
|
|
|
|
return 1; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
sub conf_check { |
381
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
382
|
0
|
|
|
|
|
|
my %p = validate( |
383
|
|
|
|
|
|
|
@_, |
384
|
|
|
|
|
|
|
{ 'check' => { type => SCALAR, }, |
385
|
|
|
|
|
|
|
'line' => { type => SCALAR, }, |
386
|
|
|
|
|
|
|
'file' => { type => SCALAR, optional => 1, }, |
387
|
|
|
|
|
|
|
$self->get_std_opts, |
388
|
|
|
|
|
|
|
}, |
389
|
|
|
|
|
|
|
); |
390
|
|
|
|
|
|
|
|
391
|
0
|
|
|
|
|
|
my %args = $self->get_std_args( %p ); |
392
|
0
|
|
|
|
|
|
my $check = $p{check}; |
393
|
0
|
|
|
|
|
|
my $line = $p{line}; |
394
|
0
|
|
0
|
|
|
|
my $file = $p{file} || "/etc/rc.conf"; |
395
|
0
|
|
|
|
|
|
$self->util->audit("conf_check: looking for $check"); |
396
|
|
|
|
|
|
|
|
397
|
0
|
0
|
|
|
|
|
return $p{'test_ok'} if defined $p{'test_ok'}; |
398
|
|
|
|
|
|
|
|
399
|
0
|
|
|
|
|
|
my $changes; |
400
|
|
|
|
|
|
|
my @lines; |
401
|
0
|
0
|
|
|
|
|
@lines = $self->util->file_read( $file ) if -f $file; |
402
|
0
|
|
|
|
|
|
foreach ( @lines ) { |
403
|
0
|
0
|
|
|
|
|
next if $_ !~ /^$check\=/; |
404
|
0
|
0
|
|
|
|
|
return $self->util->audit("\tno change") if $_ eq $line; |
405
|
0
|
|
|
|
|
|
$self->util->audit("\tchanged:\n$_\n\tto:\n$line\n" ); |
406
|
0
|
|
|
|
|
|
$_ = $line; |
407
|
0
|
|
|
|
|
|
$changes++; |
408
|
|
|
|
|
|
|
}; |
409
|
0
|
0
|
|
|
|
|
if ( $changes ) { |
410
|
0
|
|
|
|
|
|
return $self->util->file_write( $file, lines => \@lines, %args ); |
411
|
|
|
|
|
|
|
}; |
412
|
|
|
|
|
|
|
|
413
|
0
|
|
|
|
|
|
return $self->util->file_write( $file, append => 1, lines => [$line], %args ); |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
1; |
417
|
|
|
|
|
|
|
__END__ |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=head1 NAME |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
Mail::Toaster::FreeBSD - FreeBSD specific Mail::Toaster functions. |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=head1 SYNOPSIS |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
Primarily functions for working with FreeBSD ports (updating, installing, configuring with custom options, etc) but also includes a suite of methods for FreeBSD managing jails. |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
=head1 DESCRIPTION |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
Usage examples for each subroutine are included. |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
=head1 SUBROUTINES |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=over |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=item new |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
use Mail::Toaster::FreeBSD; |
441
|
|
|
|
|
|
|
my $fbsd = Mail::Toaster::FreeBSD->new; |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
=item is_port_installed |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
Checks to see if a port is installed. |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
$fbsd->is_port_installed( "p5-CGI" ); |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
arguments required |
451
|
|
|
|
|
|
|
port - the name of the port/package |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
arguments optional: |
454
|
|
|
|
|
|
|
alt - alternate package name. This can help as ports evolve and register themselves differently in the ports database. |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
result: |
457
|
|
|
|
|
|
|
0 - not installed |
458
|
|
|
|
|
|
|
1 - if installed |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=item jail_create |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
$fbsd->jail_create( ); |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
arguments required: |
466
|
|
|
|
|
|
|
ip - 10.0.1.1 |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
arguments optional: |
469
|
|
|
|
|
|
|
hostname - jail36.example.com, |
470
|
|
|
|
|
|
|
jail_home - /home/jail, |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
If hostname is not passed and reverse DNS is set up, it will |
473
|
|
|
|
|
|
|
be looked up. Otherwise, the hostname defaults to "jail". |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
jail_home defaults to "/home/jail". |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
Here's an example of how I use it: |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
ifconfig fxp0 inet alias 10.0.1.175/32 |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
perl -e 'use Mail::Toaster::FreeBSD; |
482
|
|
|
|
|
|
|
my $fbsd = Mail::Toaster::FreeBSD->new; |
483
|
|
|
|
|
|
|
$fbsd->jail_create( ip=>"10.0.1.175" )'; |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
After running $fbsd->jail_create, you need to set up the jail. |
486
|
|
|
|
|
|
|
At the very least, you need to: |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
1. set root password |
489
|
|
|
|
|
|
|
2. create a user account |
490
|
|
|
|
|
|
|
3. get remote root |
491
|
|
|
|
|
|
|
a) use sudo (pkg_add -r sudo; visudo) |
492
|
|
|
|
|
|
|
b) add user to wheel group (vi /etc/group) |
493
|
|
|
|
|
|
|
c) modify /etc/ssh/sshd_config to permit root login |
494
|
|
|
|
|
|
|
4. install perl (pkg_add -r perl) |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
Here's how I set up my jails: |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
pw useradd -n matt -d /home/matt -s /bin/tcsh -m -h 0 |
499
|
|
|
|
|
|
|
passwd root |
500
|
|
|
|
|
|
|
pkg_add -r sudo rsync perl5.8 |
501
|
|
|
|
|
|
|
rehash; visudo |
502
|
|
|
|
|
|
|
sh /etc/rc |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
Ssh into the jail from another terminal. Once successfully |
505
|
|
|
|
|
|
|
logged in with root privs, you can drop the initial shell |
506
|
|
|
|
|
|
|
and access the jail directly. |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
Read the jail man pages for more details. Read the perl code |
509
|
|
|
|
|
|
|
to see what else it does. |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
=item jail_delete |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
Delete a jail. |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
$freebsd->jail_delete( ip=>'10.0.1.160' ); |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
This script unmounts the proc and dev filesystems and then nukes the jail directory. |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
It would be a good idea to shut down any processes in the jail first. |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=item jail_start |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
Starts up a FreeBSD jail. |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
$fbsd->jail_start( ip=>'10.0.1.1', hostname=>'jail03.example.com' ); |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
arguments required: |
531
|
|
|
|
|
|
|
ip - 10.0.1.1, |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
arguments optional: |
534
|
|
|
|
|
|
|
hostname - jail36.example.com, |
535
|
|
|
|
|
|
|
jail_home - /home/jail, |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
If hostname is not passed and reverse DNS is set up, it will be |
538
|
|
|
|
|
|
|
looked up. Otherwise, the hostname defaults to "jail". |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
jail_home defaults to "/home/jail". |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
Here's an example of how I use it: |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
perl -e 'use Mail::Toaster::FreeBSD; |
545
|
|
|
|
|
|
|
$fbsd = Mail::Toaster::FreeBSD->new; |
546
|
|
|
|
|
|
|
$fbsd->jail_start( ip=>"10.0.1.175" )'; |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
=item install_port |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
$fbsd->install_port( "openldap" ); |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
That's it. Really. Well, OK, sometimes it can get a little more complex. install_port checks first to determine if a port is already installed and if so, skips right on by. It is very intelligent that way. However, sometimes port maintainers do goofy things and we need to override settings that would normally work. A good example of this is currently openldap. |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
If you want to install OpenLDAP 2, then you can install from any of: |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
/usr/ports/net/openldap23-server |
559
|
|
|
|
|
|
|
/usr/ports/net/openldap23-client |
560
|
|
|
|
|
|
|
/usr/ports/net/openldap24-server |
561
|
|
|
|
|
|
|
/usr/ports/net/openldap24-client |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
So, a full complement of settings could look like: |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
$freebsd->install_port( "openldap-client", |
566
|
|
|
|
|
|
|
dir => "openldap24-server", |
567
|
|
|
|
|
|
|
check => "openldap-client-2.4", |
568
|
|
|
|
|
|
|
flags => "NOPORTDOCS=true", |
569
|
|
|
|
|
|
|
fatal => 0, |
570
|
|
|
|
|
|
|
); |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
arguments required: |
573
|
|
|
|
|
|
|
port - the name of the directory in which the port resides |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
arguments optional: |
576
|
|
|
|
|
|
|
dir - overrides 'port' for the build directory |
577
|
|
|
|
|
|
|
check - what to test for to determine if the port is installed (see note #1) |
578
|
|
|
|
|
|
|
flags - comma separated list of arguments to pass when building |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
NOTES: |
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
#1 - On rare occasion, a port will get installed as a name other than the ports name. Of course, that wreaks all sorts of havoc so when one of them nasties is found, you can optionally pass along a fourth parameter which can be used as the port installation name to check with. |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
=item install_package |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
$fbsd->install_package( "maildrop" ); |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
Suggested usage: |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
unless ( $fbsd->install_package( "maildrop" ) ) { |
592
|
|
|
|
|
|
|
$fbsd->install_port( "maildrop" ); |
593
|
|
|
|
|
|
|
}; |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
Installs the selected package from FreeBSD packages. If the first install fails, it will try again using an alternate FTP site (ftp2.freebsd.org). If that fails, it returns 0 (failure) so you know it failed and can try something else, like installing via ports. |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
If the package is registered in FreeBSD's package registry as another name and you want to check against that name (so it doesn't try installing a package that's already installed), instead, pass it along as alt. |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
arguments required: |
600
|
|
|
|
|
|
|
port - the name of the package to install |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
arguments optional: |
603
|
|
|
|
|
|
|
alt - a name the package is registered in the ports tree as |
604
|
|
|
|
|
|
|
url - a URL to fetch the package from |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
See the pkg_add man page for more details on using an alternate URL. |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
=item update_ports |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
Updates the FreeBSD ports tree (/usr/ports/). |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
$fbsd->update_ports(); |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
arguments required: |
616
|
|
|
|
|
|
|
conf - a hashref |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
See the docs for toaster-watcher.conf for complete details. |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
=item conf_check |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
$fbsd->conf_check(check=>"snmpd_enable", line=>"snmpd_enable=\"YES\""); |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
The above example is for snmpd. This checks to verify that an snmpd_enable line exists in /etc/rc.conf. If it doesn't, then it will add it by appending the second argument to the file. |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
=back |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
=head1 AUTHOR |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
Matt Simerson <matt@tnpi.net> |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
=head1 BUGS |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
None known. Report any to author. |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
=head1 TODO |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
Needs more documentation. |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
=head1 SEE ALSO |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
The following are all man/perldoc pages: |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
Mail::Toaster |
647
|
|
|
|
|
|
|
Mail::Toaster::Conf |
648
|
|
|
|
|
|
|
toaster.conf |
649
|
|
|
|
|
|
|
toaster-watcher.conf |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
http://mail-toaster.org/ |
652
|
|
|
|
|
|
|
http://www.tnpi.net/computing/freebsd/ |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
=head1 COPYRIGHT |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
Copyright 2003-2012, The Network People, Inc. All Rights Reserved. |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
Neither the name of the The Network People, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
=cut |