Subversion Repositories

?revision_form?Rev ?revision_input??revision_submit??revision_endform?

Rev 6 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 6 Rev 13
1
#! /usr/bin/perl -w
1
#! /usr/bin/perl -w
2
2
3
#####
3
#####
4
#
4
#
5
# Copyright 2003-2004 Joel Baker. All rights reserved.
5
# Copyright 2003-2004 Joel Baker. All rights reserved.
6
# 
6
# 
7
# Redistribution and use in source and binary forms, with or without
7
# Redistribution and use in source and binary forms, with or without
8
# modification, are permitted provided that the following conditions
8
# modification, are permitted provided that the following conditions
9
# are met:
9
# are met:
10
# 1. Redistributions of source code must retain the above copyright
10
# 1. Redistributions of source code must retain the above copyright
11
#    notice, this list of conditions and the following disclaimer.
11
#    notice, this list of conditions and the following disclaimer.
12
# 2. Redistributions in binary form must reproduce the above copyright
12
# 2. Redistributions in binary form must reproduce the above copyright
13
#    notice, this list of conditions and the following disclaimer in the
13
#    notice, this list of conditions and the following disclaimer in the
14
#    documentation and/or other materials provided with the distribution.
14
#    documentation and/or other materials provided with the distribution.
15
# 3. Neither the name of the Author nor the names of any contributors
15
# 3. Neither the name of the Author nor the names of any contributors
16
#    may be used to endorse or promote products derived from this software
16
#    may be used to endorse or promote products derived from this software
17
#    without specific prior written permission.
17
#    without specific prior written permission.
18
# 
18
# 
19
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
# SUCH DAMAGE.
29
# SUCH DAMAGE.
30
#
30
#
31
# $Id: debpool 54 2005-02-21 21:48:29Z joel $
31
# $Id: debpool 54 2005-02-21 21:48:29Z joel $
32
#
32
#
33
#####
33
#####
34
34
35
# Put our private support module area into the search path
35
# Put our private support module area into the search path
36
36
37
use lib '/usr/share/debpool/perl5';
37
use lib '/usr/share/debpool/perl5';
38
38
39
# We always want to be careful about things...
39
# We always want to be careful about things...
40
40
41
use strict;
41
use strict;
42
use warnings;
42
use warnings;
43
43
44
use POSIX; # This gets us strftime.
44
use POSIX; # This gets us strftime.
45
45
46
# First things first - figure out how we need to be configured.
46
# First things first - figure out how we need to be configured.
47
47
48
use Getopt::Long qw(:config pass_through);
48
use Getopt::Long qw(:config pass_through);
49
use DebPool::Config qw(:functions :vars);
49
use DebPool::Config qw(:functions :vars);
50
50
-
 
51
my($help);
-
 
52
GetOptions('help!' => \$help);
-
 
53
if (defined($help)) {
-
 
54
#23456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 |
-
 
55
    print "Usage: debpool [Options]
-
 
56
Pool-based Debian package archive manager
-
 
57
-
 
58
--config=configfile May be issued multiple times; each time it is used, it will
-
 
59
                    add the named config file to the list which DebPool will
-
 
60
                    load (later config files override earlier ones, in case of
-
 
61
                    any conflicts).
-
 
62
--daemon            Run debpool as a daemon.
-
 
63
--debug             Run debpool in debug mode. Identical to daemon mode but
-
 
64
                    remains in foreground.
-
 
65
--help              Displays this help text.
-
 
66
--dumpdb            Dumps the debpool database.
-
 
67
--log_file=filename Send logging output to the specified filename.
-
 
68
--rebuild-files     Forces all of the distribution files (Packages and Sources)
-
 
69
                    to be rebuilt.
-
 
70
--rebuild-dbs       Forces all of the metadata files to be rebuilt from scratch.
-
 
71
                    WARNING: This feature is not yet implemented
-
 
72
--rebuild-all       Turn on all other rebuild options (currently --rebuild-files
-
 
73
                    and --rebuild-dbs).
-
 
74
                    WARNING: This feature depends on rebuild-dbs, which is not
-
 
75
                    yet implemented; only the --rebuild-files section will be
-
 
76
                    triggered.
-
 
77
-
 
78
";
-
 
79
-
 
80
    exit(0);
-
 
81
}
-
 
82
51
# First, grab --config and --nodefault options if they exist. We
83
# First, grab --config and --nodefault options if they exist. We
52
# don't want these in the %Options hash, and they affect what we do when
84
# don't want these in the %Options hash, and they affect what we do when
53
# loading it.
85
# loading it.
54
86
55
my(@config_files);
87
my(@config_files);
56
my($default);
88
my($default);
57
89
58
GetOptions('config=s' => \@config_files, 'default!' => \$default);
90
GetOptions('config=s' => \@config_files, 'default!' => \$default);
59
91
60
# Call Load_Default_Configs if we're loading default values, or
92
# Call Load_Default_Configs if we're loading default values, or
61
# Load_Minimal_Configs if we're not (we still need the OptionDefs hash to
93
# Load_Minimal_Configs if we're not (we still need the OptionDefs hash to
62
# be populated).
94
# be populated).
63
95
64
if (!defined($default) || $default) {
96
if (!defined($default) || $default) {
65
    Load_Default_Configs();
97
    Load_Default_Configs();
66
} else {
98
} else {
67
    Load_Minimal_Configs();
99
    Load_Minimal_Configs();
68
}
100
}
69
101
70
# Load any config files we were given.
102
# Load any config files we were given.
71
103
72
my($config);
104
my($config);
73
105
74
foreach $config (@config_files) {
106
foreach $config (@config_files) {
75
    Load_File_Configs($config);
107
    Load_File_Configs($config);
76
}
108
}
77
109
78
# And finally, pull in any other command line options.
110
# And finally, pull in any other command line options.
79
111
80
GetOptions(\%Options, values(%OptionDefs));
112
GetOptions(\%Options, values(%OptionDefs));
81
113
82
# Run the cleanup stuff on %Options.
114
# Run the cleanup stuff on %Options.
83
115
84
Clean_Options();
116
Clean_Options();
85
117
86
# Okay. We're more or less ready to go. First, load some modules that we
118
# Okay. We're more or less ready to go. First, load some modules that we
87
# know we'll be calling.
119
# know we'll be calling.
88
120
89
use DebPool::Dirs qw(:functions :vars); # Directory management
121
use DebPool::Dirs qw(:functions :vars); # Directory management
90
use DebPool::DB qw(:functions :vars); # Various databases
122
use DebPool::DB qw(:functions :vars); # Various databases
91
use DebPool::GnuPG qw(:functions :vars); # GnuPG interaction routines
123
use DebPool::GnuPG qw(:functions :vars); # GnuPG interaction routines
92
use DebPool::Gzip qw(:functions :vars); # Gzip interaction routines
124
use DebPool::Gzip qw(:functions :vars); # Gzip interaction routines
93
use DebPool::Logging qw(:functions :facility :level); # Logging routines
125
use DebPool::Logging qw(:functions :facility :level); # Logging routines
94
use DebPool::Packages qw(:functions :vars); # Distribution databases
126
use DebPool::Packages qw(:functions :vars); # Distribution databases
95
use DebPool::Signal qw(:functions :vars); # Handle signals
127
use DebPool::Signal qw(:functions :vars); # Handle signals
96
128
97
# Before we do anything else, let's find out if we need to act as a daemon,
129
# Before we do anything else, let's find out if we need to act as a daemon,
98
# and if so, whether we can manage to pull it off.
130
# and if so, whether we can manage to pull it off.
99
131
100
if ($Options{'daemon'}) {
132
if ($Options{'daemon'}) {
101
    Log_Message("Trying to enter daemon mode.", LOG_GENERAL, LOG_DEBUG);
133
    Log_Message("Trying to enter daemon mode.", LOG_GENERAL, LOG_DEBUG);
102
134
103
    require Proc::Daemon;
135
    require Proc::Daemon;
104
    Proc::Daemon::Init();
136
    Proc::Daemon::Init();
105
137
106
    Log_Message("Now running as a daemon.", LOG_GENERAL, LOG_DEBUG);
138
    Log_Message("Now running as a daemon.", LOG_GENERAL, LOG_DEBUG);
107
}
139
}
108
140
109
# Create the directory tree. This is clean even it it already exists,
141
# Create the directory tree. This is clean even it it already exists,
110
# so we can do it every time we start up. I believe the fancy word is
142
# so we can do it every time we start up. I believe the fancy word is
111
# 'idempotent'. We do this before grabbing a lockfile because it should
143
# 'idempotent'. We do this before grabbing a lockfile because it should
112
# never screw anything up, even if run multiple times at once, and our
144
# never screw anything up, even if run multiple times at once, and our
113
# lockfile may be (probably is, in fact) in one of these places.
145
# lockfile may be (probably is, in fact) in one of these places.
114
146
115
if (!Create_Tree()) {
147
if (!Create_Tree()) {
116
    my($msg) = "Couldn't create directory tree: $DebPool::Dirs::Error";
148
    my($msg) = "Couldn't create directory tree: $DebPool::Dirs::Error";
117
    Log_Message($msg, LOG_GENERAL, LOG_FATAL);
149
    Log_Message($msg, LOG_GENERAL, LOG_FATAL);
118
    die "$msg\n";
150
    die "$msg\n";
119
}
151
}
120
152
121
# Obtain a lockfile. We should never run more than one occurance; it's too
153
# Obtain a lockfile. We should never run more than one occurance; it's too
122
# likely that we'd step on our own toes.
154
# likely that we'd step on our own toes.
123
155
124
if (!sysopen(LOCK_FILE, $Options{'lock_file'}, O_WRONLY|O_CREAT|O_EXCL, 0644)) {
156
if (!sysopen(LOCK_FILE, $Options{'lock_file'}, O_WRONLY|O_CREAT|O_EXCL, 0644)) {
125
    my($msg) = "Couldn't obtain lockfile '$Options{'lock_file'}'; ";
157
    my($msg) = "Couldn't obtain lockfile '$Options{'lock_file'}'; ";
126
158
127
    if (open(LOCK_FILE, '<', $Options{'lock_file'}) &&
159
    if (open(LOCK_FILE, '<', $Options{'lock_file'}) &&
128
       (my($pid) = <LOCK_FILE>)) {
160
       (my($pid) = <LOCK_FILE>)) {
129
        chomp($pid);
161
        chomp($pid);
130
        $msg .= "(PID $pid)\n";
162
        $msg .= "(PID $pid)\n";
131
    } else {
163
    } else {
132
        $msg .= "(unable to read PID)\n";
164
        $msg .= "(unable to read PID)\n";
133
    }
165
    }
134
166
135
    die $msg;
167
    die $msg;
136
} else { # Do something useful - like put our PID into the file.
168
} else { # Do something useful - like put our PID into the file.
137
    print LOCK_FILE "$$\n";
169
    print LOCK_FILE "$$\n";
138
    close(LOCK_FILE);
170
    close(LOCK_FILE);
139
}
171
}
140
172
141
# Start the main loop. We use a do/until loop so that we always fire off at
173
# Start the main loop. We use a do/until loop so that we always fire off at
142
# least once.
174
# least once.
143
175
144
MAIN_LOOP: do {
176
MAIN_LOOP: do {
145
177
146
Log_Message("Starting processing run", LOG_GENERAL, LOG_DEBUG);
178
Log_Message("Starting processing run", LOG_GENERAL, LOG_DEBUG);
147
179
148
# First off, open up our databases. We do this each time through the loop,
180
# First off, open up our databases. We do this each time through the loop,
149
# so that they get flushed periodically if we're in daemon mode.
181
# so that they get flushed periodically if we're in daemon mode.
150
182
151
Open_Databases();
183
Open_Databases();
152
184
153
# This keeps track of what distributions need to have their Packages and
185
# This keeps track of what distributions need to have their Packages and
154
# Sources files rebuilt. We force it to be 'everything' if the user has
186
# Sources files rebuilt. We force it to be 'everything' if the user has
155
# requested a rebuild (normally from the command line).
187
# requested a rebuild (normally from the command line).
156
188
157
my(%rebuild) = ();
189
my(%rebuild) = ();
158
190
159
if ($Options{'rebuild-files'}) {
191
if ($Options{'rebuild-files'}) {
160
    my($dist);
192
    my($dist);
161
    foreach $dist (@{$Options{'realdists'}}) {
193
    foreach $dist (@{$Options{'realdists'}}) {
162
        $rebuild{$dist} = 1;
194
        $rebuild{$dist} = 1;
163
    }
195
    }
164
}
196
}
165
197
166
# Check for any changes files in the incoming directory.
198
# Check for any changes files in the incoming directory.
167
199
168
my(@changefiles) = Scan_Changes($Options{'incoming_dir'});
200
my(@changefiles) = Scan_Changes($Options{'incoming_dir'});
169
201
170
# Go through each of the changes files we found, and process it. This is the
202
# Go through each of the changes files we found, and process it. This is the
171
# heart of things.
203
# heart of things.
172
204
173
my($changefile);
205
my($changefile);
174
206
175
foreach $changefile (@changefiles) {
207
foreach $changefile (@changefiles) {
176
    Log_Message("Processing changefile '$changefile'", LOG_GENERAL, LOG_INFO);
208
    Log_Message("Processing changefile '$changefile'", LOG_GENERAL, LOG_INFO);
177
209
178
    # .dsc = .changes, minus the part after the last _, plus .dsc
210
    # .dsc = .changes, minus the part after the last _, plus .dsc
179
211
180
    my(@parts) = split(/_/, $changefile);
212
    my(@parts) = split(/_/, $changefile);
181
    pop(@parts);
213
    pop(@parts);
182
    my($dscfile) = join('_', @parts) . '.dsc';
214
    my($dscfile) = join('_', @parts) . '.dsc';
183
215
184
    my($changes_data) = Parse_Changes("$Options{'incoming_dir'}/$changefile");
216
    my($changes_data) = Parse_Changes("$Options{'incoming_dir'}/$changefile");
185
    if (!defined($changes_data)) {
217
    if (!defined($changes_data)) {
186
        Log_Message("Failure parsing changes file '$changefile': " .
218
        Log_Message("Failure parsing changes file '$changefile': " .
187
                    $DebPool::Packages::Error, LOG_GENERAL, LOG_ERROR);
219
                    $DebPool::Packages::Error, LOG_GENERAL, LOG_ERROR);
188
        next;
220
        next;
189
    }
221
    }
190
222
191
    my($with_source) = undef; # Upload with or without source?
223
    my($with_source) = undef; # Upload with or without source?
192
    my($temp);
224
    my($temp);
193
225
194
    for $temp (@{$changes_data->{'Architecture'}}) {
226
    for $temp (@{$changes_data->{'Architecture'}}) {
195
        if ('source' eq $temp) {
227
        if ('source' eq $temp) {
196
            $with_source = 1;
228
            $with_source = 1;
197
        }
229
        }
198
    }
230
    }
199
231
200
    my($has_orig) = undef; # Has an orig tarball?
232
    my($has_orig) = undef; # Has an orig tarball?
201
    my($filehr);
233
    my($filehr);
202
234
203
    foreach $filehr (@{$changes_data->{'Files'}}) {
235
    foreach $filehr (@{$changes_data->{'Files'}}) {
204
        if ($filehr->{'Filename'} =~ /orig\.tar\.gz/) {
236
        if ($filehr->{'Filename'} =~ /orig\.tar\.gz/) {
205
            $has_orig = 1;
237
            $has_orig = 1;
206
        }
238
        }
207
    }
239
    }
208
240
209
    my($dsc_data) = Parse_DSC("$Options{'incoming_dir'}/$dscfile");
241
    my($dsc_data) = Parse_DSC("$Options{'incoming_dir'}/$dscfile");
210
    if ($with_source && !defined($dsc_data)) {
242
    if ($with_source && !defined($dsc_data)) {
211
        Log_Message("Failure parsing dsc file '$dscfile': " .
243
        Log_Message("Failure parsing dsc file '$dscfile': " .
212
                    $DebPool::Packages::Error, LOG_GENERAL, LOG_ERROR);
244
                    $DebPool::Packages::Error, LOG_GENERAL, LOG_ERROR);
213
        next;
245
        next;
214
    }
246
    }
215
247
216
    my($package) = $changes_data->{'Source'};
248
    my($package) = $changes_data->{'Source'};
217
    my($version) = $changes_data->{'Version'};
249
    my($version) = $changes_data->{'Version'};
218
250
219
    if ($Options{'require_sigs_meta'}) {
251
    if ($Options{'require_sigs_meta'}) {
220
        # First, check the changefile signature
252
        # First, check the changefile signature
221
253
222
        if (!Check_Signature("$Options{'incoming_dir'}/$changefile")) {
254
        if (!Check_Signature("$Options{'incoming_dir'}/$changefile")) {
223
            Reject_Package($changefile, $changes_data);
255
            Reject_Package($changefile, $changes_data);
224
            Log_Message("GPG signature failure in changes file '$changefile'",
256
            Log_Message("GPG signature failure in changes file '$changefile'",
225
                        LOG_REJECT, LOG_ERROR);
257
                        LOG_REJECT, LOG_ERROR);
226
            next;
258
            next;
227
        } else {
259
        } else {
228
            Log_Message("Successful changes signature: '$changefile'",
260
            Log_Message("Successful changes signature: '$changefile'",
229
                         LOG_GPG, LOG_DEBUG);
261
                         LOG_GPG, LOG_DEBUG);
230
        }
262
        }
231
263
232
        # Now check the dscfile signature
264
        # Now check the dscfile signature
233
265
234
        if ($with_source && !Check_Signature("$Options{'incoming_dir'}/$dscfile")) {
266
        if ($with_source && !Check_Signature("$Options{'incoming_dir'}/$dscfile")) {
235
            Reject_Package($changefile, $changes_data);
267
            Reject_Package($changefile, $changes_data);
236
            Log_Message("GPG signature failure in dsc file '$dscfile'",
268
            Log_Message("GPG signature failure in dsc file '$dscfile'",
237
                        LOG_REJECT, LOG_ERROR);
269
                        LOG_REJECT, LOG_ERROR);
238
            next;
270
            next;
239
        } else {
271
        } else {
240
            Log_Message("Successful dsc signature: '$dscfile'",
272
            Log_Message("Successful dsc signature: '$dscfile'",
241
                        LOG_GPG, LOG_DEBUG);
273
                        LOG_GPG, LOG_DEBUG);
242
        }
274
        }
243
    }
275
    }
244
276
245
    # Verify MD5 checksums on all files.
277
    # Verify MD5 checksums on all files.
246
278
247
    my($valid) = 1;
279
    my($valid) = 1;
248
280
249
    foreach $filehr (@{$changes_data->{'Files'}}) {
281
    foreach $filehr (@{$changes_data->{'Files'}}) {
250
        if (!(Verify_MD5("$Options{'incoming_dir'}/$filehr->{'Filename'}",
282
        if (!(Verify_MD5("$Options{'incoming_dir'}/$filehr->{'Filename'}",
251
                         $filehr->{'MD5Sum'}))) {
283
                         $filehr->{'MD5Sum'}))) {
252
            $valid = undef;
284
            $valid = undef;
253
        }
285
        }
254
    }
286
    }
255
287
256
    if (!$valid) {
288
    if (!$valid) {
257
        Reject_Package($changefile, $changes_data);
289
        Reject_Package($changefile, $changes_data);
258
290
259
        my($msg) = "MD5 checksum failure in changes file '$changefile'";
291
        my($msg) = "MD5 checksum failure in changes file '$changefile'";
260
        Log_Message($msg, LOG_REJECT, LOG_ERROR);
292
        Log_Message($msg, LOG_REJECT, LOG_ERROR);
261
        next;
293
        next;
262
    }
294
    }
263
295
264
    $valid = 1;
296
    $valid = 1;
265
    my($rejected) = undef;
297
    my($rejected) = undef;
266
298
267
    if ($with_source) {
299
    if ($with_source) {
268
        foreach $filehr (@{$dsc_data->{'Files'}}) {
300
        foreach $filehr (@{$dsc_data->{'Files'}}) {
269
            # A bit of a special case here; if the Changes file lists an
301
            # A bit of a special case here; if the Changes file lists an
270
            # orig tarball, we must *not* have one for that version in the
302
            # orig tarball, we must *not* have one for that version in the
271
            # pool. If it doesn't, then we *must* have one. In either case,
303
            # pool. If it doesn't, then we *must* have one. In either case,
272
            # as long as it's in the right place we use that file for the
304
            # as long as it's in the right place we use that file for the
273
            # MD5Sum check when the file is listed in the DSC.
305
            # MD5Sum check when the file is listed in the DSC.
274
306
275
            my($file) = $filehr->{'Filename'};
307
            my($file) = $filehr->{'Filename'};
276
308
277
            if ($file =~ /orig\.tar\.gz/) {
309
            if ($file =~ /orig\.tar\.gz/) {
278
                my($section) = Guess_Section($changes_data);
310
                my($section) = Guess_Section($changes_data);
279
                my($pkg_pooldir) = join('/',
311
                my($pkg_pooldir) = join('/',
280
                    ($Options{'pool_dir'}, PoolDir($package, $section),
312
                    ($Options{'pool_dir'}, PoolDir($package, $section),
281
                    $package));
313
                    $package));
282
                
314
                
283
                if ($has_orig) { # Orig tarball uploaded
315
                if ($has_orig) { # Orig tarball uploaded
284
                    if (-e "$pkg_pooldir/$file") {
316
                    if (-e "$pkg_pooldir/$file") {
285
                        Reject_Package($changefile, $changes_data);
317
                        Reject_Package($changefile, $changes_data);
286
    
318
    
287
                        my($msg) = "Duplicate orig tarball '$file'";
319
                        my($msg) = "Duplicate orig tarball '$file'";
288
                        Log_Message($msg, LOG_REJECT, LOG_ERROR);
320
                        Log_Message($msg, LOG_REJECT, LOG_ERROR);
289
321
290
                        $rejected = 1;
322
                        $rejected = 1;
291
                        last; # Don't check other files, we just rejected
323
                        last; # Don't check other files, we just rejected
292
                    } elsif (!(-e "$Options{'incoming_dir'}/$file")) {
324
                    } elsif (!(-e "$Options{'incoming_dir'}/$file")) {
293
                        Reject_Package($changefile, $changes_data);
325
                        Reject_Package($changefile, $changes_data);
294
    
326
    
295
                        my($msg) = "Missing orig tarball '$file'";
327
                        my($msg) = "Missing orig tarball '$file'";
296
                        Log_Message($msg, LOG_REJECT, LOG_ERROR);
328
                        Log_Message($msg, LOG_REJECT, LOG_ERROR);
297
329
298
                        $rejected = 1;
330
                        $rejected = 1;
299
                        last; # Don't check other files, we just rejected
331
                        last; # Don't check other files, we just rejected
300
                    } else {
332
                    } else {
301
                        $file = "$Options{'incoming_dir'}/$file";
333
                        $file = "$Options{'incoming_dir'}/$file";
302
                    }
334
                    }
303
                } else { # Orig tarball in pool - we hope
335
                } else { # Orig tarball in pool - we hope
304
                    if (!(-e "$pkg_pooldir/$file")) {
336
                    if (!(-e "$pkg_pooldir/$file")) {
305
                        Reject_Package($changefile, $changes_data);
337
                        Reject_Package($changefile, $changes_data);
306
    
338
    
307
                        my($msg) = "Missing orig tarball '$file'";
339
                        my($msg) = "Missing orig tarball '$file'";
308
                        Log_Message($msg, LOG_REJECT, LOG_ERROR);
340
                        Log_Message($msg, LOG_REJECT, LOG_ERROR);
309
341
310
                        $rejected = 1;
342
                        $rejected = 1;
311
                        last; # Don't check other files, we just rejected
343
                        last; # Don't check other files, we just rejected
312
                    } else {
344
                    } else {
313
                        $file = "$pkg_pooldir/$file";
345
                        $file = "$pkg_pooldir/$file";
314
                    }
346
                    }
315
                }
347
                }
316
            } else { # Not an orig tarball - must be in upload
348
            } else { # Not an orig tarball - must be in upload
317
                $file = "$Options{'incoming_dir'}/$file";
349
                $file = "$Options{'incoming_dir'}/$file";
318
            }
350
            }
319
351
320
            # Whatever it is, it must also pass the MD5 checksum test.
352
            # Whatever it is, it must also pass the MD5 checksum test.
321
353
322
            if (!(Verify_MD5($file, $filehr->{'MD5Sum'}))) {
354
            if (!(Verify_MD5($file, $filehr->{'MD5Sum'}))) {
323
                $valid = undef;
355
                $valid = undef;
324
                last; # Don't check other files, we already failed
356
                last; # Don't check other files, we already failed
325
            }
357
            }
326
        }
358
        }
327
    }
359
    }
328
360
329
    next if ($rejected); # Reject message already logged, go to next package.
361
    next if ($rejected); # Reject message already logged, go to next package.
330
362
331
    if (!$valid) {
363
    if (!$valid) {
332
        Reject_Package($changefile, $changes_data);
364
        Reject_Package($changefile, $changes_data);
333
365
334
        my($msg) = "MD5 checksum failure in dsc file '$dscfile'";
366
        my($msg) = "MD5 checksum failure in dsc file '$dscfile'";
335
        Log_Message($msg, LOG_REJECT, LOG_ERROR);
367
        Log_Message($msg, LOG_REJECT, LOG_ERROR);
336
        next;
368
        next;
337
    }
369
    }
338
370
339
    # Go through each distribution in the changes file, and decide whether
371
    # Go through each distribution in the changes file, and decide whether
340
    # the package is valid for that distribution.
372
    # the package is valid for that distribution.
341
373
342
    my($distribution, $realdist);
374
    my($distribution, $realdist);
343
    my(@valid_dists);
375
    my(@valid_dists);
344
376
345
    foreach $distribution (@{$changes_data->{'Distribution'}}) {
377
    foreach $distribution (@{$changes_data->{'Distribution'}}) {
346
        $realdist = $distribution;
378
        $realdist = $distribution;
347
379
348
        if (defined($Options{'virtual_dists'}->{$realdist})) {
380
        if (defined($Options{'virtual_dists'}->{$realdist})) {
349
            $realdist = $Options{'virtual_dists'}->{$realdist};
381
            $realdist = $Options{'virtual_dists'}->{$realdist};
350
        }
382
        }
351
383
352
        if (defined($Options{'dists'}->{$realdist})) {
384
        if (defined($Options{'dists'}->{$realdist})) {
353
            $realdist = $Options{'dists'}->{$realdist};
385
            $realdist = $Options{'dists'}->{$realdist};
354
        }
386
        }
355
387
356
        if (!defined($realdist)) {
388
        if (!defined($realdist)) {
357
            Log_Message("Distribution $distribution does not exist",
389
            Log_Message("Distribution $distribution does not exist",
358
                        LOG_INSTALL, LOG_ERROR);
390
                        LOG_INSTALL, LOG_ERROR);
359
            next;
391
            next;
360
        }
392
        }
361
393
362
        my($allow) = Allow_Version($package, $version, $realdist);
394
        my($allow) = Allow_Version($package, $version, $realdist);
363
395
364
        if (!defined($allow)) {
396
        if (!defined($allow)) {
365
            Log_Message("Version check for $version failed: " .
397
            Log_Message("Version check for $version failed: " .
366
                        $DebPool::Packages::Error, LOG_INSTALL, LOG_ERROR);
398
                        $DebPool::Packages::Error, LOG_INSTALL, LOG_ERROR);
367
            next;
399
            next;
368
        }
400
        }
369
401
370
        if (!$allow) {
402
        if (!$allow) {
371
            Log_Message("Cannot install version $version of $package to " .
403
            Log_Message("Cannot install version $version of $package to " .
372
                        "$realdist", LOG_INSTALL, LOG_WARNING);
404
                        "$realdist", LOG_INSTALL, LOG_WARNING);
373
            next;
405
            next;
374
        }
406
        }
375
407
376
        # It's valid. Put it in the list.
408
        # It's valid. Put it in the list.
377
409
378
        push(@valid_dists, $realdist);
410
        push(@valid_dists, $realdist);
379
    }
411
    }
380
412
381
    if (-1 == $#valid_dists) {
413
    if (-1 == $#valid_dists) {
382
        Reject_Package($changefile, $changes_data);
414
        Reject_Package($changefile, $changes_data);
383
        Log_Message("No valid distributions for version $version of $package",
415
        Log_Message("No valid distributions for version $version of $package",
384
                    LOG_REJECT, LOG_ERROR);
416
                    LOG_REJECT, LOG_ERROR);
385
        next;
417
        next;
386
    }
418
    }
387
419
388
    # Install the package
420
    # Install the package
389
421
390
    if (Install_Package($changefile, $changes_data, $dscfile, $dsc_data, \@valid_dists)) {
422
    if (Install_Package($changefile, $changes_data, $dscfile, $dsc_data, \@valid_dists)) {
391
        my($dist);
423
        my($dist);
392
        foreach $dist (@valid_dists) {
424
        foreach $dist (@valid_dists) {
393
            $rebuild{$dist} = 1;
425
            $rebuild{$dist} = 1;
394
        }
426
        }
395
427
396
        my($msg) = "Installed $package ($version) to ";
428
        my($msg) = "Installed $package ($version) to ";
397
        $msg .= "distribution(s): " . join(', ', @valid_dists);
429
        $msg .= "distribution(s): " . join(', ', @valid_dists);
398
        Log_Message($msg, LOG_INSTALL, LOG_INFO);
430
        Log_Message($msg, LOG_INSTALL, LOG_INFO);
399
    } else {
431
    } else {
400
        # Something is very, very wrong.
432
        # Something is very, very wrong.
401
        Log_Message("Couldn't install package '$package': " . 
433
        Log_Message("Couldn't install package '$package': " . 
402
                    $DebPool::Packages::Error, LOG_INSTALL, LOG_FATAL);
434
                    $DebPool::Packages::Error, LOG_INSTALL, LOG_FATAL);
403
        Close_Databases();
435
        Close_Databases();
404
        unlink($Options{'lock_file'}); # Release our lock
436
        unlink($Options{'lock_file'}); # Release our lock
405
        die "Couldn't install package '$package'\n";
437
        die "Couldn't install package '$package'\n";
406
    }
438
    }
407
439
408
    # And, now that that's done, audit the package area in the pool to get
440
    # And, now that that's done, audit the package area in the pool to get
409
    # rid of crufty, obsolete versions.
441
    # rid of crufty, obsolete versions.
410
442
411
    Audit_Package($package, $changes_data);
443
    Audit_Package($package, $changes_data);
412
}
444
}
413
445
414
# Regenerate {Packages,Sources}{,.gz} for distributions which need it. Also
446
# Regenerate {Packages,Sources}{,.gz} for distributions which need it. Also
415
# rebuild Release files that need it, if we're doing them.
447
# rebuild Release files that need it, if we're doing them.
416
448
417
my($dist, $section);
449
my($dist, $section);
418
450
419
foreach $dist (keys(%rebuild)) {
451
foreach $dist (keys(%rebuild)) {
420
    my(@rel_filelist) = ();
452
    my(@rel_filelist) = ();
421
    foreach $section (@{$Options{'sections'}}) {
453
    foreach $section (@{$Options{'sections'}}) {
422
        my(@archs) = @{$Options{'archs'}};
454
        my(@archs) = @{$Options{'archs'}};
423
        @archs = grep(!/^all$/, @archs); # We don't build binary-all files.
455
        @archs = grep(!/^all$/, @archs); # We don't build binary-all files.
424
456
425
        my($arch);
457
        my($arch);
426
458
427
ARCH_LOOP:
459
ARCH_LOOP:
428
        foreach $arch (@{$Options{'archs'}}) {
460
        foreach $arch (@{$Options{'archs'}}) {
429
            # We cheat, and use @triple for dist/section/arch inputs.
461
            # We cheat, and use @triple for dist/section/arch inputs.
430
            # Perl lets us get away with this. I'd care, except that Perl
462
            # Perl lets us get away with this. I'd care, except that Perl
431
            # prototyping isn't, so it's useless to not do this.
463
            # prototyping isn't, so it's useless to not do this.
432
464
433
            my(@triple) = ($dist, $section, $arch);
465
            my(@triple) = ($dist, $section, $arch);
434
466
435
            # Generate a Packages/Sources file.
467
            # Generate a Packages/Sources file.
436
468
437
            my($file) = Generate_List(@triple);
469
            my($file) = Generate_List(@triple);
438
    
470
    
439
            if (!defined($file)) {
471
            if (!defined($file)) {
440
                my($msg) = "Couldn't create list for $dist/$section/${arch}: ";
472
                my($msg) = "Couldn't create list for $dist/$section/${arch}: ";
441
                $msg .= $DebPool::Packages::Error;
473
                $msg .= $DebPool::Packages::Error;
442
                Log_Message($msg, LOG_GENERAL, LOG_ERROR);
474
                Log_Message($msg, LOG_GENERAL, LOG_ERROR);
443
    
475
    
444
                next;
476
                next;
445
            }
477
            }
446
478
447
            # If we're compressing distribution files, do that here.
479
            # If we're compressing distribution files, do that here.
448
480
449
            my($gzfile);
481
            my($gzfile);
450
            if ($Options{'compress_dists'}) {
482
            if ($Options{'compress_dists'}) {
451
                $gzfile = Gzip_File($file);
483
                $gzfile = Gzip_File($file);
452
484
453
                if (!defined($gzfile)) {
485
                if (!defined($gzfile)) {
454
                    my($msg) = "Couldn't create compressed file: ";
486
                    my($msg) = "Couldn't create compressed file: ";
455
                    $msg .= $DebPool::Gzip::Error;
487
                    $msg .= $DebPool::Gzip::Error;
456
                    Log_Message($msg, LOG_GENERAL, LOG_ERROR);
488
                    Log_Message($msg, LOG_GENERAL, LOG_ERROR);
457
489
458
                    unlink($file);
490
                    unlink($file);
459
                    next;
491
                    next;
460
                }
492
                }
461
            }
493
            }
462
494
463
            # If we're doing Release files, now is the time for triples.
495
            # If we're doing Release files, now is the time for triples.
464
496
465
            my($relfile);
497
            my($relfile);
466
            my($sigfile);
498
            my($sigfile);
467
499
468
            if ($Options{'do_release'}) {
500
            if ($Options{'do_release'}) {
469
                require DebPool::Release;
501
                require DebPool::Release;
470
502
471
                # Release versions are YYYY.MM.DD.HH.MM.SS (GMT) by default.
503
                # Release versions are YYYY.MM.DD.HH.MM.SS (GMT) by default.
472
504
473
                my($release_version) = strftime('%Y.%m.%d.%H.%M.%S', gmtime());
505
                my($release_version) = strftime('%Y.%m.%d.%H.%M.%S', gmtime());
474
                $relfile = DebPool::Release::Generate_Release_Triple(
506
                $relfile = DebPool::Release::Generate_Release_Triple(
475
                    @triple, $release_version);
507
                    @triple, $release_version);
476
508
477
                if (!defined($relfile)) {
509
                if (!defined($relfile)) {
478
                    my($msg) = "Couldn't create Release file: ";
510
                    my($msg) = "Couldn't create Release file: ";
479
                    $msg .= $DebPool::Release::Error;
511
                    $msg .= $DebPool::Release::Error;
480
                    Log_Message($msg, LOG_GENERAL, LOG_ERROR);
512
                    Log_Message($msg, LOG_GENERAL, LOG_ERROR);
481
513
482
                    unlink($file);
514
                    unlink($file);
483
                    if (defined($gzfile)) {
515
                    if (defined($gzfile)) {
484
                        unlink($gzfile);
516
                        unlink($gzfile);
485
                    }
517
                    }
486
                    next;
518
                    next;
487
                }
519
                }
488
                
520
                
489
                if ($Options{'sign_release'}) {
521
                if ($Options{'sign_release'}) {
490
                    $sigfile = Sign_Release($relfile);
522
                    $sigfile = Sign_Release($relfile);
491
    
523
    
492
                    if (!defined($sigfile)) {
524
                    if (!defined($sigfile)) {
493
                        my($msg) = "Couldn't create Release signature file: ";
525
                        my($msg) = "Couldn't create Release signature file: ";
494
                        $msg .= $DebPool::GnuPG::Error;
526
                        $msg .= $DebPool::GnuPG::Error;
495
                        Log_Message($msg, LOG_GENERAL, LOG_ERROR);
527
                        Log_Message($msg, LOG_GENERAL, LOG_ERROR);
496
    
528
    
497
                        unlink($file);
529
                        unlink($file);
498
530
499
                        if (defined($gzfile)) {
531
                        if (defined($gzfile)) {
500
                            unlink($gzfile);
532
                            unlink($gzfile);
501
                        }
533
                        }
502
534
503
                        if (defined($relfile)) {
535
                        if (defined($relfile)) {
504
                            unlink($relfile);
536
                            unlink($relfile);
505
                        }
537
                        }
506
538
507
                        next;
539
                        next;
508
                    }
540
                    }
509
                }
541
                }
510
            }
542
            }
511
543
512
            # Install {Packages,Sources}{,.gz}
544
            # Install {Packages,Sources}{,.gz}
513
545
514
            if (!Install_List(@triple, $file, $gzfile)) {
546
            if (!Install_List(@triple, $file, $gzfile)) {
515
547
516
                my($msg) = "Couldn't install distribution files for ";
548
                my($msg) = "Couldn't install distribution files for ";
517
                $msg .= "$dist/$section/${arch}: " . $DebPool::Packages::Error;
549
                $msg .= "$dist/$section/${arch}: " . $DebPool::Packages::Error;
518
                Log_Message($msg, LOG_GENERAL, LOG_ERROR);
550
                Log_Message($msg, LOG_GENERAL, LOG_ERROR);
519
551
520
                if (-e $file) {
552
                if (-e $file) {
521
                    unlink($file);
553
                    unlink($file);
522
                }
554
                }
523
555
524
                if (defined($gzfile) && -e $gzfile) {
556
                if (defined($gzfile) && -e $gzfile) {
525
                    unlink($gzfile);
557
                    unlink($gzfile);
526
                }
558
                }
527
559
528
                if (defined($relfile) && -e $relfile) {
560
                if (defined($relfile) && -e $relfile) {
529
                    unlink($relfile);
561
                    unlink($relfile);
530
                }
562
                }
531
563
532
                if (defined($sigfile) && -e $sigfile) {
564
                if (defined($sigfile) && -e $sigfile) {
533
                    unlink($sigfile);
565
                    unlink($sigfile);
534
                }
566
                }
535
567
536
                next;
568
                next;
537
            }
569
            }
538
570
539
            # Install Release{,.gpg}
571
            # Install Release{,.gpg}
540
572
541
            if (defined($relfile) &&
573
            if (defined($relfile) &&
542
                !DebPool::Release::Install_Release(@triple, $relfile, $sigfile)) {
574
                !DebPool::Release::Install_Release(@triple, $relfile, $sigfile)) {
543
575
544
                my($msg) = "Couldn't install release files for ";
576
                my($msg) = "Couldn't install release files for ";
545
                $msg .= "$dist/$section/${arch}: " . $DebPool::Release::Error;
577
                $msg .= "$dist/$section/${arch}: " . $DebPool::Release::Error;
546
                Log_Message($msg, LOG_GENERAL, LOG_ERROR);
578
                Log_Message($msg, LOG_GENERAL, LOG_ERROR);
547
579
548
                if (-e $relfile) {
580
                if (-e $relfile) {
549
                    unlink($relfile);
581
                    unlink($relfile);
550
                }
582
                }
551
583
552
                if (defined($sigfile) && -e $sigfile) {
584
                if (defined($sigfile) && -e $sigfile) {
553
                    unlink($sigfile);
585
                    unlink($sigfile);
554
                }
586
                }
555
587
556
                next;
588
                next;
557
            }
589
            }
558
590
559
            my($pushfile) = Archfile(@triple, 0);
591
            my($pushfile) = Archfile(@triple, 0);
560
            $pushfile =~ s/${dist}\///;
592
            $pushfile =~ s/${dist}\///;
561
            push(@rel_filelist, $pushfile);
593
            push(@rel_filelist, $pushfile);
562
594
563
            if (defined($gzfile)) {
595
            if (defined($gzfile)) {
564
                push(@rel_filelist, $pushfile . '.gz');
596
                push(@rel_filelist, $pushfile . '.gz');
565
            }
597
            }
566
598
567
            if (defined($relfile)) {
599
            if (defined($relfile)) {
568
                $pushfile = Archfile(@triple, 1);
600
                $pushfile = Archfile(@triple, 1);
569
                $pushfile =~ s/${dist}\///;
601
                $pushfile =~ s/${dist}\///;
570
                $pushfile .= '/Release';
602
                $pushfile .= '/Release';
571
                push(@rel_filelist, $pushfile);
603
                push(@rel_filelist, $pushfile);
572
604
573
                if (defined($sigfile)) {
605
                if (defined($sigfile)) {
574
                    push(@rel_filelist, $pushfile . '.gpg');
606
                    push(@rel_filelist, $pushfile . '.gpg');
575
                }
607
                }
576
            }
608
            }
577
        }
609
        }
578
    }
610
    }
579
611
580
    # If we're doing Release files, now is the time for the general dist one.
612
    # If we're doing Release files, now is the time for the general dist one.
581
613
582
    my($relfile);
614
    my($relfile);
583
    my($sigfile);
615
    my($sigfile);
584
616
585
    if ($Options{'do_release'}) {
617
    if ($Options{'do_release'}) {
586
        require DebPool::Release;
618
        require DebPool::Release;
587
619
588
        # Release versions are YYYY.MM.DD.HH.MM.SS (GMT) by default.
620
        # Release versions are YYYY.MM.DD.HH.MM.SS (GMT) by default.
589
621
590
        my($release_version) = strftime('%Y.%m.%d.%H.%M.%S', gmtime());
622
        my($release_version) = strftime('%Y.%m.%d.%H.%M.%S', gmtime());
591
        $relfile = DebPool::Release::Generate_Release_Dist(
623
        $relfile = DebPool::Release::Generate_Release_Dist(
592
            $dist, $release_version, @rel_filelist);
624
            $dist, $release_version, @rel_filelist);
593
625
594
        if (!defined($relfile)) {
626
        if (!defined($relfile)) {
595
            my($msg) = "Couldn't create Release file: ";
627
            my($msg) = "Couldn't create Release file: ";
596
            $msg .= $DebPool::Release::Error;
628
            $msg .= $DebPool::Release::Error;
597
            Log_Message($msg, LOG_GENERAL, LOG_ERROR);
629
            Log_Message($msg, LOG_GENERAL, LOG_ERROR);
598
        } else {
630
        } else {
599
            if ($Options{'sign_release'}) {
631
            if ($Options{'sign_release'}) {
600
                $sigfile = Sign_Release($relfile);
632
                $sigfile = Sign_Release($relfile);
601
    
633
    
602
                if (!defined($sigfile)) {
634
                if (!defined($sigfile)) {
603
                    my($msg) = "Couldn't create Release signature file: ";
635
                    my($msg) = "Couldn't create Release signature file: ";
604
                    $msg .= $DebPool::GnuPG::Error;
636
                    $msg .= $DebPool::GnuPG::Error;
605
                    Log_Message($msg, LOG_GENERAL, LOG_ERROR);
637
                    Log_Message($msg, LOG_GENERAL, LOG_ERROR);
606
                    unlink($relfile);
638
                    unlink($relfile);
607
                    $relfile = undef;
639
                    $relfile = undef;
608
                }
640
                }
609
            }
641
            }
610
        }
642
        }
611
    }
643
    }
612
644
613
    # Install Release{,.gpg}
645
    # Install Release{,.gpg}
614
646
615
    if (defined($relfile) &&
647
    if (defined($relfile) &&
616
        !DebPool::Release::Install_Release($dist, undef, undef,
648
        !DebPool::Release::Install_Release($dist, undef, undef,
617
            $relfile, $sigfile)) {
649
            $relfile, $sigfile)) {
618
        my($msg) = "Couldn't install release files for ";
650
        my($msg) = "Couldn't install release files for ";
619
        $msg .= "${dist}: " . $DebPool::Release::Error;
651
        $msg .= "${dist}: " . $DebPool::Release::Error;
620
        Log_Message($msg, LOG_GENERAL, LOG_ERROR);
652
        Log_Message($msg, LOG_GENERAL, LOG_ERROR);
621
653
622
        if (-e $relfile) {
654
        if (-e $relfile) {
623
            unlink($relfile);
655
            unlink($relfile);
624
        }
656
        }
625
657
626
        if (defined($sigfile) && -e $sigfile) {
658
        if (defined($sigfile) && -e $sigfile) {
627
            unlink($sigfile);
659
            unlink($sigfile);
628
        }
660
        }
629
    }
661
    }
630
}
662
}
631
663
632
# Close out the databases, ensuring that they're flushed to disk. We'll
664
# Close out the databases, ensuring that they're flushed to disk. We'll
633
# just reopen them in a moment, if we're in daemon mode; it's still good to
665
# just reopen them in a moment, if we're in daemon mode; it's still good to
634
# write them out.
666
# write them out.
635
667
636
Close_Databases();
668
Close_Databases();
637
669
638
# This will short-circuit if we catch a signal while sleeping.
670
# This will short-circuit if we catch a signal while sleeping.
639
671
640
if ($Options{'daemon'}) {
672
if ($Options{'daemon'}) {
641
    Log_Message("Waiting on changes to incoming dir.", LOG_GENERAL, LOG_DEBUG);
673
    Log_Message("Waiting on changes to incoming dir.", LOG_GENERAL, LOG_DEBUG);
642
674
643
    if (!Monitor_Incoming()) {
675
    if (!Monitor_Incoming()) {
644
        my($msg) = "Error in Monitor_Incoming: " . $DebPool::Dirs::Error;
676
        my($msg) = "Error in Monitor_Incoming: " . $DebPool::Dirs::Error;
645
        Log_Message($msg, LOG_GENERAL, LOG_ERROR);
677
        Log_Message($msg, LOG_GENERAL, LOG_ERROR);
646
    }
678
    }
647
}
679
}
648
680
649
# End of MAIN_LOOP; we loop back until either we're not in daemon mode
681
# End of MAIN_LOOP; we loop back until either we're not in daemon mode
650
# (that is, we've been told to single-pass), or until we catch a signal.
682
# (that is, we've been told to single-pass), or until we catch a signal.
651
683
652
} until ((!$Options{'daemon'}) || $Signal_Caught);
684
} until ((!$Options{'daemon'}) || $Signal_Caught);
653
685
654
# Release our lock
686
# Release our lock
655
687
656
unlink($Options{'lock_file'});
688
unlink($Options{'lock_file'});
657
689
658
Log_Message("Exiting.", LOG_GENERAL, LOG_DEBUG);
690
Log_Message("Exiting.", LOG_GENERAL, LOG_DEBUG);
659
691
660
exit(0);
692
exit(0);
661
693
662
__END__
694
__END__
663
695
664
# vim:set tabstop=4 expandtab:
696
# vim:set tabstop=4 expandtab: